Files
typo3-13/tailwind.config.js
T
frommeandClaude Opus 5.5 5d41660a9a feat: availability calendar in the product detail sidebar is back
TYPO3 10 showed a "Belegungskalender" in the sidebar of every product
with a calendar hotel. It was dropped when the price calendar arrived,
and the price calendar is limited to summer products, so winter
products showed no availability at all.

The sidebar calendar is shown for products with a calendar hotel that
are not summer products. AjaxCalendar::availability reads the
availability from MyE&P (contingents/availability, as the iCal feed
does) instead of bpn-connect, and renders all months in one cacheable
response; the month select only switches between them. Months with
prices in the price config (summer, covered by the price calendar) are
left out. If the price config is unavailable, all months are shown
without caching.

The plain availability-* classes are safelisted in Tailwind: they were
only kept on TYPO3 10 because the ContingentViewHelper named them, and
the class names are now built in the controller.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 14:03:59 +01:00

187 lines
7.1 KiB
JavaScript

const postcss = require('postcss')
const plugin = require('tailwindcss/plugin')
module.exports = {
content: [
'./packages/ep_theme/Configuration/RTE/*.yaml',
'./packages/ep_theme/Configuration/TypoScript/**/*.typoscript',
'./packages/ep_theme/Resources/Private/Layouts/**/*.html',
'./packages/ep_theme/Resources/Private/Partials/**/*.html',
'./packages/ep_theme/Resources/Private/Templates/**/*.html',
'./packages/ep_theme/Resources/Private/Assets/js/**/*.{js,vue}',
'./packages/ep_theme/Classes/ViewHelpers/**/*.php',
],
safelist: [
'pt-8', 'pt-16', 'pb-8', 'pb-16',
'bg-red-600',
'bg-header-season-w', 'bg-header-season-s',
'bg-concept-ok', 'bg-concept-ok/70',
'bg-concept-bdg', 'bg-concept-bdg/70',
'bg-concept-skr', 'bg-concept-skr/70',
'bg-concept-evt', 'bg-concept-evt/70',
'bg-concept-fam', 'bg-concept-fam/70',
'bg-concept-grp', 'bg-concept-grp/70',
'bg-concept-prg', 'bg-concept-prg/70',
'bg-concept-ind', 'bg-concept-ind/70',
'bg-concept-wkd', 'bg-concept-wkd/70',
'bg-concept-kt', 'bg-concept-kt/70',
'bg-concept-spz', 'bg-concept-spz/70',
'bg-concept-epe', 'bg-concept-epe/70',
'bg-concept-sfl', 'bg-concept-sfl/70',
'bg-concept-ser', 'bg-concept-ser/70',
'flatpickr-input', 'flatpickr-calendar', 'flatpickr-day', 'flatpickr-day.selected',
'availability-full', 'availability-partial', 'availability-none',
'availability-full-to-none','availability-full-to-partial', 'availability-none-to-full',
'availability-partial-to-full', 'availability-none-to-partial', 'availability-partial-to-none',
],
theme: {
container: {
center: true,
padding: '1rem',
},
fontFamily: {
'sans': [ 'Lato', 'sans-serif' ],
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
},
extend: {
fontSize: {
'xs': '.8rem',
},
colors: {
concept: {
DEFAULT: '#0173A5',
bdg: '#0173A5',
skr: '#0173A5',
evt: '#BA034F',
fam: '#7ca7d5',
grp: '#576D02',
prg: '#0173A5',
ind: '#1684DD',
wkd: '#96BB05',
kt: '#576D02',
spz: '#436a8a',
epe: '#436a8a',
sfl: '#4E4E51',
ser: '#e85243',
ok: '#0173A5',
},
ep: {
primary: '#3d8ccb',
secondary: '#f9c700',
'primary-bg': '#ebf3fa',
'primary-light': '#0070E0',
'primary-medium': '#165883',
'primary-dark': '#18527b',
pink: '#fa1a8c',
},
sbw: {
primary: '#B3820F',
secondary: '#E91C26',
'primary-dark': '#8D7207',
overlay: '#c20000',
},
snz: {
primary: '#82c3c6',
secondary: '#f9c33d',
'primary-dark': '#82c3c6',
},
uch: {
primary: '#FF6A13',
secondary: '#19a3dc',
'primary-dark': '#FF6A13',
overlay: '#FF6A13',
},
ser: {
primary: '#006fb6',
secondary: '#DE2C1B',
'primary-light': '#04A4CC',
},
suz: {
primary: '#f9c33d',
secondary: '#82c3c6',
'primary-dark': '#c7a20c',
},
},
opacity: {
'55': 0.55,
'85': 0.85,
},
backgroundImage: {
'badge-gradient': 'linear-gradient(120deg, #960167 0%, #9e036a 40%, #fa1a8c 100%)',
'brand-gradient': 'linear-gradient(to top right, #009fff, #165883, #18527b)',
},
height: {
'128': '32rem',
},
inset: {
'100': '100%',
'1/2': '50%',
},
zIndex: {
'-10': '-10',
'100': 100,
},
},
},
variants: {
extend: {
backgroundColor: [ 'sbw', 'sbw-hover', 'sbw-group-hover', 'snz', 'snz-hover', 'snz-group-hover', 'uch', 'uch-hover', 'uch-group-hover', 'ser', 'ser-hover', 'ser-group-hover', 'suz', 'suz-hover', 'suz-group-hover' ],
backgroundImage: [ 'ser' ],
textColor: [ 'sbw', 'sbw-hover', 'snz', 'snz-hover', 'uch', 'uch-hover', 'ser', 'ser-hover', 'suz', 'suz-hover', 'suz-group-hover' ],
borderColor: [ 'sbw','snz', 'uch', 'ser', 'suz' ],
display: [ 'reduced' ],
flex: [ 'reduced' ],
flexDirection: [ 'reduced' ],
alignItems: [ 'reduced' ],
padding: [ 'reduced' ],
margin: [ 'reduced' ],
maxWidth: [ 'reduced' ],
},
},
plugins: [
require('@tailwindcss/aspect-ratio'),
require('@tailwindcss/forms'),
require('tailwindcss-alt')({
variants: ['sbw', 'snz', 'uch', 'ser', 'suz'],
}),
plugin(function ({addVariant, e}) {
addVariant('hover-hover', ({ container, separator }) => {
const hoverHover = postcss.atRule({ name: 'media', params: '(hover: hover)' })
hoverHover.append(container.nodes)
container.append(hoverHover)
hoverHover.walkRules(rule => {
rule.selector = `.${e(`hover-hover${separator}${rule.selector.slice(1)}`)}`
})
})
addVariant('hover-none', ({ container, separator }) => {
const hoverNone = postcss.atRule({ name: 'media', params: '(hover: none)' })
hoverNone.append(container.nodes)
container.append(hoverNone)
hoverNone.walkRules(rule => {
rule.selector = `.${e(`hover-none${separator}${rule.selector.slice(1)}`)}`
})
})
addVariant('first-type', ({modifySelectors, separator}) => {
modifySelectors(({className}) => {
return `.${e(`first-type${separator}${className}`)}:first-of-type`
})
})
addVariant('last-type', ({modifySelectors, separator}) => {
modifySelectors(({className}) => {
return `.${e(`last-type${separator}${className}`)}:last-of-type`
})
})
addVariant('reduced', ({modifySelectors, separator}) => {
modifySelectors(({className}) => {
return `.reduced .${e(`reduced${separator}${className}`)}`
})
})
}),
],
}