Initial commit
This commit is contained in:
commit
bd6876490b
13 changed files with 1444 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
dist
|
25
README.md
Normal file
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
# lilypad
|
||||
|
||||
A lightweight utility class generator. A jumping off point for a larger design system!
|
||||
|
||||
## Instructions
|
||||
|
||||
1. Install dependencies (`npm i`).
|
||||
2. Configure any variables desired within `/config`. Adding new properties hasn't been tested yet, so do so with caution!
|
||||
3. The output is stored in `dist/lilypad.css`. Ready for inclusion in your project!
|
||||
|
||||
## So what does it generate?
|
||||
|
||||
A bunch of utility classes to make building UIs easier! The idea is that basic layout can be taken care of using these utility classes, any anything specific beyond layout is taken care of via CSS. Following the [CUBE CSS](https://cube.fyi/) method, all of the generated classes would live in the `utilities` folder, ready for use!
|
||||
|
||||
When numeric values are used, they are based off of the spacing values inside `config/spacing.js`. By default "one space" equals `4px`, So "two spaces" (e.g. `p-2` or "apply two spacing's worth of padding in each direction") would be `4px * 2 = 8px`!
|
||||
|
||||
> **N.B.** The spacing values should probably use `rem` or at least `em` to be compatible with changing font sizes!
|
||||
|
||||
A non-exhaustive list:
|
||||
|
||||
- Helpers for margin and padding, e.g. `m-1`, `px-2`, `ml-3`, etc.
|
||||
- Helpers for using the colours in the design system, e.g. `bg-primary` and `text-secondary`.
|
||||
- CSS variables to utilize the fonts configured in `config/fonts.js`, e.g. `--font-family-display`.
|
||||
|
||||
It's not meant to provide everything possibly required, just a small subset of commonly used utility functions to make building faster and fun!
|
22
config/colors.js
Normal file
22
config/colors.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
export default {
|
||||
light: {
|
||||
primary: "oklch(0.6 0.1025 212.16)",
|
||||
secondary: "oklch(0.61 0.2232 31.48)",
|
||||
background: "oklch(0.98 0 0)",
|
||||
surface: "oklch(0.96 0.0078 207.9)",
|
||||
border: "oklch(0.87 0.045077 207.8465)",
|
||||
text: "oklch(0.15 0 0)",
|
||||
fadeText: "oklch(0.45 0.0214 207.84)",
|
||||
shadow: "oklch(0.39 0.0688 212.35)",
|
||||
},
|
||||
dark: {
|
||||
primary: "oklch(0.57 0.0991 213.4)",
|
||||
secondary: "oklch(0.55 0.1982 31.52)",
|
||||
background: "oklch(0.2 0 0)",
|
||||
surface: "oklch(0.26 0.0106 233.21)",
|
||||
border: "oklch(0.27 0.0238 245.26)",
|
||||
text: "oklch(0.98 0 0)",
|
||||
fadeText: "oklch(0.78 0.018 207.85)",
|
||||
shadow: "oklch(0.39 0.0688 212.35)",
|
||||
},
|
||||
};
|
38
config/fonts.js
Normal file
38
config/fonts.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
export default {
|
||||
display: {
|
||||
family: "Atikinson Hyperlegible Next",
|
||||
format: "woff2",
|
||||
styles: {
|
||||
Regular: {
|
||||
path: "assets/fonts/hyperlegible/AtkinsonHyperlegibleNextVF-Variable.woff2",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "125 950",
|
||||
fontStretch: "75% 125%",
|
||||
},
|
||||
},
|
||||
},
|
||||
body: {
|
||||
family: "Atikinson Hyperlegible Next",
|
||||
format: "woff2",
|
||||
styles: {
|
||||
Regular: {
|
||||
path: "assets/fonts/hyperlegible/AtkinsonHyperlegibleNextVF-Variable.woff2",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "125 950",
|
||||
fontStretch: "75% 125%",
|
||||
},
|
||||
},
|
||||
},
|
||||
monospace: {
|
||||
family: "Atikinson Hyperlegible Mono",
|
||||
format: "woff2",
|
||||
styles: {
|
||||
Regular: {
|
||||
path: "assets/fonts/hyperlegible-mono/AtkinsonHyperlegibleMonoVF-Variable.woff2",
|
||||
fontStyle: "normal",
|
||||
fontWeight: "125 950",
|
||||
fontStretch: "75% 125%",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
11
config/spacing.js
Normal file
11
config/spacing.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
export default {
|
||||
0: 0,
|
||||
1: 4,
|
||||
2: 8,
|
||||
3: 16,
|
||||
4: 24,
|
||||
5: 32,
|
||||
6: 48,
|
||||
7: 64,
|
||||
8: 80,
|
||||
};
|
32
index.js
Normal file
32
index.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Implementation sourced from eleventyone starter kit
|
||||
* https://github.com/philhawksworth/eleventyone
|
||||
* ---
|
||||
* https://github.com/philhawksworth/eleventyone/blob/master/src/site/css/styles.11ty.js
|
||||
*/
|
||||
import fs from "node:fs";
|
||||
import postcss from "postcss";
|
||||
import cssnano from "cssnano";
|
||||
|
||||
import colors from "./src/colors.js";
|
||||
import fontFamily from "./src/font-family.js";
|
||||
import fontVariables from "./src/font-variables.js";
|
||||
import spacing from "./src/spacing.js";
|
||||
|
||||
async function generateCSS() {
|
||||
const css = `${fontFamily}${fontVariables}${colors}${spacing}`;
|
||||
await postcss([cssnano])
|
||||
.process(css, {
|
||||
from: undefined,
|
||||
to: "dist/lilypad.css",
|
||||
})
|
||||
.then((result) => {
|
||||
fs.mkdirSync("dist");
|
||||
fs.writeFileSync("dist/lilypad.css", result.css);
|
||||
if (result.map) {
|
||||
fs.writeFile("dest/app.css.map", result.map.toString(), () => true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
generateCSS();
|
1051
package-lock.json
generated
Normal file
1051
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
23
package.json
Normal file
23
package.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "lilypad",
|
||||
"version": "1.0.0",
|
||||
"description": "Generate some useful CSS helpers from a set of configuration variables.",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node index.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "ssh://git@git.cloud.haska.me:2222/wonderfulfrog/lilypad.git"
|
||||
},
|
||||
"keywords": [
|
||||
"css"
|
||||
],
|
||||
"author": "Devin Haska",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"cssnano": "^7.0.7",
|
||||
"postcss": "^8.5.3"
|
||||
}
|
||||
}
|
34
src/colors.js
Normal file
34
src/colors.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
import colorSchemes from "../config/colors.js";
|
||||
import { helperClassesToCss } from "./utils/helper-classes.js";
|
||||
|
||||
const lightScheme = colorSchemes.light;
|
||||
const darkScheme = colorSchemes.dark;
|
||||
|
||||
const colorToCss = (key, value) => `--color-${key}: ${value};`;
|
||||
|
||||
const colorSchemeToCss = (scheme) =>
|
||||
Object.entries(scheme).reduce(
|
||||
(css, [key, value]) => css + colorToCss(key, value),
|
||||
``,
|
||||
);
|
||||
|
||||
const lightCss = colorSchemeToCss(lightScheme);
|
||||
const darkCss = colorSchemeToCss(darkScheme);
|
||||
|
||||
const colorSchemeToHelperClassesCss = (scheme, helperClasses) => {
|
||||
return Object.entries(scheme).reduce((css, [key]) => {
|
||||
return css + helperClassesToCss(helperClasses, key, `var(--color-${key})`);
|
||||
}, ``);
|
||||
};
|
||||
|
||||
const helperClasses = [
|
||||
["text", ["color"]],
|
||||
["bg", ["background-color"]],
|
||||
];
|
||||
|
||||
const helperClassesCss = colorSchemeToHelperClassesCss(
|
||||
lightScheme,
|
||||
helperClasses,
|
||||
);
|
||||
|
||||
export default `:root{${lightCss}}${helperClassesCss}@media (prefers-color-scheme: dark) {:root{${darkCss}}}`;
|
56
src/font-family.js
Normal file
56
src/font-family.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
import fonts from "../config/fonts.js";
|
||||
|
||||
function fontsToCss(fonts) {
|
||||
return Object.entries(fonts).reduce((css, [, fontProperties]) => {
|
||||
const family = fontProperties.family;
|
||||
const format = fontProperties.format;
|
||||
const styles = fontProperties.styles;
|
||||
|
||||
return (
|
||||
css +
|
||||
Object.entries(styles).reduce((css, [variant, fontFamily]) => {
|
||||
const url = fontFamily.path;
|
||||
const style = fontFamily.fontStyle;
|
||||
const weight = fontFamily.fontWeight;
|
||||
const stretch = fontFamily.fontStretch;
|
||||
const postScriptName = [family, variant].join("-").replaceAll(" ", "");
|
||||
|
||||
return (
|
||||
css +
|
||||
fontFamilyToCss(
|
||||
family,
|
||||
style,
|
||||
weight,
|
||||
stretch,
|
||||
url,
|
||||
family,
|
||||
postScriptName,
|
||||
format,
|
||||
)
|
||||
);
|
||||
}, ``)
|
||||
);
|
||||
}, ``);
|
||||
}
|
||||
|
||||
function fontFamilyToCss(
|
||||
family,
|
||||
style,
|
||||
weight,
|
||||
stretch,
|
||||
url,
|
||||
localName,
|
||||
postScriptName,
|
||||
format,
|
||||
) {
|
||||
return `@font-face {
|
||||
font-family: ${family};
|
||||
font-style: ${style};
|
||||
font-weight: ${weight};
|
||||
font-stretch: ${stretch};
|
||||
font-display: swap;
|
||||
src: local("${localName}"), local("${postScriptName}"), url("${url}") format("${format}")
|
||||
}\n`;
|
||||
}
|
||||
|
||||
export default fontsToCss(fonts);
|
57
src/font-variables.js
Normal file
57
src/font-variables.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Fallbacks from Modern Font Stacks.
|
||||
* https://modernfontstacks.com/
|
||||
*/
|
||||
|
||||
import fonts from "../config/fonts.js";
|
||||
|
||||
const displayFallbacks = [
|
||||
"ui-monospace",
|
||||
"Cascadia Code",
|
||||
"Source Code Pro",
|
||||
"Menlo",
|
||||
"Consolas",
|
||||
"DejaVu Sans Mono",
|
||||
"monospace",
|
||||
];
|
||||
|
||||
const bodyFallbacks = [
|
||||
"ui-monospace",
|
||||
"Cascadia Code",
|
||||
"Source Code Pro",
|
||||
"Menlo",
|
||||
"Consolas",
|
||||
"DejaVu Sans Mono",
|
||||
"monospace",
|
||||
];
|
||||
|
||||
const monoFallbacks = [
|
||||
"ui-monospace",
|
||||
"Cascadia Code",
|
||||
"Source Code Pro",
|
||||
"Menlo",
|
||||
"Consolas",
|
||||
"DejaVu Sans Mono",
|
||||
"monospace",
|
||||
];
|
||||
|
||||
const fallbacks = {
|
||||
display: displayFallbacks,
|
||||
body: bodyFallbacks,
|
||||
monospace: monoFallbacks,
|
||||
};
|
||||
|
||||
const fontsToCss = (fonts) => {
|
||||
return Object.entries(fonts).reduce((css, [fontType, fontProperties]) => {
|
||||
const family = fontProperties.family;
|
||||
|
||||
const fontTypeCss = fontFamilyToCss(fontType, family);
|
||||
|
||||
return css + fontTypeCss;
|
||||
}, ``);
|
||||
};
|
||||
|
||||
const fontFamilyToCss = (type, value) =>
|
||||
`--font-family-${type}: ${value},${fallbacks[type].join(",")};`;
|
||||
|
||||
export default `:root{${fontsToCss(fonts)}}`;
|
50
src/spacing.js
Normal file
50
src/spacing.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
import spacing from "../config/spacing.js";
|
||||
import { helperClassesToCss } from "./utils/helper-classes.js";
|
||||
|
||||
const spacingToCss = (variant, value) => `--spacing-${variant}: ${value}px;`;
|
||||
|
||||
const spacingToHelperClassesCss = (spacingValues, helperClasses) => {
|
||||
return Object.entries(spacingValues).reduce((css, [spacingVariant]) => {
|
||||
const variant = spacingVariant.replace(".", "\\.");
|
||||
return (
|
||||
css +
|
||||
helperClassesToCss(helperClasses, variant, `var(--spacing-${variant})`)
|
||||
);
|
||||
}, ``);
|
||||
};
|
||||
|
||||
const helperClasses = [
|
||||
["m", ["margin"]],
|
||||
["my", ["margin-block-start", "margin-block-end"]],
|
||||
["mx", ["margin-inline-start", "margin-inline-end"]],
|
||||
["ml", ["margin-inline-start"]],
|
||||
["mr", ["margin-inline-start"]],
|
||||
["mt", ["margin-block-start"]],
|
||||
["mb", ["margin-block-end"]],
|
||||
["p", ["padding"]],
|
||||
["py", ["padding-block-start", "padding-block-end"]],
|
||||
["px", ["padding-inline-start", "padding-inline-end"]],
|
||||
["pl", ["padding-inline-start"]],
|
||||
["pr", ["padding-inline-start"]],
|
||||
["pt", ["padding-block-start"]],
|
||||
["pb", ["padding-block-end"]],
|
||||
["w", ["width"]],
|
||||
["h", ["height"]],
|
||||
["size", ["width", "height"]],
|
||||
["radius", ["border-radius"]],
|
||||
["gap", ["gap"]],
|
||||
["row-gap", ["row-gap"]],
|
||||
["column-gap", ["column-gap"]],
|
||||
["flow-space", ["--flow-space"]],
|
||||
];
|
||||
|
||||
const spacingVariablesCss = Object.entries(spacing).reduce(
|
||||
(css, [variant, value]) => css + spacingToCss(variant, value),
|
||||
``,
|
||||
);
|
||||
|
||||
const helperCss = spacingToHelperClassesCss(spacing, helperClasses);
|
||||
|
||||
const css = `:root{${spacingVariablesCss}}${helperCss}`;
|
||||
|
||||
export default css;
|
43
src/utils/helper-classes.js
Normal file
43
src/utils/helper-classes.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* Given an array of CSS properties, output css properties
|
||||
* with each property equal to `value`
|
||||
*/
|
||||
export const cssPropertiesToCss = (cssProperties, value) => {
|
||||
return cssProperties.reduce((css, cssProp) => {
|
||||
return css + `${cssProp}:${value};`;
|
||||
}, ``);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a helperClass (string) and array of cssProperties,
|
||||
* will generate a css class named helperClass that has
|
||||
* all cssProperties mapped to value.
|
||||
*/
|
||||
export const helperClassToCss = (helperClass, cssProperties, value) => {
|
||||
const cssProps = cssPropertiesToCss(cssProperties, value);
|
||||
return `.${helperClass}{${cssProps}}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an array of helperClasses that map to cssProperties,
|
||||
* output a string of CSS that maps the helperClass (with variant modifier)
|
||||
* to the array of css properties with each css property equal to
|
||||
* value
|
||||
*
|
||||
* e.g.
|
||||
* helperClasses = [["text", ["color"]]],
|
||||
* variant = "primary",
|
||||
* value = "#000"
|
||||
*
|
||||
* Will output the following:
|
||||
* .text-primary {
|
||||
* color: #000;
|
||||
* }
|
||||
*/
|
||||
export const helperClassesToCss = (helperClasses, variant, value) => {
|
||||
return helperClasses.reduce((css, [helperClass, cssProperties]) => {
|
||||
return (
|
||||
css + helperClassToCss(`${helperClass}-${variant}`, cssProperties, value)
|
||||
);
|
||||
}, ``);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue