From ae17fa0145dda57b181f3fef9430bcea94dfa96d Mon Sep 17 00:00:00 2001 From: Oscar Otero Date: Mon, 2 Jan 2023 15:57:03 +0100 Subject: [PATCH] Added Tailwindcss plugin. Close #344 --- CHANGELOG.md | 3 + cli/new.ts | 1 + deps/tailwindcss.ts | 2 + plugins/postcss.ts | 1 + plugins/tailwindcss.ts | 58 + tests/__snapshots__/tailwindcss.test.ts.snap | 1675 ++++++++++++++++++ tests/assets/tailwindcss/index.njk | 261 +++ tests/assets/tailwindcss/script.js | 5 + tests/assets/tailwindcss/styles.css | 3 + tests/tailwindcss.test.ts | 18 + 10 files changed, 2027 insertions(+) create mode 100644 deps/tailwindcss.ts create mode 100644 plugins/tailwindcss.ts create mode 100644 tests/__snapshots__/tailwindcss.test.ts.snap create mode 100644 tests/assets/tailwindcss/index.njk create mode 100644 tests/assets/tailwindcss/script.js create mode 100644 tests/assets/tailwindcss/styles.css create mode 100644 tests/tailwindcss.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ff207d0..31232341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] ### Added - Archetypes, that allows to create templates used when creating new content [#337]. +- New plugin `tailwindcss` [#344]. - Third argument to `site.data()` to customize the data path [#339]. - Improved the `relations` plugin: - You can configure the key used to save the relations with `relationKey`. - You can configure the key used to save the multiple relations with `pluralRelationKey`. +- New hook `postcss` to modify the `Processor` instance in a low level. ### Changed - `denosass` library has been replaced with [@lumeland/sass](https://www.npmjs.com/package/@lumeland/sass) NPM package @@ -2025,6 +2027,7 @@ The first version. [#339]: https://github.com/lumeland/lume/issues/339 [#341]: https://github.com/lumeland/lume/issues/341 [#342]: https://github.com/lumeland/lume/issues/342 +[#344]: https://github.com/lumeland/lume/issues/344 [#346]: https://github.com/lumeland/lume/issues/346 [Unreleased]: https://github.com/lumeland/lume/compare/v1.14.2...HEAD diff --git a/cli/new.ts b/cli/new.ts index 49b4b0bf..93c4532f 100644 --- a/cli/new.ts +++ b/cli/new.ts @@ -21,6 +21,7 @@ export async function create( name: string, args: string[], ) { + // deno-lint-ignore no-explicit-any let fn: any; const site = await createSite(config); diff --git a/deps/tailwindcss.ts b/deps/tailwindcss.ts new file mode 100644 index 00000000..5ed30616 --- /dev/null +++ b/deps/tailwindcss.ts @@ -0,0 +1,2 @@ +export { default } from "npm:@lumeland/tailwindcss@3.2.5"; +export type { Config } from "npm:@lumeland/tailwindcss@3.2.5"; diff --git a/plugins/postcss.ts b/plugins/postcss.ts index fe4f4e63..8d10561e 100644 --- a/plugins/postcss.ts +++ b/plugins/postcss.ts @@ -63,6 +63,7 @@ export default function (userOptions?: Partial) { site.hooks.addPostcssPlugin = (plugin) => { runner.use(plugin); }; + site.hooks.postcss = (callback) => callback(runner); site.loadAssets(options.extensions); site.process(options.extensions, postCss); diff --git a/plugins/tailwindcss.ts b/plugins/tailwindcss.ts new file mode 100644 index 00000000..ec38b5c7 --- /dev/null +++ b/plugins/tailwindcss.ts @@ -0,0 +1,58 @@ +import tailwind, { Config } from "../deps/tailwindcss.ts"; +import { merge } from "../core/utils.ts"; + +import type { Site } from "../core.ts"; + +export interface Options { + extensions: string[]; + options: Config; +} + +export const defaults: Options = { + extensions: [".html"], + options: {}, +}; + +export default function (userOptions?: Partial) { + const options = merge(defaults, userOptions); + + return (site: Site) => { + // deno-lint-ignore no-explicit-any + let tailwindPlugins: any[]; + + if (site.hooks.postcss) { + throw new Error( + "PostCSS plugin is required to be installed AFTER TailwindCSS plugin", + ); + } + + site.processAll(options.extensions, (pages) => { + // Get the content of all HTML pages + const content = pages.map((page) => ({ raw: page.content as string })); + + // Create Tailwind plugin + // @ts-ignore: This expression is not callable. + const plugin = tailwind({ + ...options.options, + content, + }); + + // Ensure PostCSS plugin is installed + if (!site.hooks.postcss) { + throw new Error( + "PostCSS plugin is required to be installed AFTER TailwindCSS plugin", + ); + } + + // Replace the old Tailwind plugin configuration from PostCSS plugins + // deno-lint-ignore no-explicit-any + site.hooks.postcss((runner: any) => { + tailwindPlugins?.forEach((plugin) => { + runner.plugins.splice(runner.plugins.indexOf(plugin), 1); + }); + tailwindPlugins = runner.normalize([plugin]); + runner.plugins = runner.plugins.concat(tailwindPlugins); + }); + }); + }; +} diff --git a/tests/__snapshots__/tailwindcss.test.ts.snap b/tests/__snapshots__/tailwindcss.test.ts.snap new file mode 100644 index 00000000..e638e509 --- /dev/null +++ b/tests/__snapshots__/tailwindcss.test.ts.snap @@ -0,0 +1,1675 @@ +export const snapshot = {}; + +snapshot[`postcss plugin 1`] = `3`; + +snapshot[`postcss plugin 2`] = ` +{ + formats: [ + { + engines: 1, + ext: ".tmpl.ts", + pageLoader: [AsyncFunction: module], + }, + { + engines: 1, + ext: ".tmpl.js", + pageLoader: [AsyncFunction: module], + }, + { + engines: undefined, + ext: ".tmpl.json", + pageLoader: [AsyncFunction: json], + }, + { + dataLoader: [AsyncFunction: json], + engines: undefined, + ext: ".json", + }, + { + engines: 1, + ext: ".md", + pageLoader: [AsyncFunction: text], + }, + { + asset: true, + componentLoader: [AsyncFunction: module], + dataLoader: [AsyncFunction: module], + engines: 1, + ext: ".js", + pageLoader: [AsyncFunction: text], + }, + { + componentLoader: [AsyncFunction: module], + dataLoader: [AsyncFunction: module], + engines: 1, + ext: ".ts", + }, + { + componentLoader: [AsyncFunction: text], + engines: 1, + ext: ".njk", + includesPath: "_includes", + pageLoader: [AsyncFunction: text], + }, + { + dataLoader: [AsyncFunction: yaml], + engines: undefined, + ext: ".yaml", + pageLoader: [AsyncFunction: yaml], + }, + { + dataLoader: [AsyncFunction: yaml], + engines: undefined, + ext: ".yml", + pageLoader: [AsyncFunction: yaml], + }, + { + asset: true, + engines: undefined, + ext: ".css", + includesPath: "_includes", + pageLoader: [AsyncFunction: text], + }, + ], +} +`; + +snapshot[`postcss plugin 3`] = ` +[ +] +`; + +snapshot[`postcss plugin 4`] = ` +{ + content: \` + + + + + + essential + + + + + +
Free shipping on all orders over £50
+
+
+ essential +
+
+ + +
+ +
+ + Shop + About + Articles +
+
+
+
+
Clean and affordable beauty
+

Beautiful, natural skin

+

A unique layout with a striking design

+ +
+ +
+
+
+
Why Cheslsea?
+

Natural and organic is the future of skincare and life as we know it.

+
+
+ + + +
+
+

Let's face it. Many cosmetics are bad for your skin. We use only natural ingredients and still provide consistently great tanning results.

+ Learn more +
+
+ +
+ Shop now +
+
+
+
+
Limited Run
+

Moisturise

+

Whether in the sun or on the couch, hydration is key to maintaining happy, healthy skin.

+ Shop now +
+
+
+ +
+
+ +
+
+ +
+
+
+

Testimonials

+
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+
+
+
+ +
+
+
+
Only the best
+

Cleansers

+

We're humans too and we understand that skin care and cosmetics should rejuvenate and rehydrate in the short and long run.

+ Shop now +
+
+
+ +
+
+ +
+
+
+
+
+
essential
+
+
+
More Info
+ Shop + About + Info + FAQ +
+
+
Helpful Links
+ Shop + About + Info + FAQ +
+
+
Find out more
+ Shop + About + Info + FAQ +
+
+
+
©2021 design by novolio. images by unsplash
+ + +\`, + data: { + content: \` + + + + + + essential + + + + + +
Free shipping on all orders over £50
+
+
+ essential +
+
+ + +
+ +
+ + Shop + About + Articles +
+
+
+
+
Clean and affordable beauty
+

Beautiful, natural skin

+

A unique layout with a striking design

+ +
+ +
+
+
+
Why Cheslsea?
+

Natural and organic is the future of skincare and life as we know it.

+
+
+ + + +
+
+

Let's face it. Many cosmetics are bad for your skin. We use only natural ingredients and still provide consistently great tanning results.

+ Learn more +
+
+ +
+ Shop now +
+
+
+
+
Limited Run
+

Moisturise

+

Whether in the sun or on the couch, hydration is key to maintaining happy, healthy skin.

+ Shop now +
+
+
+ +
+
+ +
+
+ +
+
+
+

Testimonials

+
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+
+
+
+ +
+
+
+
Only the best
+

Cleansers

+

We're humans too and we understand that skin care and cosmetics should rejuvenate and rehydrate in the short and long run.

+ Shop now +
+
+
+ +
+
+ +
+
+
+
+
+
essential
+
+
+
More Info
+ Shop + About + Info + FAQ +
+
+
Helpful Links
+ Shop + About + Info + FAQ +
+
+
Find out more
+ Shop + About + Info + FAQ +
+
+
+
©2021 design by novolio. images by unsplash
+ + +\`, + date: 1970-01-01T00:00:00.000Z, + mergedKeys: { + tags: "stringArray", + }, + page: undefined, + paginate: [Function: paginate], + search: Search {}, + tags: [ + ], + url: "/", + }, + dest: { + ext: ".html", + path: "/index", + }, + src: { + asset: undefined, + ext: ".njk", + path: "/index", + remote: undefined, + slug: "index", + }, +} +`; + +snapshot[`postcss plugin 5`] = ` +{ + content: "menuButton.addEventListener('click', function () { + const classList = document.getElementById('nav').classList; + classList.toggle('gap-8'); + classList.toggle('gap-16'); +}); +", + data: { + content: "menuButton.addEventListener('click', function () { + const classList = document.getElementById('nav').classList; + classList.toggle('gap-8'); + classList.toggle('gap-16'); +}); +", + date: 1970-01-01T00:00:00.000Z, + mergedKeys: { + tags: "stringArray", + }, + page: undefined, + paginate: [Function: paginate], + search: Search {}, + tags: [ + ], + url: "/script.js", + }, + dest: { + ext: ".js", + path: "/script", + }, + src: { + asset: true, + ext: ".js", + path: "/script", + remote: undefined, + slug: "script", + }, +} +`; + +snapshot[`postcss plugin 6`] = ` +{ + content: "/* +! tailwindcss v3.2.5 | MIT License | https://tailwindcss.com +*//* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; /* 1 */ + border-width: 0; /* 2 */ + border-style: solid; /* 2 */ + border-color: #e5e7eb; /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured \`sans\` font-family by default. +5. Use the user's configured \`sans\` font-feature-settings by default. +*/ + +html { + line-height: 1.5; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -moz-tab-size: 4; /* 3 */ + -o-tab-size: 4; + tab-size: 4; /* 3 */ + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"; /* 4 */ + font-feature-settings: normal; /* 5 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from \`html\` so users can set them as a class directly on the \`html\` element. +*/ + +body { + margin: 0; /* 1 */ + line-height: inherit; /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; /* 1 */ + color: inherit; /* 2 */ + border-top-width: 1px; /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured \`mono\` font family by default. +2. Correct the odd \`em\` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\"Liberation Mono\\", \\"Courier New\\", monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent \`sub\` and \`sup\` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; /* 1 */ + border-color: inherit; /* 2 */ + border-collapse: collapse; /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + font-weight: inherit; /* 1 */ + line-height: inherit; /* 1 */ + color: inherit; /* 1 */ + margin: 0; /* 2 */ + padding: 0; /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; /* 1 */ + background-color: transparent; /* 2 */ + background-image: none; /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional \`:invalid\` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to \`inherit\` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; /* 1 */ + color: #9ca3af; /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role=\\"button\\"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ +:disabled { + cursor: default; +} + +/* +1. Make replaced elements \`display: block\` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add \`vertical-align: middle\` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; /* 1 */ + vertical-align: middle; /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* Make elements with the HTML hidden attribute stay hidden by default */ +[hidden] { + display: none; +} + +*, ::before, ::after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +::backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} +.container { + width: 100%; +} +@media (min-width: 640px) { + + .container { + max-width: 640px; + } +} +@media (min-width: 768px) { + + .container { + max-width: 768px; + } +} +@media (min-width: 1024px) { + + .container { + max-width: 1024px; + } +} +@media (min-width: 1280px) { + + .container { + max-width: 1280px; + } +} +@media (min-width: 1536px) { + + .container { + max-width: 1536px; + } +} +.fixed { + position: fixed; +} +.absolute { + position: absolute; +} +.relative { + position: relative; +} +.inset-0 { + top: 0px; + right: 0px; + bottom: 0px; + left: 0px; +} +.top-0 { + top: 0px; +} +.right-0 { + right: 0px; +} +.left-0 { + left: 0px; +} +.z-10 { + z-index: 10; +} +.z-40 { + z-index: 40; +} +.col-span-1 { + grid-column: span 1 / span 1; +} +.row-span-1 { + grid-row: span 1 / span 1; +} +.mx-auto { + margin-left: auto; + margin-right: auto; +} +.mx-6 { + margin-left: 1.5rem; + margin-right: 1.5rem; +} +.ml-4 { + margin-left: 1rem; +} +.mt-12 { + margin-top: 3rem; +} +.mr-12 { + margin-right: 3rem; +} +.-mt-32 { + margin-top: -8rem; +} +.mt-2 { + margin-top: 0.5rem; +} +.mt-4 { + margin-top: 1rem; +} +.mt-6 { + margin-top: 1.5rem; +} +.mt-3 { + margin-top: 0.75rem; +} +.-mb-10 { + margin-bottom: -2.5rem; +} +.-mt-4 { + margin-top: -1rem; +} +.-mb-8 { + margin-bottom: -2rem; +} +.-mt-10 { + margin-top: -2.5rem; +} +.-ml-8 { + margin-left: -2rem; +} +.mb-6 { + margin-bottom: 1.5rem; +} +.mb-4 { + margin-bottom: 1rem; +} +.block { + display: block; +} +.inline-block { + display: inline-block; +} +.flex { + display: flex; +} +.grid { + display: grid; +} +.hidden { + display: none; +} +.h-8 { + height: 2rem; +} +.h-24 { + height: 6rem; +} +.h-6 { + height: 1.5rem; +} +.h-screen { + height: 100vh; +} +.h-10 { + height: 2.5rem; +} +.h-full { + height: 100%; +} +.h-32 { + height: 8rem; +} +.h-64 { + height: 16rem; +} +.h-28 { + height: 7rem; +} +.w-6 { + width: 1.5rem; +} +.w-screen { + width: 100vw; +} +.w-10 { + width: 2.5rem; +} +.w-full { + width: 100%; +} +.w-32 { + width: 8rem; +} +.w-28 { + width: 7rem; +} +.max-w-sm { + max-width: 24rem; +} +.max-w-md { + max-width: 28rem; +} +.grid-cols-1 { + grid-template-columns: repeat(1, minmax(0, 1fr)); +} +.grid-rows-2 { + grid-template-rows: repeat(2, minmax(0, 1fr)); +} +.flex-col { + flex-direction: column; +} +.flex-wrap { + flex-wrap: wrap; +} +.items-center { + align-items: center; +} +.justify-end { + justify-content: flex-end; +} +.justify-center { + justify-content: center; +} +.justify-between { + justify-content: space-between; +} +.gap-4 { + gap: 1rem; +} +.gap-12 { + gap: 3rem; +} +.gap-6 { + gap: 1.5rem; +} +.gap-8 { + gap: 2rem; +} +.gap-16 { + gap: 4rem; +} +.space-y-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); +} +.bg-gray-100 { + --tw-bg-opacity: 1; + background-color: rgb(243 244 246 / var(--tw-bg-opacity)); +} +.bg-blue-100 { + --tw-bg-opacity: 1; + background-color: rgb(219 234 254 / var(--tw-bg-opacity)); +} +.bg-blue-200 { + --tw-bg-opacity: 1; + background-color: rgb(191 219 254 / var(--tw-bg-opacity)); +} +.bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} +.bg-gray-200 { + --tw-bg-opacity: 1; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)); +} +.object-cover { + -o-object-fit: cover; + object-fit: cover; +} +.p-4 { + padding: 1rem; +} +.p-12 { + padding: 3rem; +} +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} +.px-8 { + padding-left: 2rem; + padding-right: 2rem; +} +.py-4 { + padding-top: 1rem; + padding-bottom: 1rem; +} +.py-24 { + padding-top: 6rem; + padding-bottom: 6rem; +} +.py-12 { + padding-top: 3rem; + padding-bottom: 3rem; +} +.px-12 { + padding-left: 3rem; + padding-right: 3rem; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.font-sans { + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \\"Segoe UI\\", Roboto, \\"Helvetica Neue\\", Arial, \\"Noto Sans\\", sans-serif, \\"Apple Color Emoji\\", \\"Segoe UI Emoji\\", \\"Segoe UI Symbol\\", \\"Noto Color Emoji\\"; +} +.text-xs { + font-size: 0.75rem; + line-height: 1rem; +} +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} +.text-3xl { + font-size: 1.875rem; + line-height: 2.25rem; +} +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} +.text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; +} +.font-normal { + font-weight: 400; +} +.font-semibold { + font-weight: 600; +} +.font-light { + font-weight: 300; +} +.uppercase { + text-transform: uppercase; +} +.lowercase { + text-transform: lowercase; +} +.tracking-wider { + letter-spacing: 0.05em; +} +.tracking-widest { + letter-spacing: 0.1em; +} +.text-gray-700 { + --tw-text-opacity: 1; + color: rgb(55 65 81 / var(--tw-text-opacity)); +} +.text-blue-900 { + --tw-text-opacity: 1; + color: rgb(30 58 138 / var(--tw-text-opacity)); +} +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} +.text-gray-800 { + --tw-text-opacity: 1; + color: rgb(31 41 55 / var(--tw-text-opacity)); +} +.text-gray-900 { + --tw-text-opacity: 1; + color: rgb(17 24 39 / var(--tw-text-opacity)); +} +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} +.text-opacity-40 { + --tw-text-opacity: 0.4; +} +.antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.opacity-95 { + opacity: 0.95; +} +.opacity-75 { + opacity: 0.75; +} +.opacity-5 { + opacity: 0.05; +} +@media (min-width: 768px) { + + .md\\\\:col-span-2 { + grid-column: span 2 / span 2; + } + + .md\\\\:col-span-3 { + grid-column: span 3 / span 3; + } + + .md\\\\:col-span-5 { + grid-column: span 5 / span 5; + } + + .md\\\\:row-span-2 { + grid-row: span 2 / span 2; + } + + .md\\\\:flex { + display: flex; + } + + .md\\\\:hidden { + display: none; + } + + .md\\\\:h-screen { + height: 100vh; + } + + .md\\\\:h-auto { + height: auto; + } + + .md\\\\:grid-cols-2 { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .md\\\\:grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .md\\\\:grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)); + } + + .md\\\\:grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .md\\\\:grid-rows-2 { + grid-template-rows: repeat(2, minmax(0, 1fr)); + } + + .md\\\\:gap-24 { + gap: 6rem; + } + + .md\\\\:text-5xl { + font-size: 3rem; + line-height: 1; + } + + .md\\\\:text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; + } +} +@media (min-width: 1024px) { + + .lg\\\\:col-span-1 { + grid-column: span 1 / span 1; + } + + .lg\\\\:col-span-2 { + grid-column: span 2 / span 2; + } + + .lg\\\\:row-span-2 { + grid-row: span 2 / span 2; + } + + .lg\\\\:mt-0 { + margin-top: 0px; + } + + .lg\\\\:mb-0 { + margin-bottom: 0px; + } + + .lg\\\\:-ml-8 { + margin-left: -2rem; + } + + .lg\\\\:w-auto { + width: auto; + } + + .lg\\\\:flex-1 { + flex: 1 1 0%; + } + + .lg\\\\:rotate-90 { + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + + .lg\\\\:transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } + + .lg\\\\:text-base { + font-size: 1rem; + line-height: 1.5rem; + } +} +", + data: { + content: "@tailwind base; +@tailwind components; +@tailwind utilities; +", + date: 1970-01-01T00:00:00.000Z, + mergedKeys: { + tags: "stringArray", + }, + page: undefined, + paginate: [Function: paginate], + search: Search {}, + tags: [ + ], + url: "/styles.css", + }, + dest: { + ext: ".css", + path: "/styles", + }, + src: { + asset: true, + ext: ".css", + path: "/styles", + remote: undefined, + slug: "styles", + }, +} +`; diff --git a/tests/assets/tailwindcss/index.njk b/tests/assets/tailwindcss/index.njk new file mode 100644 index 00000000..29d1887d --- /dev/null +++ b/tests/assets/tailwindcss/index.njk @@ -0,0 +1,261 @@ + + + + + + + essential + + + + + +
Free shipping on all orders over £50
+
+
+ essential +
+
+ + +
+ +
+ + Shop + About + Articles +
+
+
+
+
Clean and affordable beauty
+

Beautiful, natural skin

+

A unique layout with a striking design

+ +
+ +
+
+
+
Why Cheslsea?
+

Natural and organic is the future of skincare and life as we know it.

+
+
+ + + +
+
+

Let's face it. Many cosmetics are bad for your skin. We use only natural ingredients and still provide consistently great tanning results.

+ Learn more +
+
+ +
+ Shop now +
+
+
+
+
Limited Run
+

Moisturise

+

Whether in the sun or on the couch, hydration is key to maintaining happy, healthy skin.

+ Shop now +
+
+
+ +
+
+ +
+
+ +
+
+
+

Testimonials

+
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+ + + + Elle Spearman +
+ + + + +
+
+
+
+
+ +
+
+
+
Only the best
+

Cleansers

+

We're humans too and we understand that skin care and cosmetics should rejuvenate and rehydrate in the short and long run.

+ Shop now +
+
+
+ +
+
+ +
+
+
+
+
+
essential
+
+
+
More Info
+ Shop + About + Info + FAQ +
+
+
Helpful Links
+ Shop + About + Info + FAQ +
+
+
Find out more
+ Shop + About + Info + FAQ +
+
+
+
©2021 design by novolio. images by unsplash
+ + diff --git a/tests/assets/tailwindcss/script.js b/tests/assets/tailwindcss/script.js new file mode 100644 index 00000000..2d2d6b89 --- /dev/null +++ b/tests/assets/tailwindcss/script.js @@ -0,0 +1,5 @@ +menuButton.addEventListener("click", function () { + const classList = document.getElementById("nav").classList; + classList.toggle("gap-8"); + classList.toggle("gap-16"); +}); diff --git a/tests/assets/tailwindcss/styles.css b/tests/assets/tailwindcss/styles.css new file mode 100644 index 00000000..b5c61c95 --- /dev/null +++ b/tests/assets/tailwindcss/styles.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/tests/tailwindcss.test.ts b/tests/tailwindcss.test.ts new file mode 100644 index 00000000..c88dae7a --- /dev/null +++ b/tests/tailwindcss.test.ts @@ -0,0 +1,18 @@ +import { assertSiteSnapshot, build, getSite } from "./utils.ts"; +import postcss from "../plugins/postcss.ts"; +import tailwindcss from "../plugins/tailwindcss.ts"; + +Deno.test("postcss plugin", async (t) => { + const site = getSite({ + src: "tailwindcss", + }); + + site.use(tailwindcss({ + extensions: [".html", ".js"], + })); + site.use(postcss()); + site.loadAssets([".js"]); + + await build(site); + await assertSiteSnapshot(t, site); +});