From 33bef0dcc0d764a066af1b078af7dcc5754ae110 Mon Sep 17 00:00:00 2001 From: jramke Date: Sun, 29 Dec 2024 18:55:08 +0100 Subject: [PATCH] [TASK] baseline for v2 --- Configuration/Ext/Form/Yaml/Setup.yaml | 145 ++++++++--------- Resources/Private/Ext/Form/Partials/Page.html | 12 ++ Resources/Private/Tailwind/Src/Plugin.ts | 18 --- Resources/Private/Tailwind/Src/Preset.ts | 27 ---- Resources/Private/Tailwind/Src/Safelist.ts | 46 ++++-- .../Private/Tailwind/Src/Styles/Container.css | 21 +++ .../Private/Tailwind/Src/Styles/Container.ts | 22 --- .../Private/Tailwind/Src/Styles/Form.css | 63 ++++++++ .../Private/Tailwind/Src/Styles/Frame.ts | 3 +- .../Private/Tailwind/Src/Styles/Table.ts | 13 -- .../Private/Tailwind/Src/Styles/Theme.css | 6 + .../Private/Tailwind/Src/Styles/Utilities.css | 13 ++ .../Private/Tailwind/Src/Styles/index.ts | 9 -- Resources/Private/Tailwind/__tsc.safelist | 147 ++++++++++++++++++ Resources/Private/Tailwind/index.css | 4 + Resources/Private/Tailwind/index.ts | 20 ++- Resources/Private/Tailwind/types.d.ts | 7 +- index.css | 4 + index.js | 9 +- package.json | 9 +- src/input.css | 13 +- src/tailwind.config.js | 10 -- 22 files changed, 412 insertions(+), 209 deletions(-) create mode 100644 Resources/Private/Ext/Form/Partials/Page.html delete mode 100644 Resources/Private/Tailwind/Src/Plugin.ts delete mode 100644 Resources/Private/Tailwind/Src/Preset.ts create mode 100644 Resources/Private/Tailwind/Src/Styles/Container.css delete mode 100644 Resources/Private/Tailwind/Src/Styles/Container.ts create mode 100644 Resources/Private/Tailwind/Src/Styles/Form.css delete mode 100644 Resources/Private/Tailwind/Src/Styles/Table.ts create mode 100644 Resources/Private/Tailwind/Src/Styles/Theme.css create mode 100644 Resources/Private/Tailwind/Src/Styles/Utilities.css delete mode 100644 Resources/Private/Tailwind/Src/Styles/index.ts create mode 100644 Resources/Private/Tailwind/__tsc.safelist create mode 100644 Resources/Private/Tailwind/index.css create mode 100644 index.css delete mode 100644 src/tailwind.config.js diff --git a/Configuration/Ext/Form/Yaml/Setup.yaml b/Configuration/Ext/Form/Yaml/Setup.yaml index 3a4ac7f..27a31c6 100755 --- a/Configuration/Ext/Form/Yaml/Setup.yaml +++ b/Configuration/Ext/Form/Yaml/Setup.yaml @@ -14,175 +14,180 @@ TYPO3: renderingOptions: formNavigation: btnNextClassAttribute: 'btn btn-primary' - btnPreviousClassAttribute: 'btn btn-outline btn-primary' + btnPreviousClassAttribute: 'btn btn-secondary' btnSubmitClassAttribute: 'btn btn-primary' + navigationWrapperClassAttribute: 'mt-form' 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' + descriptionClassAttribute: 'form-description' + errorClassAttribute: '' + errorMsgClassAttribute: 'form-error' requiredMarkClassAttribute: 'required' visuallyHiddenClassAttribute: 'sr-only' SummaryPage: variants: - renderingOptions: - listRowClassAttribute: 'grid grid-cols-2 gap-4' + listClassAttribute: 'space-y-2' + listRowClassAttribute: 'grid grid-cols-2 gap-form' + labelWrapperClassAttribute: 'form-label' + valueWrapperClassAttribute: '' # 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 + fieldsetClassAttribute: 'form-field form-field-advancedpassword' + containerClassAttribute: 'form-field' + elementClassAttribute: 'form-input' + confirmationClassAttribute: 'form-input' + labelClassAttribute: 'form-label' + legendVisuallyHidden: 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' + containerClassAttribute: 'form-field form-field-checkbox' + elementClassAttribute: 'form-checkbox' + labelTextClassAttribute: 'leading-none form-label' + labelClassAttribute: 'flex items-center gap-2' ContentElement: variants: 1: properties: - outerContainerClassAttribute: 'mb-4 [&_.container]:max-w-none [&_.frame]:py-0' + outerContainerClassAttribute: 'form-field form-field-contentelement' CountrySelect: variants: - properties: - containerClassAttribute: 'form-control form-element-select mb-4' - elementClassAttribute: 'select select-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-select' + elementClassAttribute: 'form-select' + labelClassAttribute: 'form-label' Date: variants: - properties: - containerClassAttribute: 'form-control form-element-date mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-date' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' DatePicker: variants: - properties: - containerClassAttribute: 'form-control form-element-date mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-date' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' SingleSelect: variants: - properties: - containerClassAttribute: 'form-control form-element-select mb-4' - elementClassAttribute: 'select select-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-select' + elementClassAttribute: 'form-select' + labelClassAttribute: 'form-label' StaticText: variants: 1: properties: - containerClassAttribute: 'form-element-statictext mb-4 [&>h2]:font-bold [&>h2]:text-base [&>h2]:mb-1 [&>p]:label-text' + containerClassAttribute: 'form-field form-field-statictext' Email: variants: - properties: - containerClassAttribute: 'form-control form-element-email mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-email' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' Fieldset: variants: - properties: - elementClassAttribute: 'form-element-fieldset mb-4 [&>legend]:font-bold' + elementClassAttribute: 'form-field form-field-fieldset gap-0 [&>legend]:form-legend [&>legend]:mb-form-field' FileUpload: variants: - properties: - containerClassAttribute: 'form-control form-element-fileupload mb-4' + containerClassAttribute: 'form-field form-field-fileupload' elementClassAttribute: 'file-input file-input-bordered' - labelClassAttribute: 'label label-text justify-start' + labelClassAttribute: 'form-label' ImageUpload: variants: - properties: - containerClassAttribute: 'form-control form-element-imageupload mb-4' + containerClassAttribute: 'form-field form-field-imageupload' elementClassAttribute: 'file-input file-input-bordered' - labelClassAttribute: 'label label-text justify-start' + labelClassAttribute: 'form-label' 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' + fieldsetClassAttribute: 'form-field form-field-checkbox [&>legend]:form-legend [&>legend]:mb-form-field' + containerClassAttribute: 'mb-2 last:mb-0' + elementClassAttribute: 'form-checkbox' + labelTextClassAttribute: 'form-label leading-none' + labelClassAttribute: 'flex items-center gap-2' MultiSelect: variants: - properties: - containerClassAttribute: 'form-control form-element-multiselect mb-4' - elementClassAttribute: 'select select-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-multiselect' + elementClassAttribute: 'form-multiselect' + labelClassAttribute: 'form-label' Number: variants: - properties: - containerClassAttribute: 'form-control form-element-number mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-number' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' Password: variants: - properties: - containerClassAttribute: 'form-control form-element-password mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-password' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' 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' + fieldsetClassAttribute: 'form-field form-field-radiobutton [&>legend]:form-legend [&>legend]:mb-form-field' + containerClassAttribute: 'mb-2 last:mb-0' + elementClassAttribute: 'form-radio' + labelTextClassAttribute: 'form-label leading-none' + labelClassAttribute: 'flex items-center gap-2' + legendVisuallyHidden: 0 Telephone: variants: - properties: - containerClassAttribute: 'form-control form-element-phone mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-phone' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' Text: variants: - properties: - containerClassAttribute: 'form-control form-element-text mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-text' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' Textarea: variants: - properties: - containerClassAttribute: 'form-control form-element-textarea mb-4' - elementClassAttribute: 'textarea textarea-bordered h-24' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-textarea' + elementClassAttribute: 'form-textarea' + labelClassAttribute: 'form-label' Url: variants: - properties: - containerClassAttribute: 'form-control form-element-url mb-4' - elementClassAttribute: 'input input-bordered' - labelClassAttribute: 'label label-text justify-start' + containerClassAttribute: 'form-field form-field-url' + elementClassAttribute: 'form-input' + labelClassAttribute: 'form-label' GridRow: variants: - properties: - elementClassAttribute: 'form-element form-element-gridrow grid gap-x-4' + elementClassAttribute: 'form-element form-field-gridrow grid gap-form' gridColumnClassAutoConfiguration: gridSize: 12 viewPorts: @@ -197,4 +202,4 @@ TYPO3: xl: classPattern: 'xl:col-span-{@numbersOfColumnsToUse}' xxl: - classPattern: 'xxl:col-span-{@numbersOfColumnsToUse}' + classPattern: 'xxl:col-span-{@numbersOfColumnsToUse}' \ No newline at end of file diff --git a/Resources/Private/Ext/Form/Partials/Page.html b/Resources/Private/Ext/Form/Partials/Page.html new file mode 100644 index 0000000..ad0c7c4 --- /dev/null +++ b/Resources/Private/Ext/Form/Partials/Page.html @@ -0,0 +1,12 @@ + + +
+ +

{formvh:translateElementProperty(element: page, property: 'label')}

+
+ + + +
+
+ \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Plugin.ts b/Resources/Private/Tailwind/Src/Plugin.ts deleted file mode 100644 index 55bc657..0000000 --- a/Resources/Private/Tailwind/Src/Plugin.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PluginCreator } from 'tailwindcss/types/config'; -import type { TscConfig } from '../types'; - -import tailwindPlugin from 'tailwindcss/plugin'; -import { defaultConfig } from './Config'; -import { frameStyles, containerStyles, tableStyles } from './Styles'; -import { deepMerge } from './Utils'; - -const mainFunction: PluginCreator = (pluginApi) => { - const pluginConfig = pluginApi.config('tsc') as Partial; - const tscConfig = deepMerge(defaultConfig, pluginConfig); - - frameStyles(tscConfig.frame, pluginApi); - containerStyles(pluginApi); - tableStyles(pluginApi); -}; - -export default tailwindPlugin(mainFunction); diff --git a/Resources/Private/Tailwind/Src/Preset.ts b/Resources/Private/Tailwind/Src/Preset.ts deleted file mode 100644 index e037808..0000000 --- a/Resources/Private/Tailwind/Src/Preset.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { Config } from 'tailwindcss'; - -import plugin from './Plugin'; -import typography from '@tailwindcss/typography'; -import daisyui from 'daisyui'; - -export default { - theme: { - extend: { - container: { - center: true, - padding: '1.5rem', - }, - spacing: { - reading: '80ch', - }, - typography: { - DEFAULT: { - css: { - maxWidth: 'none', - }, - }, - }, - }, - }, - plugins: [typography, daisyui, plugin], -} satisfies Omit; \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Safelist.ts b/Resources/Private/Tailwind/Src/Safelist.ts index a06c159..4cd2d2e 100644 --- a/Resources/Private/Tailwind/Src/Safelist.ts +++ b/Resources/Private/Tailwind/Src/Safelist.ts @@ -1,22 +1,36 @@ +// TODO: adjust safelist handling after stable tailwind v4 +import * as fs from 'fs'; +import * as path from 'path'; + function safelistGrid(minGridCols: number, maxGridCols: number) { - let gridColsRegexPatterns: string[] = []; + let classes: string[] = []; + for (let i = minGridCols; i <= maxGridCols; i++) { - gridColsRegexPatterns.push(`(col-span|grid-cols)-${i}`); + classes.push(`col-span-${i}`, `grid-cols-${i}`); } - if (gridColsRegexPatterns.length > 0) { - return { - pattern: new RegExp(gridColsRegexPatterns.join('|')), - variants: ['sm', 'md', 'lg', 'xl', '2xl'], - }; - } else { - return null; - } + const variants = ['sm', 'md', 'lg', 'xl', '2xl']; + + let classesWithVariants: string[] = []; + variants.forEach(variant => { + classes.map(className => { + classesWithVariants.push(`${variant}:${className}`); + }); + }); + + return [...classes, ...classesWithVariants]; }; -export default [ - safelistGrid(1, 12), - { - pattern: /text-(left|center|right)/, - }, -]; \ No newline at end of file +(() => { + const safelist = [ + ...safelistGrid(1, 12), + ...['text-center', 'text-left', 'text-right'], + ]; + + const filePath = path.resolve(import.meta.dirname, '../__tsc.safelist'); + + fs.writeFileSync(filePath, safelist.join('\n'), 'utf8'); + console.log(`Safelist classes written to ${filePath}`); + + return safelist; +})(); \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/Container.css b/Resources/Private/Tailwind/Src/Styles/Container.css new file mode 100644 index 0000000..4e0bfdc --- /dev/null +++ b/Resources/Private/Tailwind/Src/Styles/Container.css @@ -0,0 +1,21 @@ +@utility container { + margin-inline: auto; + padding-inline: 1.5rem; +} + +@layer components { + .container.none { + max-width: none; + } + .container.full { + max-width: none; + padding-left: 0px; + padding-right: 0px; + } + .frame:has(.container.indent-right) { + margin-right: '33.33%'; + } + .frame:has(.container.indent-left) { + margin-left: '33.33%'; + } +} \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/Container.ts b/Resources/Private/Tailwind/Src/Styles/Container.ts deleted file mode 100644 index 865522f..0000000 --- a/Resources/Private/Tailwind/Src/Styles/Container.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { PluginAPI } from "tailwindcss/types/config"; - -export function containerStyles(pluginApi: PluginAPI) { - const { addComponents } = pluginApi; - - addComponents({ - '.container.none': { - 'max-width': 'none', - }, - '.container.full': { - 'max-width': 'none', - 'padding-left': '0px', - 'padding-right': '0px', - }, - '.frame:has(.container.indent-right)': { - 'margin-right': '33.33%', - }, - '.frame:has(.container.indent-left)': { - 'margin-left': '33.33%', - }, - }); -} \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/Form.css b/Resources/Private/Tailwind/Src/Styles/Form.css new file mode 100644 index 0000000..dbd07aa --- /dev/null +++ b/Resources/Private/Tailwind/Src/Styles/Form.css @@ -0,0 +1,63 @@ +@utility form-legend { + @apply font-semibold; +} +@utility form-field { + display: flex; + flex-direction: column; + gap: var(--spacing-form-field); +} +@utility form-label { + @apply text-sm font-medium; +} +@utility form-input { + @apply py-1 px-2 sm:text-sm; +} +@utility form-error { + @apply text-sm text-error; +} +@utility form-description { + @apply text-[0.8rem] text-neutral-600; +} +@utility form-navigation { + display: flex; + gap: var(--spacing-form-field); +} + +@layer utilities { + + /* if these where declared using the @utility they would get overriden by their defaults from the forms plugin */ + .form-select { + @apply form-input; + } + .form-multiselect { + @apply form-input; + } + .form-textarea { + @apply form-input; + --padding-y: calc(var(--spacing) * 1); + --border-width: 1px; + min-height: calc(3lh + (2 * (var(--padding-y) + var(--border-width)))); + max-height: calc(8lh + (2 * (var(--padding-y) + var(--border-width)))); + field-sizing: content; + } + + .form-field:not(:last-child):not(:has(+ .form-description)) { + margin-bottom: var(--spacing-form); + } + .form-field:has([aria-invalid="true"]) .form-label:before { + @apply bg-error; + content: ''; + display: inline-block; + margin-inline-end: .2em; + width: 1em; + height: 1em; + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='lucide lucide-circle-x'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m15 9-6 6'/%3E%3Cpath d='m9 9 6 6'/%3E%3C/svg%3E"); + mask-size: contain; + transform: translateY(2px); + } + .form-input[aria-invalid="true"], .form-textarea[aria-invalid="true"], .form-radio[aria-invalid="true"], .form-checkbox[aria-invalid="true"] { + @apply border-error ring-error; + } + + +} \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/Frame.ts b/Resources/Private/Tailwind/Src/Styles/Frame.ts index 28c5aca..283e4f6 100644 --- a/Resources/Private/Tailwind/Src/Styles/Frame.ts +++ b/Resources/Private/Tailwind/Src/Styles/Frame.ts @@ -1,5 +1,4 @@ -import type { PluginAPI } from "tailwindcss/types/config"; -import type { TscConfig } from "../../types"; +import type { TscConfig, PluginAPI } from "../../types"; export function frameStyles(frameConfig: TscConfig['frame'], pluginApi: PluginAPI) { if (frameConfig === false) { diff --git a/Resources/Private/Tailwind/Src/Styles/Table.ts b/Resources/Private/Tailwind/Src/Styles/Table.ts deleted file mode 100644 index 8d3a09c..0000000 --- a/Resources/Private/Tailwind/Src/Styles/Table.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { PluginAPI } from "tailwindcss/types/config"; - -export function tableStyles(pluginApi: PluginAPI) { - const { addComponents } = pluginApi; - - // CKEditor wraps the table in a figure with the class "table". This causes overflow issues because it tells tailwind to set the display to table. - // Because its not so easy to change this behavior in CKEditor, we need this css. - addComponents({ - '.prose figure.table': { - display: 'initial' - }, - }); -} \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/Theme.css b/Resources/Private/Tailwind/Src/Styles/Theme.css new file mode 100644 index 0000000..301f434 --- /dev/null +++ b/Resources/Private/Tailwind/Src/Styles/Theme.css @@ -0,0 +1,6 @@ +@theme { + --spacing-reading: 80ch; + --spacing-form: 2rem; + --spacing-form-field: 0.4rem; + --color-error: #FE5861; +} \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/Utilities.css b/Resources/Private/Tailwind/Src/Styles/Utilities.css new file mode 100644 index 0000000..8e772f3 --- /dev/null +++ b/Resources/Private/Tailwind/Src/Styles/Utilities.css @@ -0,0 +1,13 @@ +@utility prose { + max-width: none; +} + +@layer utilities { + /* + CKEditor wraps the table in a figure with the class "table". This causes overflow issues because it tells tailwind to set the display to table. + Because its not so easy to change this behavior in CKEditor, we need this css. + */ + .prose figure.table { + display: initial; + } +} \ No newline at end of file diff --git a/Resources/Private/Tailwind/Src/Styles/index.ts b/Resources/Private/Tailwind/Src/Styles/index.ts deleted file mode 100644 index dbd85fc..0000000 --- a/Resources/Private/Tailwind/Src/Styles/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { containerStyles } from "./Container"; -import { frameStyles } from "./Frame"; -import { tableStyles } from "./Table"; - -export { - containerStyles, - frameStyles, - tableStyles, -} \ No newline at end of file diff --git a/Resources/Private/Tailwind/__tsc.safelist b/Resources/Private/Tailwind/__tsc.safelist new file mode 100644 index 0000000..ef3060d --- /dev/null +++ b/Resources/Private/Tailwind/__tsc.safelist @@ -0,0 +1,147 @@ +col-span-1 +grid-cols-1 +col-span-2 +grid-cols-2 +col-span-3 +grid-cols-3 +col-span-4 +grid-cols-4 +col-span-5 +grid-cols-5 +col-span-6 +grid-cols-6 +col-span-7 +grid-cols-7 +col-span-8 +grid-cols-8 +col-span-9 +grid-cols-9 +col-span-10 +grid-cols-10 +col-span-11 +grid-cols-11 +col-span-12 +grid-cols-12 +sm:col-span-1 +sm:grid-cols-1 +sm:col-span-2 +sm:grid-cols-2 +sm:col-span-3 +sm:grid-cols-3 +sm:col-span-4 +sm:grid-cols-4 +sm:col-span-5 +sm:grid-cols-5 +sm:col-span-6 +sm:grid-cols-6 +sm:col-span-7 +sm:grid-cols-7 +sm:col-span-8 +sm:grid-cols-8 +sm:col-span-9 +sm:grid-cols-9 +sm:col-span-10 +sm:grid-cols-10 +sm:col-span-11 +sm:grid-cols-11 +sm:col-span-12 +sm:grid-cols-12 +md:col-span-1 +md:grid-cols-1 +md:col-span-2 +md:grid-cols-2 +md:col-span-3 +md:grid-cols-3 +md:col-span-4 +md:grid-cols-4 +md:col-span-5 +md:grid-cols-5 +md:col-span-6 +md:grid-cols-6 +md:col-span-7 +md:grid-cols-7 +md:col-span-8 +md:grid-cols-8 +md:col-span-9 +md:grid-cols-9 +md:col-span-10 +md:grid-cols-10 +md:col-span-11 +md:grid-cols-11 +md:col-span-12 +md:grid-cols-12 +lg:col-span-1 +lg:grid-cols-1 +lg:col-span-2 +lg:grid-cols-2 +lg:col-span-3 +lg:grid-cols-3 +lg:col-span-4 +lg:grid-cols-4 +lg:col-span-5 +lg:grid-cols-5 +lg:col-span-6 +lg:grid-cols-6 +lg:col-span-7 +lg:grid-cols-7 +lg:col-span-8 +lg:grid-cols-8 +lg:col-span-9 +lg:grid-cols-9 +lg:col-span-10 +lg:grid-cols-10 +lg:col-span-11 +lg:grid-cols-11 +lg:col-span-12 +lg:grid-cols-12 +xl:col-span-1 +xl:grid-cols-1 +xl:col-span-2 +xl:grid-cols-2 +xl:col-span-3 +xl:grid-cols-3 +xl:col-span-4 +xl:grid-cols-4 +xl:col-span-5 +xl:grid-cols-5 +xl:col-span-6 +xl:grid-cols-6 +xl:col-span-7 +xl:grid-cols-7 +xl:col-span-8 +xl:grid-cols-8 +xl:col-span-9 +xl:grid-cols-9 +xl:col-span-10 +xl:grid-cols-10 +xl:col-span-11 +xl:grid-cols-11 +xl:col-span-12 +xl:grid-cols-12 +2xl:col-span-1 +2xl:grid-cols-1 +2xl:col-span-2 +2xl:grid-cols-2 +2xl:col-span-3 +2xl:grid-cols-3 +2xl:col-span-4 +2xl:grid-cols-4 +2xl:col-span-5 +2xl:grid-cols-5 +2xl:col-span-6 +2xl:grid-cols-6 +2xl:col-span-7 +2xl:grid-cols-7 +2xl:col-span-8 +2xl:grid-cols-8 +2xl:col-span-9 +2xl:grid-cols-9 +2xl:col-span-10 +2xl:grid-cols-10 +2xl:col-span-11 +2xl:grid-cols-11 +2xl:col-span-12 +2xl:grid-cols-12 +text-center +text-left +text-right \ No newline at end of file diff --git a/Resources/Private/Tailwind/index.css b/Resources/Private/Tailwind/index.css new file mode 100644 index 0000000..c404163 --- /dev/null +++ b/Resources/Private/Tailwind/index.css @@ -0,0 +1,4 @@ +@import "./Src/Styles/Theme"; +@import "./Src/Styles/Utilities"; +@import "./Src/Styles/Container"; +@import "./Src/Styles/Form"; \ No newline at end of file diff --git a/Resources/Private/Tailwind/index.ts b/Resources/Private/Tailwind/index.ts index b104467..cbd0501 100644 --- a/Resources/Private/Tailwind/index.ts +++ b/Resources/Private/Tailwind/index.ts @@ -1,9 +1,13 @@ -import plugin from './Src/Plugin'; -import safelist from './Src/Safelist'; -import preset from './Src/Preset'; +import type { TscConfig } from './types'; -export { - plugin, - safelist, - preset, -}; \ No newline at end of file +import tailwindPlugin from 'tailwindcss/plugin'; +import { defaultConfig } from './Src/Config'; +import { frameStyles } from './Src/Styles/Frame'; +import { deepMerge } from './Src/Utils'; + +export default tailwindPlugin(async (pluginApi) => { + const pluginConfig = pluginApi.config('tsc') as Partial; + const tscConfig = deepMerge(defaultConfig, pluginConfig); + + frameStyles(tscConfig.frame, pluginApi); +}); diff --git a/Resources/Private/Tailwind/types.d.ts b/Resources/Private/Tailwind/types.d.ts index 5f48866..7679e21 100644 --- a/Resources/Private/Tailwind/types.d.ts +++ b/Resources/Private/Tailwind/types.d.ts @@ -1,3 +1,5 @@ +import createPlugin from 'tailwindcss/plugin'; + export type TscConfig = { frame: { default: string; @@ -7,4 +9,7 @@ export type TscConfig = { large: string; }; } | false; -}; \ No newline at end of file +}; + +// Somehow not exported by Tailwind +export type PluginAPI = Parameters[0]>[0]; \ No newline at end of file diff --git a/index.css b/index.css new file mode 100644 index 0000000..96f31d2 --- /dev/null +++ b/index.css @@ -0,0 +1,4 @@ +/* TODO: adjust safelist handling after stable tailwind v4 */ +@source "./**/*.{html,yaml,typoscript,tsconfig,safelist}"; + +@import "./Resources/Private/Tailwind"; diff --git a/index.js b/index.js index 7e55308..8b7d242 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,2 @@ -import { plugin, safelist, preset } from './Resources/Private/Tailwind'; - -export { - plugin, - safelist, - preset, -} \ No newline at end of file +import Plugin from "./Resources/Private/Tailwind"; +export default Plugin; \ No newline at end of file diff --git a/package.json b/package.json index 9775c43..f0e193c 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,13 @@ { + "type": "module", "devDependencies": { + "@tailwindcss/cli": "^4.0.0-beta.8", + "@tailwindcss/forms": "^0.5.9", "@tailwindcss/typography": "^0.5.15", - "daisyui": "^4.12.10", - "tailwindcss": "^3.4.12" + "tailwindcss": "^4.0.0-beta.8" }, "scripts": { - "tailwind": "npx tailwindcss -i ./input.css -o ./public/output.css --watch" + "safelist": "tsx ./Resources/Private/Tailwind/Src/Safelist.ts", + "tailwind": "npx @tailwindcss/cli -i ./input.css -o ./public/output.css --watch" } } diff --git a/src/input.css b/src/input.css index bd6213e..62d8b51 100644 --- a/src/input.css +++ b/src/input.css @@ -1,3 +1,10 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; \ No newline at end of file +@import "tailwindcss"; + +@plugin "@tailwindcss/typography"; +@plugin "@tailwindcss/forms" { + strategy: "class"; +} + +/* TODO: how can we use the @import programmatically inside the plugin so we only need one line */ +@import "./vendor/jramke/tailwind-styled-content"; +@plugin "./vendor/jramke/tailwind-styled-content"; \ No newline at end of file diff --git a/src/tailwind.config.js b/src/tailwind.config.js deleted file mode 100644 index cc7ac6c..0000000 --- a/src/tailwind.config.js +++ /dev/null @@ -1,10 +0,0 @@ -import { preset, safelist } from '../../tailwind_styled_content'; - -/** @type {import('tailwindcss').Config} */ -module.exports = { - presets: [preset], - content: [ - './vendor/jramke/tailwind-styled-content/**/*.{html,yaml,typoscript,tsconfig}' - ], - safelist: [...safelist] -} \ No newline at end of file