Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 9 additions & 27 deletions packages/craftcms-legacy/cp/src/css/_main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1154,33 +1154,15 @@ ul.icons {
gap: var(--s);
}

.gap-0 {
gap: 0;
}

.gap-2xs {
gap: var(--2xs);
}

.gap-xs {
gap: var(--xs);
}

.gap-s {
gap: var(--s);
}

.gap-m {
gap: var(--m);
}

.gap-l {
gap: var(--l);
}

.gap-xl {
gap: var(--xl);
}
/*
The gap utilities that lived here are gone; use the `cp:gap-*` utilities from
`resources/css/utilities.css`, which both CP shells now load. Note the scales
are named differently — legacy `--xs` is `--c-spacing-sm`, not `-xs` — so the
mapping shifts by one step:

gap-2xs -> cp:gap-xs gap-s -> cp:gap-md gap-l -> cp:gap-lg
gap-xs -> cp:gap-sm gap-m -> cp:gap-lg gap-xl -> cp:gap-xl
*/

.spacer {
width: 14px;
Expand Down
2 changes: 1 addition & 1 deletion packages/craftcms-legacy/cp/src/js/UI.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Craft.ui = {
}
let $iconContainer;
if (config.icon || config.label || config.html) {
const $labelContainer = $('<div class="inline-flex gap-xs"/>').appendTo(
const $labelContainer = $('<div class="inline-flex gap-sm"/>').appendTo(
$btn
);
if (config.icon) {
Expand Down
2 changes: 1 addition & 1 deletion packages/craftcms-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"build:storybook": "storybook build",
"build:manifest": "custom-elements-manifest analyze --litelement --outdir dist",
"generate:vue-wrappers": "node ./scripts/generate-vue-wrappers.js",
"generate:colors": "node ./scripts/generate-colors.js && node scripts/generate-color-palette.js"
"generate:colors": "node ./scripts/generate-colors.js && node scripts/generate-color-palette.js && node ./scripts/generate-tailwind.js"
},
"exports": {
"./package.json": "./package.json",
Expand Down
9 changes: 9 additions & 0 deletions packages/craftcms-ui/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {dirname, join, relative, resolve} from 'path';
import {deleteAsync} from 'del';
import createVueWrappers from './generate-vue-wrappers.js';
import createColors from './generate-colors.js';
import createTailwindTheme from './generate-tailwind.js';

const spinner = ora({text: '@craftcms/ui', color: 'red'}).start();
const isDeveloping = process.argv.includes('--develop');
Expand Down Expand Up @@ -250,6 +251,13 @@ async function generateColors() {
return Promise.resolve();
}

async function generateTailwindTheme() {
spinner.start('Generating Tailwind Theme');
await createTailwindTheme();
spinner.succeed();
return Promise.resolve();
}

async function buildAll() {
try {
const steps = [
Expand All @@ -258,6 +266,7 @@ async function buildAll() {
generateStyles,
generateVueWrappers,
generateColors,
generateTailwindTheme,
generateBundle,
pruneOrphanedChunks,
assertDeclarationsResolved,
Expand Down
98 changes: 56 additions & 42 deletions packages/craftcms-ui/scripts/generate-colors.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
import {writeFileSync, readFileSync} from 'fs';
import {writeFileSync} from 'fs';
import {dirname, resolve} from 'path';
import {fileURLToPath} from 'url';
import {transformSync} from 'esbuild';
import {loadColorData} from './utils.js';

const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, '..');
const OUT_FILE = resolve(ROOT, 'src/styles/shared/colorable.css');
const OUT_LIT_FILE = resolve(ROOT, 'src/styles/colorable.styles.ts');
const DATA_FILE = resolve(ROOT, 'src/constants/colors.data.ts');

/*
The canonical color data lives in src/constants/colors.data.ts (shared with
constants/colors.ts). This script can't import TypeScript directly, so we
transpile it with esbuild and import the result.
*/
async function loadColorData() {
const {code} = transformSync(readFileSync(DATA_FILE, 'utf8'), {
loader: 'ts',
format: 'esm',
});
return import(
`data:text/javascript;base64,${Buffer.from(code).toString('base64')}`
);
}

const colorIncrements = {
fill: {
Expand Down Expand Up @@ -127,18 +111,51 @@ function buildSemanticTokens(semanticColors) {
return declarations.join('\n\n');
}

/**
* The generic tokens, remapped to one color group.
*
* Anything carrying a palette selector paints in that group, and so does
* everything under it: components author against the generic tokens, so they
* inherit the group without knowing which one is active.
*/
function buildDeclarations(color, indent = ' ') {
return ['fill', 'border', 'on']
.flatMap((role) =>
['quiet', 'normal', 'loud'].map(
(strength) =>
`${indent}--c-color-${role}-${strength}: var(--c-color-${color}-${role}-${strength});`
)
)
.join('\n');
}

/**
* The selectors that put an element in a color group.
*
* `.cp-palette-*` and `[data-palette]` are the current spellings — the class
* follows the CP's `.cp-*` class convention, and the attribute matches the
* class, so the two read as one idea rather than two. It is a plain stylesheet
* rule, not a Tailwind utility, so it carries no `cp:` prefix and works in the
* legacy shell and inside shadow roots as well.
*
* `.cp-color-*` and `[data-color]` are the Craft 5 spellings. They stay on the
* same rule so existing markup and plugins keep working; new code should reach
* for the palette spellings. Note that `[data-color]` is *not* the same axis as
* `[data-theme='dark']`, which selects the light/dark color scheme — which is
* why this one couldn't simply become `data-theme`.
*/
function paletteSelectors(color) {
return [
`.cp-palette-${color}`,
`[data-palette='${color}']`,
`.cp-color-${color}`,
`[data-color='${color}']`,
];
}

function buildStyleBlock(color) {
return `.cp-color-${color},
[data-color='${color}'] {
--c-color-fill-quiet: var(--c-color-${color}-fill-quiet);
--c-color-border-quiet: var(--c-color-${color}-border-quiet);
--c-color-on-quiet: var(--c-color-${color}-on-quiet);
--c-color-fill-normal: var(--c-color-${color}-fill-normal);
--c-color-border-normal: var(--c-color-${color}-border-normal);
--c-color-on-normal: var(--c-color-${color}-on-normal);
--c-color-fill-loud: var(--c-color-${color}-fill-loud);
--c-color-border-loud: var(--c-color-${color}-border-loud);
--c-color-on-loud: var(--c-color-${color}-on-loud);
return `${paletteSelectors(color).join(',\n')} {
${buildDeclarations(color)}
}`;
}

Expand All @@ -164,23 +181,20 @@ ${[...paletteColors, ...Object.keys(semanticColors)]
*/
function buildLitBlock(selectors, color) {
return ` ${selectors.join(',\n ')} {
--c-color-fill-quiet: var(--c-color-${color}-fill-quiet);
--c-color-border-quiet: var(--c-color-${color}-border-quiet);
--c-color-on-quiet: var(--c-color-${color}-on-quiet);
--c-color-fill-normal: var(--c-color-${color}-fill-normal);
--c-color-border-normal: var(--c-color-${color}-border-normal);
--c-color-on-normal: var(--c-color-${color}-on-normal);
--c-color-fill-loud: var(--c-color-${color}-fill-loud);
--c-color-border-loud: var(--c-color-${color}-border-loud);
--c-color-on-loud: var(--c-color-${color}-on-loud);
${buildDeclarations(color, ' ')}
}`;
}

function generateLitStyles(paletteColors, semanticColors) {
const palette = [...paletteColors, ...Object.keys(semanticColors)]
.map((color) =>
buildLitBlock(
[`:host([data-color='${color}'])`, `[data-color='${color}']`],
[
`:host([data-palette='${color}'])`,
`[data-palette='${color}']`,
`:host([data-color='${color}'])`,
`[data-color='${color}']`,
],
color
)
)
Expand All @@ -204,9 +218,9 @@ import {css} from 'lit';
* chip, a badge, an icon). Most components want {@link variantStyles} instead
* — this is every color in the system, so adopting it isn't free.
*
* Matches a host carrying \`data-color\`, or any element inside the shadow
* root that carries it, mirroring the \`[data-color]\` rules in
* \`shared/colorable.css\`.
* Matches a host carrying \`data-palette\` (or its deprecated \`data-color\`
* spelling), or any element inside the shadow root that carries it, mirroring
* the palette rules in \`shared/colorable.css\`.
*/
export const paletteStyles = css\`
${palette}
Expand Down
Loading