Compare commits

...

2 Commits

Author SHA1 Message Date
5ca9e98106 feat: add form design
Some checks failed
Build / build (push) Successful in 4m14s
Build / deploy-stage (push) Failing after 1m52s
Build / switch-stage (push) Has been skipped
2025-04-22 16:53:00 +02:00
6214e262cc feat: many changes 2025-04-22 12:29:34 +02:00
26 changed files with 445 additions and 77 deletions

View File

@@ -7,6 +7,7 @@ baseVariants:
dependencies:
- georgringer/news
- typo3/redirects
- typo3/form
- cloonar-typo3/base
languages:
-

72
package-lock.json generated
View File

@@ -1,12 +1,15 @@
{
"name": "lena-schilling-website",
"name": "dialog-relations-website",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "lena-schilling-website",
"name": "dialog-relations-website",
"version": "1.0.0",
"dependencies": {
"yaml-loader": "^0.8.1"
},
"devDependencies": {
"autoprefixer": "^10.4.21",
"css-loader": "^6.7.3",
@@ -944,6 +947,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
"integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -1276,6 +1288,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/emojis-list": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
"integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
"license": "MIT",
"engines": {
"node": ">= 4"
}
},
"node_modules/enhanced-resolve": {
"version": "5.18.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
@@ -1837,6 +1858,12 @@
"@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/javascript-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/javascript-stringify/-/javascript-stringify-2.1.0.tgz",
"integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==",
"license": "MIT"
},
"node_modules/jest-worker": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
@@ -1896,6 +1923,18 @@
"dev": true,
"license": "MIT"
},
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -1936,6 +1975,20 @@
"node": ">=6.11.5"
}
},
"node_modules/loader-utils": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
"license": "MIT",
"dependencies": {
"big.js": "^5.2.2",
"emojis-list": "^3.0.0",
"json5": "^2.1.2"
},
"engines": {
"node": ">=8.9.0"
}
},
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -3632,7 +3685,6 @@
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"dev": true,
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
@@ -3640,6 +3692,20 @@
"engines": {
"node": ">= 14"
}
},
"node_modules/yaml-loader": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/yaml-loader/-/yaml-loader-0.8.1.tgz",
"integrity": "sha512-BCEndnUoi3BaZmePkwGGe93txRxLgMhBa/gE725v1/GHnura8QvNs7c4+4C1yyhhKoj3Dg63M7IqhA++15j6ww==",
"license": "MIT",
"dependencies": {
"javascript-stringify": "^2.0.1",
"loader-utils": "^2.0.0",
"yaml": "^2.0.0"
},
"engines": {
"node": ">= 14"
}
}
}
}

View File

@@ -1,5 +1,5 @@
{
"name": "lena-schilling-website",
"name": "dialog-relations-website",
"version": "1.0.0",
"scripts": {
"build:css": "NODE_ENV=production webpack --config webpack.config.js --mode production",
@@ -16,5 +16,8 @@
"tailwindcss": "^3.4.17",
"webpack": "^5.88.0",
"webpack-cli": "^5.1.4"
},
"dependencies": {
"yaml-loader": "^0.8.1"
}
}

View File

@@ -0,0 +1,15 @@
plugin.tx_form {
settings {
yamlConfigurations {
11 = EXT:base/Configuration/Ext/Form/Yaml/Setup.yaml
}
}
}
module.tx_form {
settings {
yamlConfigurations {
11 = EXT:base/Configuration/Ext/Form/Yaml/Setup.yaml
}
}
}

View File

@@ -0,0 +1,200 @@
TYPO3:
CMS:
Form:
prototypes:
standard:
formElementsDefinition:
Form:
renderingOptions:
templateVariant: version2
partialRootPaths:
20: 'EXT:base/Resources/Private/Extensions/Form/Partials/'
variants:
-
renderingOptions:
formNavigation:
btnNextClassAttribute: 'btn btn-primary'
btnPreviousClassAttribute: 'btn btn-outline btn-primary'
btnSubmitClassAttribute: 'btn btn-primary'
fieldProperties:
descriptionClassAttribute: 'form-text'
errorClassAttribute: 'peer [&_input]:input-error [&_[type=checkbox]]:checkbox-error [&_[type=file]]:file-input-error [&_[type=radio]]:radio-error [&_select]:select-error [&_textarea]:textarea-error'
errorMsgClassAttribute: 'label label-text-alt justify-start text-error peer-[.form-control]:-mt-4'
requiredMarkClassAttribute: 'required'
visuallyHiddenClassAttribute: 'sr-only'
SummaryPage:
variants:
-
renderingOptions:
listRowClassAttribute: 'grid grid-cols-2 gap-4'
# Form elements
AdvancedPassword:
variants:
-
properties:
fieldsetClassAttribute: 'form-control form-element-advancedpassword mb-4'
containerClassAttribute: 'form-control mb-4'
elementClassAttribute: 'input input-bordered'
confirmationClassAttribute: 'input input-bordered'
labelClassAttribute: 'label label-text justify-start'
renderFieldset: 0
Checkbox:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-checkbox mb-4'
elementClassAttribute: 'checkbox'
labelTextClassAttribute: 'label-text'
labelClassAttribute: 'label cursor-pointer justify-start gap-2'
ContentElement:
variants:
1:
properties:
outerContainerClassAttribute: 'mb-4 [&_.container]:max-w-none [&_.frame]:py-0'
CountrySelect:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-select mb-4'
elementClassAttribute: 'select select-bordered'
labelClassAttribute: 'label label-text justify-start'
Date:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-date mb-4'
elementClassAttribute: 'input input-bordered'
labelClassAttribute: 'label label-text justify-start'
DatePicker:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-date mb-4'
elementClassAttribute: 'input input-bordered'
labelClassAttribute: 'label label-text justify-start'
SingleSelect:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-select mb-4'
elementClassAttribute: 'select select-bordered'
labelClassAttribute: 'label label-text justify-start'
StaticText:
variants:
1:
properties:
containerClassAttribute: 'form-element-statictext mb-4 [&>p]:label-text'
Email:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-email mb-4'
elementClassAttribute: 'border border-primary block w-full p-2'
labelClassAttribute: 'label label-text font-bold justify-start block w-full mb-2'
Fieldset:
variants:
-
properties:
elementClassAttribute: 'form-element-fieldset mb-4 [&>legend]:font-bold'
FileUpload:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-fileupload mb-4'
elementClassAttribute: 'file-input file-input-bordered'
labelClassAttribute: 'label label-text justify-start'
ImageUpload:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-imageupload mb-4'
elementClassAttribute: 'file-input file-input-bordered'
labelClassAttribute: 'label label-text justify-start'
MultiCheckbox:
variants:
-
properties:
fieldsetClassAttribute: 'mb-4 [&>legend]:label [&>legend]:label-text [&>legend]:justify-start'
containerClassAttribute: 'form-control form-element-checkbox'
elementClassAttribute: 'checkbox'
labelTextClassAttribute: 'label-text'
labelClassAttribute: 'label cursor-pointer justify-start gap-2'
MultiSelect:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-multiselect mb-4'
elementClassAttribute: 'select select-bordered'
labelClassAttribute: 'label label-text justify-start'
Number:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-number mb-4'
elementClassAttribute: 'input input-bordered'
labelClassAttribute: 'label label-text justify-start'
Password:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-password mb-4'
elementClassAttribute: 'input input-bordered'
labelClassAttribute: 'label label-text justify-start'
RadioButton:
variants:
-
properties:
fieldsetClassAttribute: 'mb-4 [&>legend]:label [&>legend]:label-text [&>legend]:justify-start'
containerClassAttribute: 'form-control form-element-radio'
elementClassAttribute: 'radio'
labelTextClassAttribute: 'label-text'
labelClassAttribute: 'label cursor-pointer justify-start gap-2'
Telephone:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-phone mb-4'
elementClassAttribute: 'border border-primary block w-full p-2'
labelClassAttribute: 'label label-text font-bold justify-start block w-full mb-2'
Text:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-text mb-4'
elementClassAttribute: 'border border-primary block w-full p-2'
labelClassAttribute: 'label label-text font-bold justify-start block w-full mb-2'
Textarea:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-textarea mb-4'
elementClassAttribute: 'border border-primary block w-full p-2 h-24'
labelClassAttribute: 'label label-text font-bold justify-start block w-full mb-2'
Url:
variants:
-
properties:
containerClassAttribute: 'form-control form-element-url mb-4'
elementClassAttribute: 'border border-primary block w-full p-2'
labelClassAttribute: 'label label-text font-bold justify-start block w-full mb-2'
GridRow:
variants:
-
properties:
elementClassAttribute: 'form-element form-element-gridrow grid grid-cols-12 gap-8 md:gap-16'
gridColumnClassAutoConfiguration:
gridSize: 12
viewPorts:
xs:
classPattern: 'col-span-{@numbersOfColumnsToUse}'
sm:
classPattern: 'sm:col-span-{@numbersOfColumnsToUse}'
md:
classPattern: 'md:col-span-{@numbersOfColumnsToUse}'
lg:
classPattern: 'lg:col-span-{@numbersOfColumnsToUse}'
xl:
classPattern: 'xl:col-span-{@numbersOfColumnsToUse}'
xxl:
classPattern: 'xxl:col-span-{@numbersOfColumnsToUse}'

View File

@@ -8,35 +8,18 @@ mod {
title = Default
config {
backend_layout {
colCount = 12
rowCount = 2
colCount = 1
rowCount = 1
rows {
1 {
columns {
1 {
name = LLL:EXT:base/Resources/Private/Language/locallang_be.xlf:backend_layout.column.normal
colPos = 0
colspan = 12
identifier = main
}
}
}
2 {
columns {
1 {
name = Footer Left
colPos = 90
colspan = 6
identifier = footer-left
}
2 {
name = Footer Right
colPos = 91
colspan = 6
identifier = footer-right
}
}
}
}
}
}

View File

@@ -9,7 +9,7 @@ RTE {
TCEFORM {
tt_content {
CType {
keepItems = cloonar_header,cloonar_text,cloonar_textimage,news_newsliststicky,news_pi1,cloonar_hero,cloonar_stats
keepItems = cloonar_text,cloonar_textimage,cloonar_hero,form_formframework
}
}
}

View File

@@ -1,4 +1,5 @@
@import './TypoScript/'
@import 'EXT:base/Configuration/Ext/Form/TypoScript/setup.typoscript'
# Override tx_news templates
plugin.tx_news {

View File

@@ -3,7 +3,7 @@
<f:section name="Header" />
<f:section name="Main">
<section class="bg-white md:bg-hero-gradient">
<section class="bg-white md:bg-hero-gradient mb-16">
<div class="container mx-auto px-6 py-12 md:py-24 bg-white md:bg-hero-inner">
<div class="md:flex md:items-center">
@@ -69,7 +69,7 @@
</div>
<!-- Heading -->
<h1 class="text-3xl md:text-5xl font-extrabold">
<h1>
{data.header}
</h1>

View File

@@ -1,8 +1,8 @@
<f:layout name="Default" />
<f:section name="Main">
<div class="fade-in-on-scroll">
<div class="fade-in-on-scroll py-16">
<f:if condition="{data.header}">
<f:then><h2 class="font-hajime text-primary font-normal leading-none text-3xl md:text-5xl mb-4">{data.header}</h2></f:then>
<f:then><h2>{data.header}</h2></f:then>
</f:if>
<f:if condition="{data.bodytext}">
<f:then>

View File

@@ -3,7 +3,7 @@
<f:section name="Main">
<f:variable name="imageSizeClass" value="md:w-1/2" />
<f:variable name="textSizeClass" value="md:w-1/2" />
<f:variable name="gapClass" value="gap-8" />
<f:variable name="gapClass" value="gap-8 md:gap-16" />
<f:if condition="{data.imagesize} == 1"> <!-- Size 25% -> map to 40% for layout -->
<f:variable name="imageSizeClass" value="md:w-2/5" />
@@ -11,7 +11,7 @@
<f:variable name="gapClass" value="gap-8 md:gap-16 lg:gap-32" />
</f:if>
<div class="flex flex-col {gapClass} fade-in-on-scroll {f:if(condition: '{data.imageorient} == 26', then: 'md:flex-row-reverse', else: 'md:flex-row')}">
<div class="flex flex-col {gapClass} py-16 fade-in-on-scroll {f:if(condition: '{data.imageorient} == 26', then: 'md:flex-row-reverse', else: 'md:flex-row')}">
<div class="flex items-center justify-center {imageSizeClass}">
<f:if condition="{data.image}">
<f:then>
@@ -39,7 +39,7 @@
cropVariant="default"
width="538c"
alt="{data.image.0.alternative}"
class="max-w-full h-auto rounded-lg block"
class="max-w-full h-auto block"
/>
</figure>
</f:then>
@@ -50,8 +50,7 @@
</div>
<div class="{textSizeClass}">
<f:if condition="{data.header}">
<h2 class="font-hajime text-primary font-normal leading-none text-3xl md:text-5xl mb-2">{data.header}</h2>
<h3 class="text-xl md:text-2xl font-semibold mb-4">{data.subheader}</h3>
<h2>{data.header}</h2>
</f:if>
<f:if condition="{data.bodytext}">
<div class="prose lg:prose-lg">

View File

@@ -0,0 +1,11 @@
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" xmlns:formvh="http://typo3.org/ns/TYPO3/CMS/Form/ViewHelpers" data-namespace-typo3-fluid="true">
<formvh:renderRenderable renderable="{element}">
<div class="{f:if(condition: element.properties.elementClassAttribute, then: '{element.properties.elementClassAttribute}')} grid-cols-{f:if(condition: '{element.properties.gridColumnClassAutoConfiguration.gridSize}', then: '{element.properties.gridColumnClassAutoConfiguration.gridSize}', else: '12')}">
<f:for each="{element.elements}" as="element">
<div class="{formvh:gridColumnClassAutoConfiguration(element: element)}">
<f:render partial="{element.templateName}" arguments="{element: element}" />
</div>
</f:for>
</div>
</formvh:renderRenderable>
</html>

View File

@@ -1,18 +1,18 @@
<nav class="main-nav group sticky top-0 z-50 bg-repeat" id="mainNav">
<nav class="py-1 main-nav group sticky top-0 z-50 bg-repeat" id="mainNav">
<div class="container flex items-center h-full mx-auto px-4">
<a href="/" class="nav-logo">
<f:image src="EXT:base/Resources/Public/Images/logo.png" alt="Logo" class="block max-h-[50px] h-auto w-auto" />
</a>
<button class="nav-toggle group lg:hidden relative w-[30px] h-[30px] cursor-pointer ml-auto bg-none border-none" id="navToggle" aria-label="Toggle Menu">
<span class="nav-toggle-icon block relative w-full h-[2px] bg-primary transition-all duration-300
before:content-[''] before:block before:absolute before:w-full before:h-[2px] before:bg-primary before:left-0 before:-top-[8px] before:transition-all before:duration-300
<span class="nav-toggle-icon block relative w-full h-[2px] bg-primary transition-all duration-300
before:content-[''] before:block before:absolute before:w-full before:h-[2px] before:bg-primary before:left-0 before:-top-[8px] before:transition-all before:duration-300
after:content-[''] after:block after:absolute after:w-full after:h-[2px] after:bg-primary after:left-0 after:top-[8px] after:transition-all after:duration-300
group-[.active]:bg-transparent group-[.active]:before:rotate-45 group-[.active]:before:translate-x-[5px] group-[.active]:before:translate-y-[5px]
group-[.active]:bg-transparent group-[.active]:before:rotate-45 group-[.active]:before:translate-x-[5px] group-[.active]:before:translate-y-[5px]
group-[.active]:after:-rotate-45 group-[.active]:after:translate-x-[5px] group-[.active]:after:-translate-y-[5px]"></span>
</button>
<ul class="nav-links flex items-center list-none mx-auto font-hajime text-primary
lg:flex lg:relative lg:top-auto lg:left-auto lg:right-auto lg:flex-row lg:max-h-full lg:overflow-visible lg:bg-transparent
<ul class="nav-links flex items-center list-none mx-auto font-hajime text-primary
lg:flex lg:relative lg:top-auto lg:left-auto lg:right-auto lg:flex-row lg:max-h-full lg:overflow-visible lg:bg-transparent
absolute top-full left-0 right-0 flex-col max-h-0 overflow-hidden bg-white transition-max-height duration-400 ease-in-out group-[.open]:max-h-[500px]" id="navLinks">
<f:for each="{mainnavigation}" as="mainnavigationItem">
<li class="nav-item lg:mx-4 lg:my-0 lg:p-0 lg:border-0 mx-0 my-0 p-4 border-t border-black/10 first:border-t-0 {f:if(condition: mainnavigationItem.active, then:' active')}{f:if(condition: mainnavigationItem.children, then:' has-submenu')}">

Binary file not shown.

View File

@@ -1,64 +1,76 @@
// Update font file names and ensure no spaces for better compatibility.
@font-face {
font-family: 'Hajime Sans';
src: url('../Fonts/Hajime-Sans.woff2') format('woff2');
font-weight: 400;
font-family: 'Barlow';
src: url('../Fonts/Barlow-Medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Inter';
src: url('../Fonts/Inter.woff2') format('woff2');
font-weight: 100 900; // Adjust as needed for variable font range
font-family: 'Barlow';
src: url('../Fonts/Barlow-Bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: 'Inter', sans-serif;
font-family: 'Barlow', sans-serif;
font-weight: 500;
font-size: 14px;
@media (min-width: $breakpoint-md) {
font-size: 18px;
}
}
h1, h2 {
font-family: 'Hajime Sans', sans-serif;
color: var(--bs-primary);
font-weight: 400;
h1, h2, h3, h4, h5, h6 {
font-family: 'Barlow', sans-serif;
color: var(--color-primary);
font-weight: 700;
line-height: 1;
}
h1 {
font-size: 3rem;
@media (min-width: $breakpoint-md) {
font-size: 4.5rem;
}
/* @media (min-width: $breakpoint-md) { */
/* font-size: 4.5rem; */
/* } */
}
h2 {
font-size: 2rem;
@media (min-width: $breakpoint-md) {
font-size: 3rem;
}
/* @media (min-width: $breakpoint-md) { */
/* font-size: 3rem; */
/* } */
}
h3 {
font-size: 1.125rem;
font-weight: 600;
font-size: 1.75rem;
@media (min-width: $breakpoint-md) {
font-size: 1.5rem;
}
/* @media (min-width: $breakpoint-md) { */
/* font-size: 1.5rem; */
/* } */
}
h4 {
font-size: 1.125rem;
font-weight: 600;
@media (min-width: $breakpoint-md) {
font-size: 1.5rem;
}
/* @media (min-width: $breakpoint-md) { */
/* font-size: 1.5rem; */
/* } */
}
h5 {
font-size: 0.875rem;
}
h6 {
font-size: 0.875rem;
font-weight: 500;
}
p {
@@ -71,11 +83,11 @@ a {
font-weight: 700;
&:hover {
color: var(--bs-primary-light)
color: var(--bs-primary)
}
}
button, .btn {
font-family: 'Hajime Sans', sans-serif;
font-weight: 400;
font-family: 'Barlow', sans-serif;
font-weight: 700;
}

View File

@@ -1,6 +1,6 @@
.container {
margin: auto;
padding: 3rem 1rem;
/* padding: 3rem 1rem; */
@include respond($breakpoint-sm) {
max-width: 540px;

View File

@@ -9,11 +9,11 @@
@import 'abstracts/icons';
@import 'abstracts/fade-in';
@import 'base/base';
@import 'components/navigation';
@import 'components/images';
@import 'components/news';
@import "components/news_detail";
@import 'components/footer';
/* @import 'components/navigation'; */
/* @import 'components/images'; */
/* @import 'components/news'; */
/* @import "components/news_detail"; */
/* @import 'components/footer'; */
@import 'components/buttons';
@import 'layouts/home-page';

62
safelist-loader.js Normal file
View File

@@ -0,0 +1,62 @@
// safelist-loader.js
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
/**
* Generate a Tailwind CSS safelist array from a YAML file.
* @param {string} yamlFilePath - Path to the YAML file, relative to the working directory.
* @returns {string[]} Array of unique class names.
*/
function generateSafelist(yamlFilePath) {
// Resolve the YAML file path
const absolutePath = path.resolve(process.cwd(), yamlFilePath);
const content = fs.readFileSync(absolutePath, 'utf8');
const doc = yaml.load(content);
const classes = new Set();
function walk(obj) {
if (Array.isArray(obj)) {
obj.forEach(walk);
} else if (obj && typeof obj === 'object') {
// Expand gridColumnClassAutoConfiguration placeholders
if (obj.gridColumnClassAutoConfiguration) {
const { gridSize, viewPorts } = obj.gridColumnClassAutoConfiguration;
const placeholder = /\{\@[\w]+\}/g;
if (typeof gridSize === 'number' && viewPorts) {
Object.values(viewPorts).forEach(vp => {
if (typeof vp.classPattern === 'string') {
for (let i = 1; i <= gridSize; i++) {
classes.add(vp.classPattern.replace(placeholder, i));
}
}
});
}
}
// Collect any *ClassAttribute strings
Object.entries(obj).forEach(([key, val]) => {
if (/Class(Attribute)?$/.test(key) && typeof val === 'string') {
val.split(/\s+/).forEach(c => {
if (c) classes.add(c);
});
} else {
walk(val);
}
});
}
}
walk(doc);
return Array.from(classes);
}
module.exports = generateSafelist;
// Usage in tailwind.config.js:
// const safelistLoader = require('./safelist-loader');
// module.exports = {
// // ... other config ...
// safelist: generateSafelist('packages/base/Configuration/Ext/Form/Yaml/Setup.yaml'),
// };

View File

@@ -1,27 +1,42 @@
/** @type {import('tailwindcss').Config} */
const defaultTheme = require('tailwindcss/defaultTheme')
const safelistLoader = require('./safelist-loader');
const safelist = safelistLoader('packages/base/Configuration/Ext/Form/Yaml/Setup.yaml');
const isProduction = process.env.NODE_ENV === 'production';
const config = {
// Keep content defined always, but rely on safelist in dev
content: [
"./packages/base/Configuration/**/*.yaml",
"./packages/base/Resources/Private/**/*.html",
"./packages/base/Resources/Private/**/*.js",
"./packages/base/ContentBlocks/ContentElements/**/*.html",
"./public/typo3conf/ext/*/Resources/Private/**/*.html",
],
// Disable purging in dev by safelisting everything
safelist: isProduction ? [] : [{ pattern: /.*/ }],
safelist: isProduction ? [
...safelist,
] : [
'md:col-span-6',
{
pattern: /col-span-\d+/,
variants: ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'] // Include other variants (sm, lg) if needed
},
{ pattern: /.*/ }
],
theme: {
extend: {
transitionProperty: {
'max-height': 'max-height' // Add max-height to transition properties
},
fontFamily: {
sans: ['Inter', ...defaultTheme.fontFamily.sans],
hajime: ['"Hajime Sans"', ...defaultTheme.fontFamily.sans],
barlow: ['"Barlow"', ...defaultTheme.fontFamily.sans],
},
// borderColor: {
// primary: 'var(--color-primary)',
// },
colors: {
primary: 'var(--color-primary)',
yellow: '#F5AE07',