mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 20:19:13 +00:00
Compare commits
3 Commits
select-tag
...
preprocss
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e8a5427e0 | ||
|
|
52a4e5ca54 | ||
|
|
d8673a7d71 |
@@ -12,6 +12,7 @@ import { dirname, join, relative } from 'path';
|
||||
import process from 'process';
|
||||
import copy from 'recursive-copy';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { preprocessStylesheet } from './preprocess-css.js';
|
||||
import { cdnDir, distDir, docsDir, rootDir, runScript, siteDir } from './utils.js';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
@@ -36,6 +37,7 @@ async function buildAll() {
|
||||
await generateManifest();
|
||||
await generateReactWrappers();
|
||||
await generateTypes();
|
||||
await preprocessStyles();
|
||||
await generateStyles();
|
||||
|
||||
// copy everything to unbundled before we generate bundles.
|
||||
@@ -105,6 +107,23 @@ function generateReactWrappers() {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate preprocessed CSS
|
||||
*/
|
||||
async function preprocessStyles() {
|
||||
const preprocessedCSSFiles = await globby(join(rootDir, 'src/styles/**/*.css.njk'));
|
||||
|
||||
if (preprocessedCSSFiles.length > 0) {
|
||||
spinner.start('Preprocessing stylesheets');
|
||||
|
||||
for (let filePath of preprocessedCSSFiles) {
|
||||
await preprocessStylesheet(filePath);
|
||||
}
|
||||
|
||||
spinner.succeed();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies theme stylesheets to the dist.
|
||||
*/
|
||||
@@ -371,6 +390,7 @@ if (isDeveloping) {
|
||||
try {
|
||||
const isTestFile = filename.includes('.test.ts');
|
||||
const isCssStylesheet = filename.includes('.css');
|
||||
const isPreprocessedStylesheet = filename.endsWith('.css.njk');
|
||||
const isComponent =
|
||||
filename.includes('components/') && filename.includes('.ts') && !isCssStylesheet && !isTestFile;
|
||||
|
||||
@@ -381,6 +401,10 @@ if (isDeveloping) {
|
||||
|
||||
await regenerateBundle();
|
||||
|
||||
if (isPreprocessedStylesheet || filename.endsWith('src/styles/data.js')) {
|
||||
await preprocessStyles();
|
||||
}
|
||||
|
||||
// Copy stylesheets when CSS files change
|
||||
if (isCssStylesheet) {
|
||||
await generateStyles();
|
||||
|
||||
61
scripts/preprocess-css.js
Normal file
61
scripts/preprocess-css.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import { readFile, writeFile } from 'fs/promises';
|
||||
import nunjucks from 'nunjucks';
|
||||
import * as prettier from 'prettier';
|
||||
import prettierConfig from '../prettier.config.js';
|
||||
import * as globalData from '../src/styles/data.js';
|
||||
|
||||
const prelude = inputFilename => `/* DO NOT EDIT THIS FILE. It is generated from "${inputFilename}" */`;
|
||||
|
||||
let env = nunjucks.configure({ autoescape: false });
|
||||
let filenameVariables = Object.keys(globalData)
|
||||
.filter(key => key.endsWith('s'))
|
||||
.map(key => key.slice(0, -1));
|
||||
let filenameVariablesRegex = RegExp(`\\{\\{\\s*(${filenameVariables.join('|')})\\s*\\}\\}`, 'g');
|
||||
|
||||
export async function preprocessStylesheet(inputPath) {
|
||||
const content = await readFile(inputPath, 'utf-8');
|
||||
let outputPath = inputPath.replace(/\.njk$/, '');
|
||||
let filename = outputPath.split('/').pop();
|
||||
|
||||
if (filenameVariablesRegex.test(filename)) {
|
||||
// NOTE only supports a single variable right now
|
||||
filenameVariablesRegex.lastIndex = 0;
|
||||
let ret = [];
|
||||
|
||||
for (let match of filename.matchAll(filenameVariablesRegex)) {
|
||||
let variable = match[1];
|
||||
let values = globalData[variable + 's'];
|
||||
|
||||
for (let value of values) {
|
||||
let data = { [variable]: value };
|
||||
let css = await renderCSS(content, { data, inputPath, outputPath });
|
||||
|
||||
// Now use Nunjucks *again*, to render the actual filename
|
||||
let localOutputFilePath = env.renderString(outputPath, data);
|
||||
|
||||
ret.push(writeFile(localOutputFilePath, css, 'utf-8'));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(ret);
|
||||
} else {
|
||||
let css = await renderCSS(content, { inputPath, outputPath });
|
||||
return writeFile(outputPath, css, 'utf-8');
|
||||
}
|
||||
|
||||
// TODO add generated files to .gitignore?
|
||||
}
|
||||
|
||||
export async function renderCSS(content, { data, inputPath, outputPath } = {}) {
|
||||
let inputFilename = inputPath.split('/').pop();
|
||||
data = data ? { ...globalData, ...data } : globalData;
|
||||
let css = env.renderString(content, data);
|
||||
|
||||
if (prelude) {
|
||||
css = prelude(inputFilename) + '\n' + css;
|
||||
}
|
||||
|
||||
css = await prettier.format(css, { ...prettierConfig, filepath: outputPath });
|
||||
|
||||
return css;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "base.css.njk" */
|
||||
:where(:root),
|
||||
:host,
|
||||
:where([class^='wa-theme-'], [class*=' wa-theme-']),
|
||||
@@ -8,16 +9,20 @@
|
||||
* --wa-color-brand-if-lt-N ➡️ 100% if key < N, 0% otherwise
|
||||
* --wa-color-brand-if-gte-N ➡️ 100% if key >= N, 0% otherwise
|
||||
*/
|
||||
--wa-color-brand-if-lt-40: calc(clamp(0, 40 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-lt-50: calc(clamp(0, 50 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-lt-60: calc(clamp(0, 60 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-lt-70: calc(clamp(0, 70 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-lt-80: calc(clamp(0, 80 - var(--wa-color-brand-key), 1) * 100%);
|
||||
|
||||
--wa-color-brand-if-lt-40: calc(clamp(0, 40 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-gte-40: calc(100% - var(--wa-color-brand-if-lt-40));
|
||||
|
||||
--wa-color-brand-if-lt-50: calc(clamp(0, 50 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-gte-50: calc(100% - var(--wa-color-brand-if-lt-50));
|
||||
|
||||
--wa-color-brand-if-lt-60: calc(clamp(0, 60 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-gte-60: calc(100% - var(--wa-color-brand-if-lt-60));
|
||||
|
||||
--wa-color-brand-if-lt-70: calc(clamp(0, 70 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-gte-70: calc(100% - var(--wa-color-brand-if-lt-70));
|
||||
|
||||
--wa-color-brand-if-lt-80: calc(clamp(0, 80 - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-gte-80: calc(100% - var(--wa-color-brand-if-lt-80));
|
||||
|
||||
/*
|
||||
@@ -25,6 +30,7 @@
|
||||
* --wa-color-brand-N-max ➡️ var(--color-brand) if key <= N, var(--color-brand-N) otherwise
|
||||
* --wa-color-brand-N-min ➡️ var(--color-brand) if key >= N, var(--color-brand-N) otherwise
|
||||
*/
|
||||
|
||||
--wa-color-brand-40-max: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-brand) var(--wa-color-brand-if-lt-40),
|
||||
|
||||
36
src/styles/brand/base.css.njk
Normal file
36
src/styles/brand/base.css.njk
Normal file
@@ -0,0 +1,36 @@
|
||||
:where(:root),
|
||||
:host,
|
||||
:where([class^='wa-theme-'], [class*=' wa-theme-']),
|
||||
:where([class^='wa-palette-'], [class*=' wa-palette-']),
|
||||
:where([class^='wa-brand-'], [class*=' wa-brand-']) {
|
||||
/**
|
||||
* Conditional tokens for use in color-mix()
|
||||
* --wa-color-brand-if-lt-N ➡️ 100% if key < N, 0% otherwise
|
||||
* --wa-color-brand-if-gte-N ➡️ 100% if key >= N, 0% otherwise
|
||||
*/
|
||||
{% for tint in ['40', '50', '60', '70', '80'] %}
|
||||
--wa-color-brand-if-lt-{{ tint }}: calc(clamp(0, {{ tint }} - var(--wa-color-brand-key), 1) * 100%);
|
||||
--wa-color-brand-if-gte-{{ tint }}: calc(100% - var(--wa-color-brand-if-lt-{{ tint }}));
|
||||
{% endfor %}
|
||||
|
||||
/*
|
||||
* Convenience tokens for common tint cutoffs
|
||||
* --wa-color-brand-N-max ➡️ var(--color-brand) if key <= N, var(--color-brand-N) otherwise
|
||||
* --wa-color-brand-N-min ➡️ var(--color-brand) if key >= N, var(--color-brand-N) otherwise
|
||||
*/
|
||||
{% for tint in ['40', '50', '60', '70'] %}
|
||||
--wa-color-brand-{{ tint }}-max: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-brand) var(--wa-color-brand-if-lt-{{ tint }}),
|
||||
var(--wa-color-brand-{{ tint }})
|
||||
);
|
||||
--wa-color-brand-{{ tint }}-min: color-mix(
|
||||
in oklab,
|
||||
var(--wa-color-brand) var(--wa-color-brand-if-gte-{{ tint }}),
|
||||
var(--wa-color-brand-{{ tint }})
|
||||
);
|
||||
{% endfor %}
|
||||
|
||||
/* Text color: white if key < 60, brand-10 otherwise */
|
||||
--wa-color-brand-on: color-mix(in oklab, var(--wa-color-brand-10) var(--wa-color-brand-if-gte-60), white);
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "{{ hue }}.css.njk" */
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
|
||||
13
src/styles/brand/{{ hue }}.css.njk
Normal file
13
src/styles/brand/{{ hue }}.css.njk
Normal file
@@ -0,0 +1,13 @@
|
||||
@import url('base.css');
|
||||
|
||||
:where(:root),
|
||||
:host,
|
||||
:where([class^='wa-theme-'], [class*=' wa-theme-']),
|
||||
:where([class^='wa-palette-'], [class*=' wa-palette-']),
|
||||
.wa-brand-{{ hue }} {
|
||||
{%- for tint in tints | reverse %}
|
||||
--wa-color-brand-{{ tint }}: var(--wa-color-{{ hue }}-{{ tint }});
|
||||
{%- endfor %}
|
||||
--wa-color-brand: var(--wa-color-{{ hue }});
|
||||
--wa-color-brand-key: var(--wa-color-{{ hue }}-key);
|
||||
}
|
||||
6
src/styles/data.js
Normal file
6
src/styles/data.js
Normal file
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Any data relating to the design system.
|
||||
*/
|
||||
export const hues = ['red', 'yellow', 'green', 'cyan', 'blue', 'indigo', 'purple', 'pink', 'gray'];
|
||||
export const tints = ['05', '10', '20', '30', '40', '50', '60', '70', '80', '90', '95'];
|
||||
export const variants = ['neutral', 'brand', 'success', 'warning', 'danger'];
|
||||
@@ -1,7 +1,4 @@
|
||||
/**
|
||||
* Do not edit this file directly. It is generated via variants.css.js
|
||||
*/
|
||||
|
||||
/* DO NOT EDIT THIS FILE. It is generated from "variants.css.njk" */
|
||||
/**
|
||||
* Register color properties so that the space toggle hack can work.
|
||||
*/
|
||||
@@ -64,7 +61,6 @@
|
||||
* Element defaults.
|
||||
We want these to resolve to inherit when inside a variant, and only be applied when not inside an explicit variant.
|
||||
*/
|
||||
|
||||
:host(wa-button),
|
||||
.wa-button,
|
||||
button,
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* Generate variants.css
|
||||
* To use: node variants.css.js > variants.css
|
||||
*/
|
||||
const variants = ['neutral', 'brand', 'success', 'warning', 'danger'];
|
||||
const roles = ['fill', 'border', 'on'];
|
||||
const noise = ['loud', 'normal', 'quiet'];
|
||||
const defaults = {
|
||||
neutral: [
|
||||
[':host(wa-button)', '.wa-button', 'button', "input[type='button']", "input[type='submit']"],
|
||||
[':host(wa-tag)', '.wa-tag'],
|
||||
],
|
||||
brand: [
|
||||
[':host(wa-callout)', '.wa-callout'],
|
||||
[':host(wa-badge)', '.wa-badge'],
|
||||
],
|
||||
};
|
||||
const types = roles.map(layer => noise.map(priority => layer + '-' + priority)).flat();
|
||||
|
||||
let ret = comment('Do not edit this file directly. It is generated via variants.css.js').trimStart();
|
||||
|
||||
ret += comment('Register color properties so that the space toggle hack can work.');
|
||||
|
||||
for (let type of types) {
|
||||
ret += cssRule(`@property --wa-color-${type}`, [
|
||||
`syntax: '<color>';`,
|
||||
'inherits: true;',
|
||||
'initial-value: transparent;',
|
||||
]);
|
||||
}
|
||||
|
||||
ret += comment(`Element defaults.
|
||||
We want these to resolve to inherit when inside a variant, and only be applied when not inside an explicit variant.`);
|
||||
|
||||
for (let variant in defaults) {
|
||||
let selector = defaults[variant];
|
||||
let declarations = types.map(type => `--wa-color-${type}: var(--wa-no-variant, var(--wa-color-${variant}-${type}));`);
|
||||
|
||||
ret += cssRule(selector, declarations);
|
||||
}
|
||||
|
||||
ret += comment('Variants');
|
||||
|
||||
for (let variant of variants) {
|
||||
let selector = [`.wa-${variant}`, `:host([variant='${variant}'])`];
|
||||
|
||||
if (variant === 'neutral') {
|
||||
selector.unshift(':root');
|
||||
}
|
||||
|
||||
let declarations = types.map(type => `--wa-color-${type}: var(--wa-color-${variant}-${type});`);
|
||||
ret += cssRule(selector, declarations);
|
||||
}
|
||||
|
||||
ret += cssRule([variants.map(variant => `.wa-${variant}`), ':host([variant])'], '--wa-no-variant: /* space toggle */;');
|
||||
|
||||
console.log(ret.trimEnd());
|
||||
|
||||
function cssRule(selector, declarations) {
|
||||
selector = Array.isArray(selector) ? selector.flat().join(',\n') : selector;
|
||||
declarations = Array.isArray(declarations) ? declarations.flat().join('\n') : declarations;
|
||||
declarations = declarations.replace(/^/gm, ' ');
|
||||
return `\n${selector} {\n${declarations}\n}\n`;
|
||||
}
|
||||
|
||||
function comment(text) {
|
||||
return ['\n/**', ` * ${text}`, ' */\n'].join('\n');
|
||||
}
|
||||
54
src/styles/utilities/variants.css.njk
Normal file
54
src/styles/utilities/variants.css.njk
Normal file
@@ -0,0 +1,54 @@
|
||||
{% set suffixes = [
|
||||
'fill-loud', 'fill-normal', 'fill-quiet',
|
||||
'border-loud', 'border-normal', 'border-quiet',
|
||||
'on-loud', 'on-normal', 'on-quiet'
|
||||
] -%}
|
||||
|
||||
/**
|
||||
* Register color properties so that the space toggle hack can work.
|
||||
*/
|
||||
{% for suffix in suffixes %}
|
||||
@property --wa-color-{{ suffix }} {
|
||||
syntax: '<color>';
|
||||
inherits: true;
|
||||
initial-value: transparent;
|
||||
}
|
||||
{% endfor %}
|
||||
|
||||
/**
|
||||
* Element defaults.
|
||||
We want these to resolve to inherit when inside a variant, and only be applied when not inside an explicit variant.
|
||||
*/
|
||||
:host(wa-button), .wa-button, button, input[type='button'], input[type='submit'],
|
||||
:host(wa-tag), .wa-tag {
|
||||
{%- for suffix in suffixes %}
|
||||
--wa-color-{{ suffix }}: var(--wa-no-variant, var(--wa-color-neutral-{{ suffix }}));
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
:host(wa-callout), .wa-callout,
|
||||
:host(wa-badge), .wa-badge {
|
||||
{%- for suffix in suffixes %}
|
||||
--wa-color-{{ suffix }}: var(--wa-no-variant, var(--wa-color-brand-{{ suffix }}));
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
/**
|
||||
* Variants
|
||||
*/
|
||||
{% for variant in variants %}
|
||||
{{ ':root,' if variant === 'neutral' }}
|
||||
.wa-{{ variant }},
|
||||
:host([variant='{{ variant }}']) {
|
||||
{%- for suffix in suffixes %}
|
||||
--wa-color-{{ suffix }}: var(--wa-color-{{ variant }}-{{ suffix }});
|
||||
{%- endfor %}
|
||||
}
|
||||
{%- endfor %}
|
||||
|
||||
{% for variant in variants %}
|
||||
.wa-{{ variant }},
|
||||
{%- endfor %}
|
||||
:host([variant]) {
|
||||
--wa-no-variant: /* space toggle */;
|
||||
}
|
||||
Reference in New Issue
Block a user