Initial commit

This commit is contained in:
Devin Haska 2025-05-28 16:02:16 -07:00
commit bd6876490b
Signed by: wonderfulfrog
SSH key fingerprint: SHA256:ejOGyH9064rJiikox4ykOHLeuUg1f9l8wmJxs+MzNw0
13 changed files with 1444 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
dist

25
README.md Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

23
package.json Normal file
View 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
View 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
View 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
View 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
View 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;

View 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)
);
}, ``);
};