commit a829dc5c2ff088d076947870991b7a9daad146d1
parent b8d09c91799ba4bc6c6476269efdf4221dfc3b25
Author: triesap <triesap@radroots.dev>
Date: Tue, 18 Nov 2025 01:03:21 +0000
themes: add typed theme presets, layout tokens, and cli-driven css generation, refreshing package exports/metadata and pruning legacy theme assets
Diffstat:
35 files changed, 1374 insertions(+), 590 deletions(-)
diff --git a/themes/.gitignore b/themes/.gitignore
@@ -1,47 +1,40 @@
-# dependencies
node_modules
-.pnp
-.pnp.js
+dist
+.turbo
-# testing
-coverage
+# Logs
+logs/
+*.log
-# svelte
-.svelte-kit
+# Env
+.env
+.env.*
+!.env.example
+!.env.test
+.local*
+justfile
-# misc
+# OS
.DS_Store
-*.pem
-
-# debug
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# turbo
-.turbo
-
-
-# Output
-.output
-/build
-dist
+Thumbs.db
-# local env files
-.env*
-!.env.example
+# Secrets
+*.pem
+*.crt
+*.key
+# Testing
+test*.json
-# Vite
-vite.config.js.timestamp-*
-vite.config.ts.timestamp-*
+# Editors
+.vscode/
+.idea/
+*.iml
-# local
-.tmp*
-.backup*
-.dev*
-.vscode
+# Notes
notes*.txt
notes*.md
-git-diff.txt
-justfile
+notes*.json
+tree*.txt
+diff*.txt
+prompt*.txt
diff --git a/themes/README.md b/themes/README.md
@@ -1 +0,0 @@
-# theme
diff --git a/themes/css/layout.css b/themes/css/layout.css
@@ -0,0 +1,145 @@
+@import "tailwindcss";
+
+@theme {
+ --height-bold_button: 4.25rem;
+ --height-entry_line: 48px;
+ --height-ios0: 340px;
+ --height-ios1: 345px;
+ --height-line: 46px;
+ --height-line_button: 3.25rem;
+ --height-lo_bottom_button_ios0: 90px;
+ --height-lo_bottom_button_ios1: 112px;
+ --height-lo_view_main_ios0: 22rem;
+ --height-lo_view_main_ios1: 28rem;
+ --height-nav_page_header_ios0: 62px;
+ --height-nav_page_header_ios1: 62px;
+ --height-nav_page_toolbar_ios0: 72px;
+ --height-nav_page_toolbar_ios1: 120px;
+ --height-nav_tabs_ios0: 80px;
+ --height-nav_tabs_ios1: 120px;
+ --height-touch_guide: 3.4rem;
+ --max-height-bold_button: 4.25rem;
+ --max-height-entry_line: 48px;
+ --max-height-ios0: 340px;
+ --max-height-ios1: 345px;
+ --max-height-line: 46px;
+ --max-height-line_button: 3.25rem;
+ --max-height-lo_bottom_button_ios0: 90px;
+ --max-height-lo_bottom_button_ios1: 112px;
+ --max-height-lo_view_main_ios0: 22rem;
+ --max-height-lo_view_main_ios1: 28rem;
+ --max-height-nav_page_header_ios0: 62px;
+ --max-height-nav_page_header_ios1: 62px;
+ --max-height-nav_page_toolbar_ios0: 72px;
+ --max-height-nav_page_toolbar_ios1: 120px;
+ --max-height-nav_tabs_ios0: 80px;
+ --max-height-nav_tabs_ios1: 120px;
+ --max-height-touch_guide: 3.4rem;
+ --max-width-ios0: 340px;
+ --max-width-ios1: 345px;
+ --max-width-lo_ios0: 340px;
+ --max-width-lo_ios1: 345px;
+ --max-width-lo_line_entry_ios0: 349px;
+ --max-width-lo_line_entry_ios1: 378px;
+ --max-width-lo_textdesc_ios0: 312px;
+ --max-width-lo_textdesc_ios1: 312px;
+ --max-width-trellis_display: 286px;
+ --max-width-trellis_value: 180px;
+ --min-height-bold_button: 4.25rem;
+ --min-height-entry_line: 48px;
+ --min-height-ios0: 340px;
+ --min-height-ios1: 345px;
+ --min-height-line: 46px;
+ --min-height-line_button: 3.25rem;
+ --min-height-lo_bottom_button_ios0: 90px;
+ --min-height-lo_bottom_button_ios1: 112px;
+ --min-height-lo_view_main_ios0: 22rem;
+ --min-height-lo_view_main_ios1: 28rem;
+ --min-height-nav_page_header_ios0: 62px;
+ --min-height-nav_page_header_ios1: 62px;
+ --min-height-nav_page_toolbar_ios0: 72px;
+ --min-height-nav_page_toolbar_ios1: 120px;
+ --min-height-nav_tabs_ios0: 80px;
+ --min-height-nav_tabs_ios1: 120px;
+ --min-height-touch_guide: 3.4rem;
+ --min-width-ios0: 340px;
+ --min-width-ios1: 345px;
+ --min-width-lo_ios0: 340px;
+ --min-width-lo_ios1: 345px;
+ --min-width-lo_line_entry_ios0: 349px;
+ --min-width-lo_line_entry_ios1: 378px;
+ --min-width-lo_textdesc_ios0: 312px;
+ --min-width-lo_textdesc_ios1: 312px;
+ --min-width-trellis_display: 286px;
+ --min-width-trellis_value: 180px;
+ --padding-dim_ios0: 340px;
+ --padding-dim_ios1: 345px;
+ --padding-h_bold_button: 4.25rem;
+ --padding-h_entry_line: 48px;
+ --padding-h_ios0: 340px;
+ --padding-h_ios1: 345px;
+ --padding-h_line: 46px;
+ --padding-h_line_button: 3.25rem;
+ --padding-h_lo_bottom_button_ios0: 90px;
+ --padding-h_lo_bottom_button_ios1: 112px;
+ --padding-h_lo_view_main_ios0: 22rem;
+ --padding-h_lo_view_main_ios1: 28rem;
+ --padding-h_nav_page_header_ios0: 62px;
+ --padding-h_nav_page_header_ios1: 62px;
+ --padding-h_nav_page_toolbar_ios0: 72px;
+ --padding-h_nav_page_toolbar_ios1: 120px;
+ --padding-h_nav_tabs_ios0: 80px;
+ --padding-h_nav_tabs_ios1: 120px;
+ --padding-h_touch_guide: 3.4rem;
+ --padding-w_ios0: 340px;
+ --padding-w_ios1: 345px;
+ --padding-w_lo_ios0: 340px;
+ --padding-w_lo_ios1: 345px;
+ --padding-w_lo_line_entry_ios0: 349px;
+ --padding-w_lo_line_entry_ios1: 378px;
+ --padding-w_lo_textdesc_ios0: 312px;
+ --padding-w_lo_textdesc_ios1: 312px;
+ --padding-w_trellis_display: 286px;
+ --padding-w_trellis_value: 180px;
+ --spacing-dim_ios0: 340px;
+ --spacing-dim_ios1: 345px;
+ --spacing-edge: 2px;
+ --spacing-line: 1px;
+ --translate-h_bold_button: 4.25rem;
+ --translate-h_entry_line: 48px;
+ --translate-h_ios0: 340px;
+ --translate-h_ios1: 345px;
+ --translate-h_line: 46px;
+ --translate-h_line_button: 3.25rem;
+ --translate-h_lo_bottom_button_ios0: 90px;
+ --translate-h_lo_bottom_button_ios1: 112px;
+ --translate-h_lo_view_main_ios0: 22rem;
+ --translate-h_lo_view_main_ios1: 28rem;
+ --translate-h_nav_page_header_ios0: 62px;
+ --translate-h_nav_page_header_ios1: 62px;
+ --translate-h_nav_page_toolbar_ios0: 72px;
+ --translate-h_nav_page_toolbar_ios1: 120px;
+ --translate-h_nav_tabs_ios0: 80px;
+ --translate-h_nav_tabs_ios1: 120px;
+ --translate-h_touch_guide: 3.4rem;
+ --translate-w_ios0: 340px;
+ --translate-w_ios1: 345px;
+ --translate-w_lo_ios0: 340px;
+ --translate-w_lo_ios1: 345px;
+ --translate-w_lo_line_entry_ios0: 349px;
+ --translate-w_lo_line_entry_ios1: 378px;
+ --translate-w_lo_textdesc_ios0: 312px;
+ --translate-w_lo_textdesc_ios1: 312px;
+ --translate-w_trellis_display: 286px;
+ --translate-w_trellis_value: 180px;
+ --width-ios0: 340px;
+ --width-ios1: 345px;
+ --width-lo_ios0: 340px;
+ --width-lo_ios1: 345px;
+ --width-lo_line_entry_ios0: 349px;
+ --width-lo_line_entry_ios1: 378px;
+ --width-lo_textdesc_ios0: 312px;
+ --width-lo_textdesc_ios1: 312px;
+ --width-trellis_display: 286px;
+ --width-trellis_value: 180px;
+}
diff --git a/themes/css/styles.css b/themes/css/styles.css
@@ -0,0 +1,39 @@
+@import "tailwindcss";
+
+@theme {
+ --color-ly0: hsl(var(--ly0) / <alpha-value>);
+ --color-ly0-w: hsl(var(--ly0-w) / <alpha-value>);
+ --color-ly0-a: hsl(var(--ly0-a) / <alpha-value>);
+ --color-ly0-edge: hsl(var(--ly0-edge) / <alpha-value>);
+ --color-ly0-blur: hsl(var(--ly0-blur) / <alpha-value>);
+ --color-ly0-gl: hsl(var(--ly0-gl) / <alpha-value>);
+ --color-ly0-gl-a: hsl(var(--ly0-gl-a) / <alpha-value>);
+ --color-ly0-gl-pl: hsl(var(--ly0-gl-pl) / <alpha-value>);
+ --color-ly0-gl-hl: hsl(var(--ly0-gl-hl) / <alpha-value>);
+ --color-ly0-gl-hl-a: hsl(var(--ly0-gl-hl-a) / <alpha-value>);
+ --color-ly0-gl-shade: hsl(var(--ly0-gl-shade) / <alpha-value>);
+ --color-ly0-gl-label: hsl(var(--ly0-gl-label) / <alpha-value>);
+ --color-ly1: hsl(var(--ly1) / <alpha-value>);
+ --color-ly1-a: hsl(var(--ly1-a) / <alpha-value>);
+ --color-ly1-edge: hsl(var(--ly1-edge) / <alpha-value>);
+ --color-ly1-err: hsl(var(--ly1-err) / <alpha-value>);
+ --color-ly1-focus: hsl(var(--ly1-focus) / <alpha-value>);
+ --color-ly1-gl: hsl(var(--ly1-gl) / <alpha-value>);
+ --color-ly1-gl-a: hsl(var(--ly1-gl-a) / <alpha-value>);
+ --color-ly1-gl-d: hsl(var(--ly1-gl-d) / <alpha-value>);
+ --color-ly1-gl-pl: hsl(var(--ly1-gl-pl) / <alpha-value>);
+ --color-ly1-gl-hl: hsl(var(--ly1-gl-hl) / <alpha-value>);
+ --color-ly1-gl-hl-a: hsl(var(--ly1-gl-hl-a) / <alpha-value>);
+ --color-ly1-gl-shade: hsl(var(--ly1-gl-shade) / <alpha-value>);
+ --color-ly1-gl-label: hsl(var(--ly1-gl-label) / <alpha-value>);
+ --color-ly2: hsl(var(--ly2) / <alpha-value>);
+ --color-ly2-a: hsl(var(--ly2-a) / <alpha-value>);
+ --color-ly2-edge: hsl(var(--ly2-edge) / <alpha-value>);
+ --color-ly2-gl: hsl(var(--ly2-gl) / <alpha-value>);
+ --color-ly2-gl-a: hsl(var(--ly2-gl-a) / <alpha-value>);
+ --color-ly2-gl-d: hsl(var(--ly2-gl-d) / <alpha-value>);
+ --color-ly2-gl-pl: hsl(var(--ly2-gl-pl) / <alpha-value>);
+ --color-ly2-gl-hl: hsl(var(--ly2-gl-hl) / <alpha-value>);
+ --color-ly2-gl-hl-a: hsl(var(--ly2-gl-hl-a) / <alpha-value>);
+ --color-ly2-gl-shade: hsl(var(--ly2-gl-shade) / <alpha-value>);
+}
diff --git a/themes/css/theme_os.css b/themes/css/theme_os.css
@@ -0,0 +1,83 @@
+@plugin "daisyui/theme" {
+ name: "os_dark";
+ default: false;
+ prefersdark: true;
+ color-scheme: dark;
+ --color-ly0: hsl(0, 0%, 7%);
+ --color-ly0-w: hsl(0, 0%, 7%);
+ --color-ly0-a: hsl(240, 2%, 23%);
+ --color-ly0-edge: hsl(274, 4%, 11%);
+ --color-ly0-blur: hsl(0, 0%, 12%);
+ --color-ly0-gl: hsl(230, 3%, 56%);
+ --color-ly0-gl-a: hsl(230, 3%, 51%);
+ --color-ly0-gl-pl: hsl(30, 1%, 99%);
+ --color-ly0-gl-hl: hsl(210, 100%, 52%);
+ --color-ly0-gl-hl-a: hsl(210, 91%, 21%);
+ --color-ly0-gl-shade: hsl(240, 3%, 57%);
+ --color-ly0-gl-label: hsl(240, 3%, 55%);
+ --color-ly1: hsl(240, 4%, 11%);
+ --color-ly1-a: hsl(240, 2%, 23%);
+ --color-ly1-edge: hsl(240, 3%, 19%);
+ --color-ly1-err: hsl(0, 0%, 0%);
+ --color-ly1-focus: hsl(240, 4%, 20%);
+ --color-ly1-gl: hsl(30, 100%, 100%);
+ --color-ly1-gl-a: hsl(30, 1%, 90%);
+ --color-ly1-gl-d: hsl(240, 1%, 82%);
+ --color-ly1-gl-pl: hsl(30, 1%, 99%);
+ --color-ly1-gl-hl: hsl(210, 100%, 52%);
+ --color-ly1-gl-hl-a: hsl(210, 100%, 62%);
+ --color-ly1-gl-shade: hsl(230, 4%, 61%);
+ --color-ly1-gl-label: hsl(30, 1%, 99%);
+ --color-ly2: hsl(240, 2%, 18%);
+ --color-ly2-a: hsl(240, 3%, 15%);
+ --color-ly2-edge: hsl(240, 2%, 23%);
+ --color-ly2-gl: hsl(240, 3%, 73%);
+ --color-ly2-gl-a: hsl(230, 4%, 51%);
+ --color-ly2-gl-d: hsl(240, 3%, 63%);
+ --color-ly2-gl-pl: hsl(240, 2%, 40%);
+ --color-ly2-gl-hl: hsl(210, 100%, 52%);
+ --color-ly2-gl-hl-a: hsl(210, 100%, 42%);
+ --color-ly2-gl-shade: hsl(230, 4%, 61%);
+}
+
+@plugin "daisyui/theme" {
+ name: "os_light";
+ default: false;
+ prefersdark: false;
+ color-scheme: light;
+ --color-ly0: hsl(240, 24%, 96%);
+ --color-ly0-w: hsl(248, 17%, 98%);
+ --color-ly0-a: hsl(240, 6%, 83%);
+ --color-ly0-edge: hsl(0, 0%, 87%);
+ --color-ly0-blur: hsl(179, 7%, 96%);
+ --color-ly0-gl: hsl(240, 2%, 55%);
+ --color-ly0-gl-a: hsl(240, 2%, 60%);
+ --color-ly0-gl-pl: hsl(240, 2%, 78%);
+ --color-ly0-gl-hl: hsl(219, 92%, 59%);
+ --color-ly0-gl-hl-a: hsl(211, 100%, 40%);
+ --color-ly0-gl-shade: hsl(230, 3%, 54%);
+ --color-ly0-gl-label: hsl(240, 2%, 53%);
+ --color-ly1: hsl(0, 0%, 100%);
+ --color-ly1-a: hsl(240, 6%, 83%);
+ --color-ly1-edge: hsl(274, 4%, 90%);
+ --color-ly1-err: hsl(0, 0%, 0%);
+ --color-ly1-focus: hsl(240, 15%, 94%);
+ --color-ly1-gl: hsl(0, 0%, 10%);
+ --color-ly1-gl-a: hsl(0, 0%, 10%);
+ --color-ly1-gl-d: hsl(0, 0%, 20%);
+ --color-ly1-gl-pl: hsl(240, 2%, 78%);
+ --color-ly1-gl-hl: hsl(211, 100%, 50%);
+ --color-ly1-gl-hl-a: hsl(211, 100%, 40%);
+ --color-ly1-gl-shade: hsl(240, 2%, 55%);
+ --color-ly1-gl-label: hsl(240, 2%, 53%);
+ --color-ly2: hsl(240, 5%, 90%);
+ --color-ly2-a: hsl(240, 5%, 95%);
+ --color-ly2-edge: hsl(242, 2%, 88%);
+ --color-ly2-gl: hsl(240, 2%, 55%);
+ --color-ly2-gl-a: hsl(240, 2%, 45%);
+ --color-ly2-gl-d: hsl(240, 2%, 65%);
+ --color-ly2-gl-pl: hsl(240, 2%, 78%);
+ --color-ly2-gl-hl: hsl(211, 100%, 50%);
+ --color-ly2-gl-hl-a: hsl(211, 100%, 40%);
+ --color-ly2-gl-shade: hsl(240, 2%, 55%);
+}
diff --git a/themes/package.json b/themes/package.json
@@ -1,8 +1,8 @@
{
"name": "@radroots/themes",
"version": "0.0.0",
- "private": true,
- "license": "GPLv3",
+ "private": false,
+ "license": "GPL-3.0-or-later",
"type": "module",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
@@ -12,24 +12,37 @@
"types": "./dist/types/index.d.ts",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
- }
+ },
+ "./generator": {
+ "types": "./dist/types/generator/index.d.ts",
+ "import": "./dist/esm/generator/index.js",
+ "require": "./dist/cjs/generator/index.js"
+ },
+ "./css/*": "./css/*"
+ },
+ "bin": {
+ "radroots-generate-themes": "./dist/cjs/bin/generate-theme/main.js"
},
"scripts": {
"build:esm": "tsc -p tsconfig.esm.json",
"build:cjs": "tsc -p tsconfig.cjs.json",
- "build": "npm run clean && npm run build:esm && npm run build:cjs",
- "prebuild": "npm run clean",
- "clean": "rimraf dist",
+ "build": "npm run build:esm && npm run build:cjs",
+ "prebuild": "npm run clean && npx tsx src/bin/build.ts",
+ "clean": "rimraf dist css",
"dev": "npm run watch",
- "watch": "tsc -w",
- "gen": "generate-themes-css"
+ "watch": "tsc -w"
},
"devDependencies": {
- "@radroots/tsconfig": "*",
"@radroots/dev": "*",
+ "@radroots/tsconfig": "*",
+ "tsx": "^4.20.6",
"typescript": "5.8.3"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "files": [
+ "dist",
+ "css"
+ ]
}
\ No newline at end of file
diff --git a/themes/src/bin/build.ts b/themes/src/bin/build.ts
@@ -0,0 +1,72 @@
+#!/usr/bin/env node
+
+import fs from "node:fs";
+import path from "node:path";
+import yargs from "yargs";
+import { hideBin } from "yargs/helpers";
+import { z } from "zod";
+import type { ThemeKey } from "../core/types.js";
+import { build_layout_css_from_presets } from "../generator/layout_css.js";
+import { build_styles_css_from_presets } from "../generator/styles_css.js";
+import { build_themes_css_by_preset } from "../generator/themes_css.js";
+
+const args_schema = z.object({
+ presets: z.array(z.string()).optional()
+});
+
+type BuildArgs = z.infer<typeof args_schema>;
+
+const styles_output_path = path.resolve(process.cwd(), "css/styles.css");
+const layout_output_path = path.resolve(process.cwd(), "css/layout.css");
+
+const write_css = (file_path: string, css: string): void => {
+ const dir = path.dirname(file_path);
+ fs.mkdirSync(dir, { recursive: true });
+ fs.writeFileSync(file_path, css, { encoding: "utf8" });
+};
+
+const parse_cli_args = (): BuildArgs => {
+ const argv = yargs(hideBin(process.argv))
+ .option("presets", {
+ type: "string",
+ array: true,
+ demandOption: false
+ })
+ .strict()
+ .help()
+ .parseSync();
+
+ return args_schema.parse(argv);
+};
+
+const main = (): void => {
+ try {
+ const args = parse_cli_args();
+ const presets = args.presets;
+
+ const styles_css = build_styles_css_from_presets(presets);
+ write_css(styles_output_path, styles_css);
+
+ const layout_css = build_layout_css_from_presets(undefined);
+ write_css(layout_output_path, layout_css);
+
+ const themes_css_by_preset = build_themes_css_by_preset(presets);
+ const theme_keys = Object.keys(themes_css_by_preset) as ThemeKey[];
+
+ for (const theme_key of theme_keys) {
+ const css = themes_css_by_preset[theme_key];
+ const theme_output_path = path.resolve(
+ process.cwd(),
+ `css/theme_${theme_key}.css`
+ );
+ write_css(theme_output_path, css);
+ }
+ } catch (error) {
+ const message =
+ error instanceof Error ? error.message : "unexpected error";
+ console.error(`Error: ${message}`);
+ process.exit(1);
+ }
+};
+
+main();
diff --git a/themes/src/bin/generate-theme/handle-css-layout.ts b/themes/src/bin/generate-theme/handle-css-layout.ts
@@ -0,0 +1,19 @@
+import fs from "node:fs";
+import path from "node:path";
+import { build_layout_css_from_presets } from "../../generator/layout_css.js";
+import type { LayoutArgs } from "./main.js";
+
+export const handle_css_layout = async (args: LayoutArgs): Promise<void> => {
+ const trimmed_dir = args.dir_out.trim();
+ if (trimmed_dir.length === 0) {
+ throw new Error("dir_out cannot be empty");
+ }
+
+ const output_dir = path.resolve(process.cwd(), trimmed_dir);
+ fs.mkdirSync(output_dir, { recursive: true });
+
+ const css = build_layout_css_from_presets(args.presets);
+ const output_path = path.join(output_dir, "layout.css");
+
+ fs.writeFileSync(output_path, css, { encoding: "utf8" });
+};
diff --git a/themes/src/bin/generate-theme/handle-css-styles.ts b/themes/src/bin/generate-theme/handle-css-styles.ts
@@ -0,0 +1,19 @@
+import fs from "node:fs";
+import path from "node:path";
+import { build_styles_css_from_presets } from "../../generator/styles_css.js";
+import type { StylesArgs } from "./main.js";
+
+export const handle_css_styles = async (args: StylesArgs): Promise<void> => {
+ const trimmed_dir = args.dir_out.trim();
+ if (trimmed_dir.length === 0) {
+ throw new Error("dir_out cannot be empty");
+ }
+
+ const output_dir = path.resolve(process.cwd(), trimmed_dir);
+ fs.mkdirSync(output_dir, { recursive: true });
+
+ const css = build_styles_css_from_presets(args.presets);
+ const target = path.join(output_dir, "styles.css");
+
+ fs.writeFileSync(target, css, { encoding: "utf8" });
+};
diff --git a/themes/src/bin/generate-theme/handle-css-themes.ts b/themes/src/bin/generate-theme/handle-css-themes.ts
@@ -0,0 +1,20 @@
+import fs from "node:fs";
+import path from "node:path";
+import { build_themes_css_by_preset } from "../../generator/themes_css.js";
+import type { ThemesArgs } from "./main.js";
+
+export const handle_css_themes = async (args: ThemesArgs): Promise<void> => {
+ const trimmed_dir = args.dir_out.trim();
+ if (trimmed_dir.length === 0) {
+ throw new Error("dir_out cannot be empty");
+ }
+
+ const output_dir = path.resolve(process.cwd(), trimmed_dir);
+ fs.mkdirSync(output_dir, { recursive: true });
+
+ const css_by_preset = build_themes_css_by_preset(args.presets);
+ const css = Object.values(css_by_preset).join("\n");
+ const output_path = path.join(output_dir, "themes.css");
+
+ fs.writeFileSync(output_path, css, { encoding: "utf8" });
+};
diff --git a/themes/src/bin/generate-theme/main.ts b/themes/src/bin/generate-theme/main.ts
@@ -0,0 +1,131 @@
+#!/usr/bin/env node
+
+import yargs, { Argv } from "yargs";
+import { hideBin } from "yargs/helpers";
+import { z } from "zod";
+import { handle_css_layout } from "./handle-css-layout.js";
+import { handle_css_styles } from "./handle-css-styles.js";
+import { handle_css_themes } from "./handle-css-themes.js";
+
+const layout_args_schema = z.object({
+ dir_out: z.string(),
+ presets: z.array(z.string()).optional()
+});
+
+const styles_args_schema = z.object({
+ dir_out: z.string(),
+ presets: z.array(z.string()).optional()
+});
+
+const themes_args_schema = z.object({
+ dir_out: z.string(),
+ presets: z.array(z.string()).optional()
+});
+
+export type LayoutArgs = z.infer<typeof layout_args_schema>;
+export type StylesArgs = z.infer<typeof styles_args_schema>;
+export type ThemesArgs = z.infer<typeof themes_args_schema>;
+
+export type CliArgs =
+ | { command: "layout"; args: LayoutArgs }
+ | { command: "styles"; args: StylesArgs }
+ | { command: "themes"; args: ThemesArgs };
+
+export const parse_args = (): CliArgs => {
+ const argv = yargs(hideBin(process.argv))
+ .command(
+ "layout",
+ "Generate CSS layout",
+ (y): Argv<LayoutArgs> =>
+ y
+ .option("dir_out", {
+ type: "string",
+ demandOption: false,
+ default: "styles"
+ })
+ .option("presets", {
+ type: "string",
+ array: true,
+ demandOption: false
+ })
+ )
+ .command(
+ "styles",
+ "Generate CSS styles",
+ (y): Argv<StylesArgs> =>
+ y
+ .option("dir_out", {
+ type: "string",
+ demandOption: false,
+ default: "styles"
+ })
+ .option("presets", {
+ type: "string",
+ array: true,
+ demandOption: false
+ })
+ )
+ .command(
+ "themes",
+ "Generate CSS themes",
+ (y): Argv<ThemesArgs> =>
+ y
+ .option("dir_out", {
+ type: "string",
+ demandOption: false,
+ default: "styles"
+ })
+ .option("presets", {
+ type: "string",
+ array: true,
+ demandOption: false
+ })
+ )
+ .strict()
+ .help()
+ .parseSync();
+
+ const command = String(argv._[0]);
+
+ switch (command) {
+ case "layout":
+ return {
+ command,
+ args: layout_args_schema.parse(argv)
+ };
+ case "styles":
+ return {
+ command,
+ args: styles_args_schema.parse(argv)
+ };
+ case "themes":
+ return {
+ command,
+ args: themes_args_schema.parse(argv)
+ };
+ default:
+ throw new Error(`Unknown command: ${command}`);
+ }
+};
+
+export const main = (): void => {
+ try {
+ const cli = parse_args();
+
+ switch (cli.command) {
+ case "layout":
+ return void handle_css_layout(cli.args);
+ case "styles":
+ return void handle_css_styles(cli.args);
+ case "themes":
+ return void handle_css_themes(cli.args);
+ }
+ } catch (error) {
+ const message =
+ error instanceof Error ? error.message : "Unexpected error";
+ console.error(`Error: ${message}`);
+ process.exit(1);
+ }
+};
+
+main();
diff --git a/themes/src/core/types.ts b/themes/src/core/types.ts
@@ -0,0 +1,17 @@
+export type ThemeLayer = 0 | 1 | 2;
+
+export type ThemeKey = "os";
+
+export type ThemeMode = "light" | "dark";
+
+export type ThemeId<TThemeKey extends ThemeKey = ThemeKey> = `${TThemeKey}_${ThemeMode}`;
+
+export type LightThemeId<TThemeKey extends ThemeKey = ThemeKey> = `${TThemeKey}_light`;
+
+export type DarkThemeId<TThemeKey extends ThemeKey = ThemeKey> = `${TThemeKey}_dark`;
+
+export type ThemeKeys<T extends ThemeKey> = ThemeId<T>;
+
+export type ThemeKeysLight<T extends ThemeKey> = LightThemeId<T>;
+
+export type ThemeKeysDark<T extends ThemeKey> = DarkThemeId<T>;
diff --git a/themes/src/core/utils.ts b/themes/src/core/utils.ts
@@ -0,0 +1,13 @@
+import type { ThemeKey, ThemeMode } from "./types.js";
+
+export const parse_theme_mode = (value?: string | null): ThemeMode => {
+ if (value === "dark") return "dark";
+ return "light";
+};
+
+export const parse_theme_key = (value?: string | null): ThemeKey => {
+ switch (value) {
+ case "os": return value;
+ default: return "os";
+ }
+};
diff --git a/themes/src/data/os.hsl.dark.json b/themes/src/data/os.hsl.dark.json
@@ -1,55 +0,0 @@
-{
- "layer_0": {
- "surface": {
- "_": [ 0, 0, 7 ],
- "_w": [ 0, 0, 7 ],
- "_a": [ 240, 2, 23 ],
- "edge": [ 274, 4, 11 ],
- "blur": [ 0, 0, 12 ]
- },
- "glyphs": {
- "_": [ 230, 3, 56 ],
- "_a": [ 230, 3, 51 ],
- "_pl": [ 30, 1, 99 ],
- "hl": [ 210, 100, 52 ],
- "hl_a": [ 210, 91, 21 ],
- "shade": [ 240, 3, 57 ],
- "label": [ 240, 3, 55 ]
- }
- },
- "layer_1": {
- "surface": {
- "_": [ 240, 4, 11 ],
- "_a": [ 240, 2, 23 ],
- "edge": [ 240, 3, 19 ],
- "err": [ 0, 0, 0 ],
- "focus": [ 240, 4, 20 ]
- },
- "glyphs": {
- "_": [ 30, 100, 100 ],
- "_a": [ 30, 1, 90 ],
- "_d": [ 240, 1, 82 ],
- "_pl": [ 30, 1, 99 ],
- "hl": [ 210, 100, 52 ],
- "hl_a": [ 210, 100, 62 ],
- "shade": [ 230, 4, 61 ],
- "label": [ 30, 1, 99 ]
- }
- },
- "layer_2": {
- "surface": {
- "_": [ 240, 2, 18 ],
- "_a": [ 240, 3, 15 ],
- "edge": [ 240, 2, 23 ]
- },
- "glyphs": {
- "_": [ 240, 3, 73 ],
- "_a": [ 230, 4, 51 ],
- "_d": [ 240, 3, 63 ],
- "_pl": [ 240, 2, 40 ],
- "hl": [ 210, 100, 52 ],
- "hl_a": [ 210, 100, 42 ],
- "shade": [ 230, 4, 61 ]
- }
- }
-}
diff --git a/themes/src/data/os.hsl.light.json b/themes/src/data/os.hsl.light.json
@@ -1,55 +0,0 @@
-{
- "layer_0": {
- "surface": {
- "_": [ 240, 24, 96 ],
- "_w": [ 248, 248, 250 ],
- "_a": [ 240, 6, 83 ],
- "edge": [ 0, 0, 87 ],
- "blur": [ 179, 7, 96 ]
- },
- "glyphs": {
- "_": [ 240, 2, 55 ],
- "_a": [ 240, 2, 60 ],
- "_pl": [ 240, 2, 78 ],
- "hl": [ 219, 92, 59 ],
- "hl_a": [ 211, 100, 40 ],
- "shade": [ 230, 3, 54 ],
- "label": [ 240, 2, 53 ]
- }
- },
- "layer_1": {
- "surface": {
- "_": [ 0, 0, 100 ],
- "_a": [ 240, 6, 83 ],
- "edge": [ 274, 4, 90 ],
- "err": [ 0, 0, 0 ],
- "focus": [ 240, 15, 94 ]
- },
- "glyphs": {
- "_": [ 0, 0, 10 ],
- "_a": [ 0, 0, 10 ],
- "_d": [ 0, 0, 20 ],
- "_pl": [ 240, 2, 78 ],
- "hl": [ 211, 100, 50 ],
- "hl_a": [ 211, 100, 40 ],
- "shade": [ 240, 2, 55 ],
- "label": [ 240, 2, 53 ]
- }
- },
- "layer_2": {
- "surface": {
- "_": [ 240, 5, 90 ],
- "_a": [ 240, 5, 95 ],
- "edge": [ 242, 2, 88 ]
- },
- "glyphs": {
- "_": [ 240, 2, 55 ],
- "_a": [ 240, 2, 45 ],
- "_d": [ 240, 2, 65 ],
- "_pl": [ 240, 2, 78 ],
- "hl": [ 211, 100, 50 ],
- "hl_a": [ 211, 100, 40 ],
- "shade": [ 240, 2, 55 ]
- }
- }
-}
diff --git a/themes/src/data/os.rgb.dark.json b/themes/src/data/os.rgb.dark.json
@@ -1,54 +0,0 @@
-{
- "layer_0": {
- "surface": {
- "_": [ 0, 0, 0 ],
- "_a": [ 31, 31, 31 ],
- "edge": [ 125, 125, 129 ]
- },
- "glyphs": {
- "_": [ 255, 255, 255 ],
- "_a": [ 255, 255, 255 ],
- "_d": [ 125, 125, 129 ],
- "_pl": [ 125, 125, 129 ],
- "hl": [ 54, 117, 220 ],
- "hl_a": [ 85, 151, 242 ],
- "label": [ 125, 125, 129 ]
- }
- },
- "layer_1": {
- "surface": {
- "_": [ 28, 28, 31 ],
- "_a": [ 58, 58, 60 ],
- "edge": [ 38, 38, 40 ],
- "icon": [ 152, 152, 158 ],
- "overlay": [ 142, 142, 147 ]
- },
- "glyphs": {
- "_": [ 240, 240, 240 ],
- "_a": [ 240, 240, 240 ],
- "_d": [ 88, 88, 93 ],
- "_pl": [ 128, 128, 133 ],
- "hl": [ 59, 130, 247 ],
- "hl_a": [ 21, 52, 98 ],
- "label": [ 125, 125, 125 ],
- "edge": [ 85, 85, 85 ]
- }
- },
- "layer_2": {
- "surface": {
- "_": [ 44, 44, 46 ],
- "_a": [ 58, 58, 60 ],
- "edge": [ 112, 112, 115 ],
- "icon": [ 159, 159, 164 ]
- },
- "glyphs": {
- "_": [ 241, 241, 241 ],
- "_a": [ 241, 241, 241 ],
- "_d": [ 130, 130, 134 ],
- "_pl": [ 128, 128, 133 ],
- "hl": [ 59, 130, 247 ],
- "hl_a": [ 21, 52, 98 ],
- "label": [ 130, 130, 134 ]
- }
- }
-}
diff --git a/themes/src/data/os.rgb.light.json b/themes/src/data/os.rgb.light.json
@@ -1,54 +0,0 @@
-{
- "layer_0": {
- "surface": {
- "_": [ 242, 242, 247 ],
- "_a": [ 242, 242, 247 ],
- "edge": [ 159, 159, 165 ]
- },
- "glyphs": {
- "_": [ 0, 0, 0 ],
- "_a": [ 0, 0, 0 ],
- "_d": [ 145, 145, 149 ],
- "_pl": [ 145, 145, 149 ],
- "hl": [ 52, 120, 246 ],
- "hl_a": [ 108, 165, 249 ],
- "label": [ 177, 177, 182 ]
- }
- },
- "layer_1": {
- "surface": {
- "_": [ 255, 255, 255 ],
- "_a": [ 209, 209, 214 ],
- "edge": [ 197, 197, 199 ],
- "icon": [ 127, 127, 132 ],
- "overlay": [ 142, 142, 147 ]
- },
- "glyphs": {
- "_": [ 14, 14, 14 ],
- "_a": [ 29, 29, 29 ],
- "_d": [ 29, 29, 29 ],
- "_pl": [ 29, 29, 29 ],
- "hl": [ 52, 120, 246 ],
- "hl_a": [ 199, 217, 246 ],
- "label": [ 164, 164, 164 ],
- "edge": [ 191, 191, 191 ]
- }
- },
- "layer_2": {
- "surface": {
- "_": [ 242, 242, 247 ],
- "_a": [ 58, 58, 60 ],
- "edge": [ 112, 112, 115 ],
- "icon": [ 159, 159, 164 ]
- },
- "glyphs": {
- "_": [ 14, 14, 14 ],
- "_a": [ 29, 29, 29 ],
- "_d": [ 29, 29, 29 ],
- "_pl": [ 29, 29, 29 ],
- "hl": [ 52, 120, 246 ],
- "hl_a": [ 199, 217, 246 ],
- "label": [ 137, 137, 142 ]
- }
- }
-}
diff --git a/themes/src/generator/layout_css.ts b/themes/src/generator/layout_css.ts
@@ -0,0 +1,37 @@
+import type { ThemeVariable } from "../layout/types.js";
+import {
+ collect_layout_variables,
+ select_theme_layout_keys
+} from "./theme_utils.js";
+
+export const build_layout_css = (variables: ThemeVariable[]): string => {
+ const sorted = [...variables].sort((a, b) => {
+ if (a.namespace !== b.namespace) {
+ return a.namespace.localeCompare(b.namespace);
+ }
+ return a.name.localeCompare(b.name);
+ });
+
+ const lines: string[] = [];
+ lines.push('@import "tailwindcss";');
+ lines.push("");
+ lines.push("@theme {");
+
+ for (const variable of sorted) {
+ const css_var_name = `--${variable.namespace}-${variable.name}`;
+ lines.push(` ${css_var_name}: ${variable.value};`);
+ }
+
+ lines.push("}");
+ lines.push("");
+
+ return lines.join("\n");
+};
+
+export const build_layout_css_from_presets = (
+ presets: string[] | undefined
+): string => {
+ const selected_layout_keys = select_theme_layout_keys(presets);
+ const layout_variables = collect_layout_variables(selected_layout_keys);
+ return build_layout_css(layout_variables);
+};
diff --git a/themes/src/generator/styles_css.ts b/themes/src/generator/styles_css.ts
@@ -0,0 +1,74 @@
+import { theme_presets } from "../presets/index.js";
+import {
+ collect_theme_color_entries,
+ select_theme_presets_keys,
+ theme_modes,
+ to_css_name_suffix
+} from "./theme_utils.js";
+
+export interface StyleVariable {
+ color_var_name: string;
+ token_var_name: string;
+}
+
+export const build_styles_css = (variables: StyleVariable[]): string => {
+ const lines: string[] = [];
+ lines.push('@import "tailwindcss";');
+ lines.push("");
+ lines.push("@theme {");
+
+ for (const v of variables) {
+ lines.push(
+ ` ${v.color_var_name}: hsl(var(${v.token_var_name}) / <alpha-value>);`
+ );
+ }
+
+ lines.push("}");
+ lines.push("");
+
+ return lines.join("\n");
+};
+
+export const build_styles_css_from_presets = (
+ presets: string[] | undefined
+): string => {
+ const selected = select_theme_presets_keys(presets);
+ const map = new Map<string, string>();
+
+ for (const key of selected) {
+ const preset = theme_presets[key];
+
+ for (const mode of theme_modes) {
+ const theme = preset[mode];
+ const entries = collect_theme_color_entries(theme);
+
+ for (const entry of entries) {
+ const suffix = to_css_name_suffix(entry.token_key);
+ const layer_prefix = `--${entry.layer_key}`;
+
+ const color =
+ entry.category === "surfaces"
+ ? `--color-${entry.layer_key}${suffix}`
+ : `--color-${entry.layer_key}-gl${suffix}`;
+
+ const token =
+ entry.category === "surfaces"
+ ? `${layer_prefix}${suffix}`
+ : `${layer_prefix}-gl${suffix}`;
+
+ if (!map.has(color)) {
+ map.set(color, token);
+ }
+ }
+ }
+ }
+
+ const list: StyleVariable[] = [...map.entries()].map(
+ ([color_var_name, token_var_name]) => ({
+ color_var_name,
+ token_var_name
+ })
+ );
+
+ return build_styles_css(list);
+};
diff --git a/themes/src/generator/theme_utils.ts b/themes/src/generator/theme_utils.ts
@@ -0,0 +1,138 @@
+import type { ThemeKey, ThemeMode } from "../core/types.js";
+import { parse_theme_key } from "../core/utils.js";
+import { theme_layouts } from "../layout/index.js";
+import type { ThemeLayoutKey, ThemeVariable } from "../layout/types.js";
+import { theme_presets } from "../presets/index.js";
+import type { HslTuple, OsThemePreset } from "../presets/types.js";
+
+export const theme_modes: ThemeMode[] = ["dark", "light"];
+
+const theme_layer_order: Array<keyof OsThemePreset> = ["ly0", "ly1", "ly2"];
+
+export interface ThemeColorEntry {
+ layer_key: keyof OsThemePreset;
+ category: "surfaces" | "glyphs";
+ token_key: string;
+}
+
+export const tabs = (n: number): string => " ".repeat(n);
+
+export const format_hsl = (tuple: HslTuple): string => {
+ const [h, s, l] = tuple;
+ return `hsl(${h}, ${s}%, ${l}%)`;
+};
+
+export const to_css_name_suffix = (key: string): string => {
+ const trimmed_key = key.replace(/^_+/, "");
+ if (trimmed_key.length === 0) {
+ return "";
+ }
+ return `-${trimmed_key.replace(/_/g, "-")}`;
+};
+
+export const collect_theme_color_entries = (
+ theme: OsThemePreset
+): ThemeColorEntry[] => {
+ const entries: ThemeColorEntry[] = [];
+
+ for (const layer_key of theme_layer_order) {
+ const layer = theme[layer_key];
+
+ const surface_keys = Object.keys(
+ layer.surfaces
+ ) as Array<keyof typeof layer.surfaces>;
+ for (const surface_key of surface_keys) {
+ entries.push({
+ layer_key,
+ category: "surfaces",
+ token_key: String(surface_key)
+ });
+ }
+
+ const glyph_keys = Object.keys(
+ layer.glyphs
+ ) as Array<keyof typeof layer.glyphs>;
+ for (const glyph_key of glyph_keys) {
+ entries.push({
+ layer_key,
+ category: "glyphs",
+ token_key: String(glyph_key)
+ });
+ }
+ }
+
+ return entries;
+};
+
+export const select_theme_presets_keys = (
+ presets: string[] | undefined
+): ThemeKey[] => {
+ const all_keys = Object.keys(theme_presets);
+ if (!presets || presets.length === 0) {
+ return all_keys.map(parse_theme_key);
+ }
+
+ const trimmed_presets = presets
+ .map(preset => preset.trim())
+ .filter(preset => preset.length > 0);
+
+ if (trimmed_presets.length === 0) {
+ return all_keys.map(parse_theme_key);
+ }
+
+ const unknown_presets = trimmed_presets.filter(
+ preset => !all_keys.includes(preset)
+ );
+ if (unknown_presets.length > 0) {
+ throw new Error(
+ `Unknown theme preset(s): ${unknown_presets.join(", ")}`
+ );
+ }
+
+ return all_keys
+ .filter(key => trimmed_presets.includes(key))
+ .map(parse_theme_key);
+};
+
+export const select_theme_layout_keys = (
+ presets: string[] | undefined
+): ThemeLayoutKey[] => {
+ const all_keys = Object.keys(theme_layouts) as ThemeLayoutKey[];
+
+ if (!presets || presets.length === 0) {
+ return all_keys;
+ }
+
+ const trimmed_presets = presets
+ .map(preset => preset.trim())
+ .filter(preset => preset.length > 0);
+
+ if (trimmed_presets.length === 0) {
+ return all_keys;
+ }
+
+ const unknown_presets = trimmed_presets.filter(
+ preset => !all_keys.includes(preset as ThemeLayoutKey)
+ );
+
+ if (unknown_presets.length > 0) {
+ throw new Error(
+ `Unknown layout preset(s): ${unknown_presets.join(", ")}`
+ );
+ }
+
+ return all_keys.filter(key => trimmed_presets.includes(key));
+};
+
+export const collect_layout_variables = (
+ keys: ThemeLayoutKey[]
+): ThemeVariable[] => {
+ const variables: ThemeVariable[] = [];
+
+ for (const key of keys) {
+ const layout = theme_layouts[key];
+ variables.push(...layout.variables);
+ }
+
+ return variables;
+};
diff --git a/themes/src/generator/themes_css.ts b/themes/src/generator/themes_css.ts
@@ -0,0 +1,87 @@
+import type { ThemeId, ThemeKey, ThemeMode } from "../core/types.js";
+import { theme_presets } from "../presets/index.js";
+import type { OsThemePreset, ThemePreset } from "../presets/types.js";
+import {
+ collect_theme_color_entries,
+ format_hsl,
+ select_theme_presets_keys,
+ theme_modes,
+ to_css_name_suffix
+} from "./theme_utils.js";
+
+export interface PluginOptions {
+ id: ThemeId;
+ prefers_dark: boolean;
+ color_scheme: ThemeMode;
+ theme: OsThemePreset;
+}
+
+export const build_theme_css = (options: PluginOptions): string => {
+ const lines: string[] = [];
+ lines.push('@plugin "daisyui/theme" {');
+ lines.push(` name: "${options.id}";`);
+ lines.push(" default: false;");
+ lines.push(` prefersdark: ${options.prefers_dark ? "true" : "false"};`);
+ lines.push(` color-scheme: ${options.color_scheme};`);
+
+ const entries = collect_theme_color_entries(options.theme);
+
+ for (const entry of entries) {
+ const layer = options.theme[entry.layer_key];
+ const layer_prefix = `--color-${entry.layer_key}`;
+ const suffix = to_css_name_suffix(entry.token_key);
+
+ if (entry.category === "surfaces") {
+ const surfaces = layer.surfaces;
+ const color = surfaces[entry.token_key as keyof typeof surfaces];
+ const css_var_name = `${layer_prefix}${suffix}`;
+ lines.push(` ${css_var_name}: ${format_hsl(color)};`);
+ } else {
+ const glyphs = layer.glyphs;
+ const color = glyphs[entry.token_key as keyof typeof glyphs];
+ const css_var_name = `${layer_prefix}-gl${suffix}`;
+ lines.push(` ${css_var_name}: ${format_hsl(color)};`);
+ }
+ }
+
+ lines.push("}");
+ lines.push("");
+
+ return lines.join("\n");
+};
+
+const build_theme_blocks = (
+ theme_key: ThemeKey,
+ preset: ThemePreset
+): string[] => {
+ const blocks: string[] = [];
+
+ for (const mode of theme_modes) {
+ const theme = preset[mode];
+ const id: ThemeId = `${theme_key}_${mode}`;
+ const block = build_theme_css({
+ id,
+ prefers_dark: mode === "dark",
+ color_scheme: mode,
+ theme
+ });
+ blocks.push(block);
+ }
+
+ return blocks;
+};
+
+export const build_themes_css_by_preset = (
+ presets: string[] | undefined
+): Record<ThemeKey, string> => {
+ const selected_theme_keys = select_theme_presets_keys(presets);
+ const css_by_preset = {} as Record<ThemeKey, string>;
+
+ for (const theme_key of selected_theme_keys) {
+ const preset = theme_presets[theme_key];
+ const blocks = build_theme_blocks(theme_key, preset);
+ css_by_preset[theme_key] = blocks.join("\n");
+ }
+
+ return css_by_preset;
+};
diff --git a/themes/src/index.ts b/themes/src/index.ts
@@ -1 +1,3 @@
-export * from "./types/lib.js"
+export * from "./core/types.js"
+export * from "./core/utils.js"
+
diff --git a/themes/src/layout/app/index.ts b/themes/src/layout/app/index.ts
@@ -0,0 +1,109 @@
+import { build_theme_layout_variables, with_prefix } from "../tokens.js";
+import type {
+ IosHeightTokenKey,
+ IosWidthTokenKey,
+ TailwindThemeConfig,
+ ThemeLayoutEntry,
+ ThemeLayoutParam
+} from "../types.js";
+
+const ios_height_tokens: Record<IosHeightTokenKey, string> = {
+ nav_tabs_ios0: "80px",
+ nav_tabs_ios1: "120px",
+ nav_page_toolbar_ios0: "72px",
+ nav_page_toolbar_ios1: "120px",
+ nav_page_header_ios0: "62px",
+ nav_page_header_ios1: "62px",
+ lo_bottom_button_ios0: "90px",
+ lo_bottom_button_ios1: "112px",
+ lo_view_main_ios0: "22rem",
+ lo_view_main_ios1: "28rem"
+};
+
+const ios_width_tokens: Record<IosWidthTokenKey, string> = {
+ lo_ios0: "340px",
+ lo_ios1: "345px",
+ lo_textdesc_ios0: "312px",
+ lo_textdesc_ios1: "312px",
+ lo_line_entry_ios0: "349px",
+ lo_line_entry_ios1: "378px"
+};
+
+const dimension_tokens: ThemeLayoutEntry = {
+ ios0: "340px",
+ ios1: "345px"
+};
+
+const base_spacing_tokens: ThemeLayoutEntry = {
+ line: "1px",
+ edge: "2px"
+};
+
+const height_scale: ThemeLayoutEntry = {
+ ...ios_height_tokens,
+ ...dimension_tokens,
+ line: "46px",
+ line_button: "3.25rem",
+ touch_guide: "3.4rem",
+ entry_line: "48px",
+ bold_button: "4.25rem"
+};
+
+const width_scale: ThemeLayoutEntry = {
+ ...ios_width_tokens,
+ ...dimension_tokens,
+ trellis_value: "180px",
+ trellis_display: "286px"
+};
+
+const dimension_scale: ThemeLayoutEntry = {
+ ...dimension_tokens
+};
+
+const min_height_scale: ThemeLayoutEntry = {
+ ...height_scale
+};
+
+const max_height_scale: ThemeLayoutEntry = {
+ ...height_scale
+};
+
+const min_width_scale: ThemeLayoutEntry = {
+ ...width_scale
+};
+
+const max_width_scale: ThemeLayoutEntry = {
+ ...width_scale
+};
+
+const padding_scale: ThemeLayoutEntry = {
+ ...with_prefix("h_", height_scale),
+ ...with_prefix("w_", width_scale),
+ ...with_prefix("dim_", dimension_scale)
+};
+
+const translate_scale: ThemeLayoutEntry = {
+ ...with_prefix("h_", height_scale),
+ ...with_prefix("w_", width_scale)
+};
+
+const spacing_scale: ThemeLayoutEntry = {
+ ...base_spacing_tokens,
+ ...with_prefix("dim_", dimension_scale)
+};
+
+const app_theme_config: TailwindThemeConfig = {
+ height: height_scale,
+ width: width_scale,
+ min_height: min_height_scale,
+ max_height: max_height_scale,
+ min_width: min_width_scale,
+ max_width: max_width_scale,
+ padding: padding_scale,
+ translate: translate_scale,
+ spacing: spacing_scale
+};
+
+export const theme_app_layout: ThemeLayoutParam = {
+ variables: build_theme_layout_variables(app_theme_config)
+};
diff --git a/themes/src/layout/index.ts b/themes/src/layout/index.ts
@@ -0,0 +1,6 @@
+import { theme_app_layout } from "./app/index.js";
+import { ThemeLayoutKey, ThemeLayoutParam } from "./types.js";
+
+export const theme_layouts: Record<ThemeLayoutKey, ThemeLayoutParam> = {
+ app: theme_app_layout,
+};
+\ No newline at end of file
diff --git a/themes/src/layout/tokens.ts b/themes/src/layout/tokens.ts
@@ -0,0 +1,38 @@
+import type {
+ TailwindThemeConfig,
+ TailwindThemeNamespace,
+ ThemeLayoutEntry,
+ ThemeVariable
+} from "./types.js";
+
+export const with_prefix = (
+ prefix: string,
+ source: ThemeLayoutEntry
+): ThemeLayoutEntry =>
+ Object.fromEntries(
+ Object.entries(source).map(([key, value]) => [`${prefix}${key}`, value])
+ );
+
+const to_theme_variables = (
+ namespace: TailwindThemeNamespace,
+ scale: ThemeLayoutEntry
+): ThemeVariable[] =>
+ Object.entries(scale).map(([name, value]) => ({
+ namespace,
+ name,
+ value
+ }));
+
+export const build_theme_layout_variables = (
+ config: TailwindThemeConfig
+): ThemeVariable[] => [
+ ...to_theme_variables("height", config.height),
+ ...to_theme_variables("width", config.width),
+ ...to_theme_variables("min-height", config.min_height),
+ ...to_theme_variables("max-height", config.max_height),
+ ...to_theme_variables("min-width", config.min_width),
+ ...to_theme_variables("max-width", config.max_width),
+ ...to_theme_variables("padding", config.padding),
+ ...to_theme_variables("translate", config.translate),
+ ...to_theme_variables("spacing", config.spacing)
+ ];
diff --git a/themes/src/layout/types.ts b/themes/src/layout/types.ts
@@ -0,0 +1,54 @@
+export type ThemeLayoutKey = "app";
+
+export interface ThemeLayoutParam {
+ variables: ThemeVariable[];
+}
+
+export type ThemeLayoutEntry = Record<string, string>;
+
+export interface ThemeVariable {
+ namespace: TailwindThemeNamespace;
+ name: string;
+ value: string;
+}
+
+export type TailwindThemeNamespace =
+ | "height"
+ | "width"
+ | "min-height"
+ | "max-height"
+ | "min-width"
+ | "max-width"
+ | "padding"
+ | "translate"
+ | "spacing";
+
+export interface TailwindThemeConfig {
+ height: ThemeLayoutEntry;
+ width: ThemeLayoutEntry;
+ min_height: ThemeLayoutEntry;
+ max_height: ThemeLayoutEntry;
+ min_width: ThemeLayoutEntry;
+ max_width: ThemeLayoutEntry;
+ padding: ThemeLayoutEntry;
+ translate: ThemeLayoutEntry;
+ spacing: ThemeLayoutEntry;
+}
+
+export type IosLayoutKey = "ios0" | "ios1";
+
+export type IosResponsiveLayoutKey<TBase extends string> =
+ `${TBase}_${IosLayoutKey}`;
+
+export type LayoutHeightKey =
+ | "lo_view_main"
+ | "lo_bottom_button"
+ | "nav_tabs"
+ | "nav_page_header"
+ | "nav_page_toolbar";
+
+export type LayoutWidthKey = "lo" | "lo_line_entry" | "lo_textdesc";
+
+export type IosHeightTokenKey = IosResponsiveLayoutKey<LayoutHeightKey>;
+
+export type IosWidthTokenKey = IosResponsiveLayoutKey<LayoutWidthKey>;
diff --git a/themes/src/presets/index.ts b/themes/src/presets/index.ts
@@ -0,0 +1,7 @@
+import { ThemeKey } from "../core/types.js";
+import { theme_os_preset } from "./os/index.js";
+import { ThemePreset } from "./types.js";
+
+export const theme_presets: Record<ThemeKey, ThemePreset> = {
+ os: theme_os_preset,
+};
+\ No newline at end of file
diff --git a/themes/src/presets/os/index.ts b/themes/src/presets/os/index.ts
@@ -0,0 +1,8 @@
+import { ThemePreset } from "../types.js";
+import { os_dark_theme } from "./os-theme-dark.js";
+import { os_light_theme } from "./os-theme-light.js";
+
+export const theme_os_preset: ThemePreset = {
+ light: os_light_theme,
+ dark: os_dark_theme
+}
+\ No newline at end of file
diff --git a/themes/src/presets/os/os-theme-dark.ts b/themes/src/presets/os/os-theme-dark.ts
@@ -0,0 +1,57 @@
+import type { OsThemePreset } from "../types.js";
+
+export const os_dark_theme: OsThemePreset = {
+ ly0: {
+ surfaces: {
+ _: [0, 0, 7],
+ _w: [0, 0, 7],
+ _a: [240, 2, 23],
+ edge: [274, 4, 11],
+ blur: [0, 0, 12]
+ },
+ glyphs: {
+ _: [230, 3, 56],
+ _a: [230, 3, 51],
+ _pl: [30, 1, 99],
+ hl: [210, 100, 52],
+ hl_a: [210, 91, 21],
+ shade: [240, 3, 57],
+ label: [240, 3, 55]
+ }
+ },
+ ly1: {
+ surfaces: {
+ _: [240, 4, 11],
+ _a: [240, 2, 23],
+ edge: [240, 3, 19],
+ err: [0, 0, 0],
+ focus: [240, 4, 20]
+ },
+ glyphs: {
+ _: [30, 100, 100],
+ _a: [30, 1, 90],
+ _d: [240, 1, 82],
+ _pl: [30, 1, 99],
+ hl: [210, 100, 52],
+ hl_a: [210, 100, 62],
+ shade: [230, 4, 61],
+ label: [30, 1, 99]
+ }
+ },
+ ly2: {
+ surfaces: {
+ _: [240, 2, 18],
+ _a: [240, 3, 15],
+ edge: [240, 2, 23]
+ },
+ glyphs: {
+ _: [240, 3, 73],
+ _a: [230, 4, 51],
+ _d: [240, 3, 63],
+ _pl: [240, 2, 40],
+ hl: [210, 100, 52],
+ hl_a: [210, 100, 42],
+ shade: [230, 4, 61]
+ }
+ }
+};
diff --git a/themes/src/presets/os/os-theme-light.ts b/themes/src/presets/os/os-theme-light.ts
@@ -0,0 +1,57 @@
+import type { OsThemePreset } from "../types.js";
+
+export const os_light_theme: OsThemePreset = {
+ ly0: {
+ surfaces: {
+ _: [240, 24, 96],
+ _w: [248, 17, 98],
+ _a: [240, 6, 83],
+ edge: [0, 0, 87],
+ blur: [179, 7, 96]
+ },
+ glyphs: {
+ _: [240, 2, 55],
+ _a: [240, 2, 60],
+ _pl: [240, 2, 78],
+ hl: [219, 92, 59],
+ hl_a: [211, 100, 40],
+ shade: [230, 3, 54],
+ label: [240, 2, 53]
+ }
+ },
+ ly1: {
+ surfaces: {
+ _: [0, 0, 100],
+ _a: [240, 6, 83],
+ edge: [274, 4, 90],
+ err: [0, 0, 0],
+ focus: [240, 15, 94]
+ },
+ glyphs: {
+ _: [0, 0, 10],
+ _a: [0, 0, 10],
+ _d: [0, 0, 20],
+ _pl: [240, 2, 78],
+ hl: [211, 100, 50],
+ hl_a: [211, 100, 40],
+ shade: [240, 2, 55],
+ label: [240, 2, 53]
+ }
+ },
+ ly2: {
+ surfaces: {
+ _: [240, 5, 90],
+ _a: [240, 5, 95],
+ edge: [242, 2, 88]
+ },
+ glyphs: {
+ _: [240, 2, 55],
+ _a: [240, 2, 45],
+ _d: [240, 2, 65],
+ _pl: [240, 2, 78],
+ hl: [211, 100, 50],
+ hl_a: [211, 100, 40],
+ shade: [240, 2, 55]
+ }
+ }
+};
diff --git a/themes/src/presets/types.ts b/themes/src/presets/types.ts
@@ -0,0 +1,86 @@
+import type { ThemeMode } from "../core/types.js";
+
+export type HslTuple = [number, number, number];
+
+export type ThemeSurfaceKey =
+ | "_"
+ | "_w"
+ | "_a"
+ | "edge"
+ | "blur"
+ | "err"
+ | "focus";
+
+export type ThemeGlyphKey =
+ | "_"
+ | "_a"
+ | "_pl"
+ | "_d"
+ | "hl"
+ | "hl_a"
+ | "shade"
+ | "label";
+
+export interface ThemeLayer0 {
+ surfaces: {
+ _: HslTuple;
+ _w: HslTuple;
+ _a: HslTuple;
+ edge: HslTuple;
+ blur: HslTuple;
+ };
+ glyphs: {
+ _: HslTuple;
+ _a: HslTuple;
+ _pl: HslTuple;
+ hl: HslTuple;
+ hl_a: HslTuple;
+ shade: HslTuple;
+ label: HslTuple;
+ };
+}
+
+export interface ThemeLayer1 {
+ surfaces: {
+ _: HslTuple;
+ _a: HslTuple;
+ edge: HslTuple;
+ err: HslTuple;
+ focus: HslTuple;
+ };
+ glyphs: {
+ _: HslTuple;
+ _a: HslTuple;
+ _d: HslTuple;
+ _pl: HslTuple;
+ hl: HslTuple;
+ hl_a: HslTuple;
+ shade: HslTuple;
+ label: HslTuple;
+ };
+}
+
+export interface ThemeLayer2 {
+ surfaces: {
+ _: HslTuple;
+ _a: HslTuple;
+ edge: HslTuple;
+ };
+ glyphs: {
+ _: HslTuple;
+ _a: HslTuple;
+ _d: HslTuple;
+ _pl: HslTuple;
+ hl: HslTuple;
+ hl_a: HslTuple;
+ shade: HslTuple;
+ };
+}
+
+export interface OsThemePreset {
+ ly0: ThemeLayer0;
+ ly1: ThemeLayer1;
+ ly2: ThemeLayer2;
+}
+
+export type ThemePreset = Record<ThemeMode, OsThemePreset>;
diff --git a/themes/src/styles/os.css b/themes/src/styles/os.css
@@ -1,121 +0,0 @@
-@theme {
- --color-ly0: hsl(var(--ly0) / <alpha-value>);
- --color-ly0-w: hsl(var(--ly0-w) / <alpha-value>);
- --color-ly0-a: hsl(var(--ly0-a) / <alpha-value>);
- --color-ly0-edge: hsl(var(--ly0-edge) / <alpha-value>);
- --color-ly0-blur: hsl(var(--ly0-blur) / <alpha-value>);
- --color-ly0-gl: hsl(var(--ly0-gl) / <alpha-value>);
- --color-ly0-gl-a: hsl(var(--ly0-gl-a) / <alpha-value>);
- --color-ly0-gl-pl: hsl(var(--ly0-gl-pl) / <alpha-value>);
- --color-ly0-gl-hl: hsl(var(--ly0-gl-hl) / <alpha-value>);
- --color-ly0-gl-hl-a: hsl(var(--ly0-gl-hl-a) / <alpha-value>);
- --color-ly0-gl-shade: hsl(var(--ly0-gl-shade) / <alpha-value>);
- --color-ly0-gl-label: hsl(var(--ly0-gl-label) / <alpha-value>);
- --color-ly1: hsl(var(--ly1) / <alpha-value>);
- --color-ly1-a: hsl(var(--ly1-a) / <alpha-value>);
- --color-ly1-edge: hsl(var(--ly1-edge) / <alpha-value>);
- --color-ly1-err: hsl(var(--ly1-err) / <alpha-value>);
- --color-ly1-focus: hsl(var(--ly1-focus) / <alpha-value>);
- --color-ly1-gl: hsl(var(--ly1-gl) / <alpha-value>);
- --color-ly1-gl-a: hsl(var(--ly1-gl-a) / <alpha-value>);
- --color-ly1-gl-d: hsl(var(--ly1-gl-d) / <alpha-value>);
- --color-ly1-gl-pl: hsl(var(--ly1-gl-pl) / <alpha-value>);
- --color-ly1-gl-hl: hsl(var(--ly1-gl-hl) / <alpha-value>);
- --color-ly1-gl-hl-a: hsl(var(--ly1-gl-hl-a) / <alpha-value>);
- --color-ly1-gl-shade: hsl(var(--ly1-gl-shade) / <alpha-value>);
- --color-ly1-gl-label: hsl(var(--ly1-gl-label) / <alpha-value>);
- --color-ly2: hsl(var(--ly2) / <alpha-value>);
- --color-ly2-a: hsl(var(--ly2-a) / <alpha-value>);
- --color-ly2-edge: hsl(var(--ly2-edge) / <alpha-value>);
- --color-ly2-gl: hsl(var(--ly2-gl) / <alpha-value>);
- --color-ly2-gl-a: hsl(var(--ly2-gl-a) / <alpha-value>);
- --color-ly2-gl-d: hsl(var(--ly2-gl-d) / <alpha-value>);
- --color-ly2-gl-pl: hsl(var(--ly2-gl-pl) / <alpha-value>);
- --color-ly2-gl-hl: hsl(var(--ly2-gl-hl) / <alpha-value>);
- --color-ly2-gl-hl-a: hsl(var(--ly2-gl-hl-a) / <alpha-value>);
- --color-ly2-gl-shade: hsl(var(--ly2-gl-shade) / <alpha-value>);
-}
-
-@plugin "daisyui/theme" {
- name: "os_dark";
- default: false;
- prefersdark: true;
- color-scheme: dark;
- --color-ly0: hsl(0, 0%, 7%);
- --color-ly0-w: hsl(0, 0%, 7%);
- --color-ly0-a: hsl(240, 2%, 23%);
- --color-ly0-edge: hsl(274, 4%, 11%);
- --color-ly0-blur: hsl(0, 0%, 12%);
- --color-ly0-gl: hsl(230, 3%, 56%);
- --color-ly0-gl-a: hsl(230, 3%, 51%);
- --color-ly0-gl-pl: hsl(30, 1%, 99%);
- --color-ly0-gl-hl: hsl(210, 100%, 52%);
- --color-ly0-gl-hl-a: hsl(210, 91%, 21%);
- --color-ly0-gl-shade: hsl(240, 3%, 57%);
- --color-ly0-gl-label: hsl(240, 3%, 55%);
- --color-ly1: hsl(240, 4%, 11%);
- --color-ly1-a: hsl(240, 2%, 23%);
- --color-ly1-edge: hsl(240, 3%, 19%);
- --color-ly1-err: hsl(0, 0%, 0%);
- --color-ly1-focus: hsl(240, 4%, 20%);
- --color-ly1-gl: hsl(30, 100%, 100%);
- --color-ly1-gl-a: hsl(30, 1%, 90%);
- --color-ly1-gl-d: hsl(240, 1%, 82%);
- --color-ly1-gl-pl: hsl(30, 1%, 99%);
- --color-ly1-gl-hl: hsl(210, 100%, 52%);
- --color-ly1-gl-hl-a: hsl(210, 100%, 62%);
- --color-ly1-gl-shade: hsl(230, 4%, 61%);
- --color-ly1-gl-label: hsl(30, 1%, 99%);
- --color-ly2: hsl(240, 2%, 18%);
- --color-ly2-a: hsl(240, 3%, 15%);
- --color-ly2-edge: hsl(240, 2%, 23%);
- --color-ly2-gl: hsl(240, 3%, 73%);
- --color-ly2-gl-a: hsl(230, 4%, 51%);
- --color-ly2-gl-d: hsl(240, 3%, 63%);
- --color-ly2-gl-pl: hsl(240, 2%, 40%);
- --color-ly2-gl-hl: hsl(210, 100%, 52%);
- --color-ly2-gl-hl-a: hsl(210, 100%, 42%);
- --color-ly2-gl-shade: hsl(230, 4%, 61%);
-}
-
-@plugin "daisyui/theme" {
- name: "os_light";
- default: false;
- prefersdark: false;
- color-scheme: light;
- --color-ly0: hsl(240, 24%, 96%);
- --color-ly0-w: hsl(248, 248%, 250%);
- --color-ly0-a: hsl(240, 6%, 83%);
- --color-ly0-edge: hsl(0, 0%, 87%);
- --color-ly0-blur: hsl(179, 7%, 96%);
- --color-ly0-gl: hsl(240, 2%, 55%);
- --color-ly0-gl-a: hsl(240, 2%, 60%);
- --color-ly0-gl-pl: hsl(240, 2%, 78%);
- --color-ly0-gl-hl: hsl(219, 92%, 59%);
- --color-ly0-gl-hl-a: hsl(211, 100%, 40%);
- --color-ly0-gl-shade: hsl(230, 3%, 54%);
- --color-ly0-gl-label: hsl(240, 2%, 53%);
- --color-ly1: hsl(0, 0%, 100%);
- --color-ly1-a: hsl(240, 6%, 83%);
- --color-ly1-edge: hsl(274, 4%, 90%);
- --color-ly1-err: hsl(0, 0%, 0%);
- --color-ly1-focus: hsl(240, 15%, 94%);
- --color-ly1-gl: hsl(0, 0%, 10%);
- --color-ly1-gl-a: hsl(0, 0%, 10%);
- --color-ly1-gl-d: hsl(0, 0%, 20%);
- --color-ly1-gl-pl: hsl(240, 2%, 78%);
- --color-ly1-gl-hl: hsl(211, 100%, 50%);
- --color-ly1-gl-hl-a: hsl(211, 100%, 40%);
- --color-ly1-gl-shade: hsl(240, 2%, 55%);
- --color-ly1-gl-label: hsl(240, 2%, 53%);
- --color-ly2: hsl(240, 5%, 90%);
- --color-ly2-a: hsl(240, 5%, 95%);
- --color-ly2-edge: hsl(242, 2%, 88%);
- --color-ly2-gl: hsl(240, 2%, 55%);
- --color-ly2-gl-a: hsl(240, 2%, 45%);
- --color-ly2-gl-d: hsl(240, 2%, 65%);
- --color-ly2-gl-pl: hsl(240, 2%, 78%);
- --color-ly2-gl-hl: hsl(211, 100%, 50%);
- --color-ly2-gl-hl-a: hsl(211, 100%, 40%);
- --color-ly2-gl-shade: hsl(240, 2%, 55%);
-}
-\ No newline at end of file
diff --git a/themes/src/styles/theme.css b/themes/src/styles/theme.css
@@ -1,37 +0,0 @@
-@theme {
- --color-ly0: hsl(var(--ly0) / <alpha-value>);
- --color-ly0-w: hsl(var(--ly0-w) / <alpha-value>);
- --color-ly0-a: hsl(var(--ly0-a) / <alpha-value>);
- --color-ly0-edge: hsl(var(--ly0-edge) / <alpha-value>);
- --color-ly0-blur: hsl(var(--ly0-blur) / <alpha-value>);
- --color-ly0-gl: hsl(var(--ly0-gl) / <alpha-value>);
- --color-ly0-gl-a: hsl(var(--ly0-gl-a) / <alpha-value>);
- --color-ly0-gl-pl: hsl(var(--ly0-gl-pl) / <alpha-value>);
- --color-ly0-gl-hl: hsl(var(--ly0-gl-hl) / <alpha-value>);
- --color-ly0-gl-hl-a: hsl(var(--ly0-gl-hl-a) / <alpha-value>);
- --color-ly0-gl-shade: hsl(var(--ly0-gl-shade) / <alpha-value>);
- --color-ly0-gl-label: hsl(var(--ly0-gl-label) / <alpha-value>);
- --color-ly1: hsl(var(--ly1) / <alpha-value>);
- --color-ly1-a: hsl(var(--ly1-a) / <alpha-value>);
- --color-ly1-edge: hsl(var(--ly1-edge) / <alpha-value>);
- --color-ly1-err: hsl(var(--ly1-err) / <alpha-value>);
- --color-ly1-focus: hsl(var(--ly1-focus) / <alpha-value>);
- --color-ly1-gl: hsl(var(--ly1-gl) / <alpha-value>);
- --color-ly1-gl-a: hsl(var(--ly1-gl-a) / <alpha-value>);
- --color-ly1-gl-d: hsl(var(--ly1-gl-d) / <alpha-value>);
- --color-ly1-gl-pl: hsl(var(--ly1-gl-pl) / <alpha-value>);
- --color-ly1-gl-hl: hsl(var(--ly1-gl-hl) / <alpha-value>);
- --color-ly1-gl-hl-a: hsl(var(--ly1-gl-hl-a) / <alpha-value>);
- --color-ly1-gl-shade: hsl(var(--ly1-gl-shade) / <alpha-value>);
- --color-ly1-gl-label: hsl(var(--ly1-gl-label) / <alpha-value>);
- --color-ly2: hsl(var(--ly2) / <alpha-value>);
- --color-ly2-a: hsl(var(--ly2-a) / <alpha-value>);
- --color-ly2-edge: hsl(var(--ly2-edge) / <alpha-value>);
- --color-ly2-gl: hsl(var(--ly2-gl) / <alpha-value>);
- --color-ly2-gl-a: hsl(var(--ly2-gl-a) / <alpha-value>);
- --color-ly2-gl-d: hsl(var(--ly2-gl-d) / <alpha-value>);
- --color-ly2-gl-pl: hsl(var(--ly2-gl-pl) / <alpha-value>);
- --color-ly2-gl-hl: hsl(var(--ly2-gl-hl) / <alpha-value>);
- --color-ly2-gl-hl-a: hsl(var(--ly2-gl-hl-a) / <alpha-value>);
- --color-ly2-gl-shade: hsl(var(--ly2-gl-shade) / <alpha-value>);
-}
-\ No newline at end of file
diff --git a/themes/src/types/lib.ts b/themes/src/types/lib.ts
@@ -1,5 +0,0 @@
-export type ThemeKey = `os` | `garden`;
-export type ThemeMode = `light` | `dark`;
-export type ThemeKeys<T extends ThemeKey> = `${T}_${ThemeMode}`;
-export type ThemeKeysLight<T extends ThemeKey> = `${T}_light`;
-export type ThemeKeysDark<T extends ThemeKey> = `${T}_dark`;
diff --git a/themes/theme.css b/themes/theme.css
@@ -1,159 +0,0 @@
-@theme {
- --color-ly0: hsl(var(--ly0) / <alpha-value>);
- --color-ly0-w: hsl(var(--ly0-w) / <alpha-value>);
- --color-ly0-a: hsl(var(--ly0-a) / <alpha-value>);
- --color-ly0-edge: hsl(var(--ly0-edge) / <alpha-value>);
- --color-ly0-blur: hsl(var(--ly0-blur) / <alpha-value>);
- --color-ly0-gl: hsl(var(--ly0-gl) / <alpha-value>);
- --color-ly0-gl-a: hsl(var(--ly0-gl-a) / <alpha-value>);
- --color-ly0-gl-pl: hsl(var(--ly0-gl-pl) / <alpha-value>);
- --color-ly0-gl-hl: hsl(var(--ly0-gl-hl) / <alpha-value>);
- --color-ly0-gl-hl-a: hsl(var(--ly0-gl-hl-a) / <alpha-value>);
- --color-ly0-gl-shade: hsl(var(--ly0-gl-shade) / <alpha-value>);
- --color-ly0-gl-label: hsl(var(--ly0-gl-label) / <alpha-value>);
- --color-ly1: hsl(var(--ly1) / <alpha-value>);
- --color-ly1-a: hsl(var(--ly1-a) / <alpha-value>);
- --color-ly1-edge: hsl(var(--ly1-edge) / <alpha-value>);
- --color-ly1-err: hsl(var(--ly1-err) / <alpha-value>);
- --color-ly1-focus: hsl(var(--ly1-focus) / <alpha-value>);
- --color-ly1-gl: hsl(var(--ly1-gl) / <alpha-value>);
- --color-ly1-gl-a: hsl(var(--ly1-gl-a) / <alpha-value>);
- --color-ly1-gl-d: hsl(var(--ly1-gl-d) / <alpha-value>);
- --color-ly1-gl-pl: hsl(var(--ly1-gl-pl) / <alpha-value>);
- --color-ly1-gl-hl: hsl(var(--ly1-gl-hl) / <alpha-value>);
- --color-ly1-gl-hl-a: hsl(var(--ly1-gl-hl-a) / <alpha-value>);
- --color-ly1-gl-shade: hsl(var(--ly1-gl-shade) / <alpha-value>);
- --color-ly1-gl-label: hsl(var(--ly1-gl-label) / <alpha-value>);
- --color-ly2: hsl(var(--ly2) / <alpha-value>);
- --color-ly2-a: hsl(var(--ly2-a) / <alpha-value>);
- --color-ly2-edge: hsl(var(--ly2-edge) / <alpha-value>);
- --color-ly2-gl: hsl(var(--ly2-gl) / <alpha-value>);
- --color-ly2-gl-a: hsl(var(--ly2-gl-a) / <alpha-value>);
- --color-ly2-gl-d: hsl(var(--ly2-gl-d) / <alpha-value>);
- --color-ly2-gl-pl: hsl(var(--ly2-gl-pl) / <alpha-value>);
- --color-ly2-gl-hl: hsl(var(--ly2-gl-hl) / <alpha-value>);
- --color-ly2-gl-hl-a: hsl(var(--ly2-gl-hl-a) / <alpha-value>);
- --color-ly2-gl-shade: hsl(var(--ly2-gl-shade) / <alpha-value>);
- --color-ly0: hsl(var(--ly0) / <alpha-value>);
- --color-ly0-w: hsl(var(--ly0-w) / <alpha-value>);
- --color-ly0-a: hsl(var(--ly0-a) / <alpha-value>);
- --color-ly0-edge: hsl(var(--ly0-edge) / <alpha-value>);
- --color-ly0-blur: hsl(var(--ly0-blur) / <alpha-value>);
- --color-ly0-gl: hsl(var(--ly0-gl) / <alpha-value>);
- --color-ly0-gl-a: hsl(var(--ly0-gl-a) / <alpha-value>);
- --color-ly0-gl-pl: hsl(var(--ly0-gl-pl) / <alpha-value>);
- --color-ly0-gl-hl: hsl(var(--ly0-gl-hl) / <alpha-value>);
- --color-ly0-gl-hl-a: hsl(var(--ly0-gl-hl-a) / <alpha-value>);
- --color-ly0-gl-shade: hsl(var(--ly0-gl-shade) / <alpha-value>);
- --color-ly0-gl-label: hsl(var(--ly0-gl-label) / <alpha-value>);
- --color-ly1: hsl(var(--ly1) / <alpha-value>);
- --color-ly1-a: hsl(var(--ly1-a) / <alpha-value>);
- --color-ly1-edge: hsl(var(--ly1-edge) / <alpha-value>);
- --color-ly1-err: hsl(var(--ly1-err) / <alpha-value>);
- --color-ly1-focus: hsl(var(--ly1-focus) / <alpha-value>);
- --color-ly1-gl: hsl(var(--ly1-gl) / <alpha-value>);
- --color-ly1-gl-a: hsl(var(--ly1-gl-a) / <alpha-value>);
- --color-ly1-gl-d: hsl(var(--ly1-gl-d) / <alpha-value>);
- --color-ly1-gl-pl: hsl(var(--ly1-gl-pl) / <alpha-value>);
- --color-ly1-gl-hl: hsl(var(--ly1-gl-hl) / <alpha-value>);
- --color-ly1-gl-hl-a: hsl(var(--ly1-gl-hl-a) / <alpha-value>);
- --color-ly1-gl-shade: hsl(var(--ly1-gl-shade) / <alpha-value>);
- --color-ly1-gl-label: hsl(var(--ly1-gl-label) / <alpha-value>);
- --color-ly2: hsl(var(--ly2) / <alpha-value>);
- --color-ly2-a: hsl(var(--ly2-a) / <alpha-value>);
- --color-ly2-edge: hsl(var(--ly2-edge) / <alpha-value>);
- --color-ly2-gl: hsl(var(--ly2-gl) / <alpha-value>);
- --color-ly2-gl-a: hsl(var(--ly2-gl-a) / <alpha-value>);
- --color-ly2-gl-d: hsl(var(--ly2-gl-d) / <alpha-value>);
- --color-ly2-gl-pl: hsl(var(--ly2-gl-pl) / <alpha-value>);
- --color-ly2-gl-hl: hsl(var(--ly2-gl-hl) / <alpha-value>);
- --color-ly2-gl-hl-a: hsl(var(--ly2-gl-hl-a) / <alpha-value>);
- --color-ly2-gl-shade: hsl(var(--ly2-gl-shade) / <alpha-value>);
-}
-
-@plugin "daisyui/theme" {
- name: "os_dark";
- default: false;
- prefersdark: true;
- color-scheme: dark;
-
- --color-ly0: hsl(0, 0%, 7%);
- --color-ly0-w: hsl(0, 0%, 7%);
- --color-ly0-a: hsl(240, 2%, 23%);
- --color-ly0-edge: hsl(274, 4%, 11%);
- --color-ly0-blur: hsl(0, 0%, 12%);
- --color-ly0-gl: hsl(230, 3%, 56%);
- --color-ly0-gl-a: hsl(230, 3%, 51%);
- --color-ly0-gl-pl: hsl(30, 1%, 99%);
- --color-ly0-gl-hl: hsl(210, 100%, 52%);
- --color-ly0-gl-hl-a: hsl(210, 91%, 21%);
- --color-ly0-gl-shade: hsl(240, 3%, 57%);
- --color-ly0-gl-label: hsl(240, 3%, 55%);
- --color-ly1: hsl(240, 4%, 11%);
- --color-ly1-a: hsl(240, 2%, 23%);
- --color-ly1-edge: hsl(240, 3%, 19%);
- --color-ly1-err: hsl(0, 0%, 0%);
- --color-ly1-focus: hsl(240, 4%, 20%);
- --color-ly1-gl: hsl(30, 100%, 100%);
- --color-ly1-gl-a: hsl(30, 1%, 90%);
- --color-ly1-gl-d: hsl(240, 1%, 82%);
- --color-ly1-gl-pl: hsl(30, 1%, 99%);
- --color-ly1-gl-hl: hsl(210, 100%, 52%);
- --color-ly1-gl-hl-a: hsl(210, 100%, 62%);
- --color-ly1-gl-shade: hsl(230, 4%, 61%);
- --color-ly1-gl-label: hsl(30, 1%, 99%);
- --color-ly2: hsl(240, 2%, 18%);
- --color-ly2-a: hsl(240, 3%, 15%);
- --color-ly2-edge: hsl(240, 2%, 23%);
- --color-ly2-gl: hsl(240, 3%, 73%);
- --color-ly2-gl-a: hsl(230, 4%, 51%);
- --color-ly2-gl-d: hsl(240, 3%, 63%);
- --color-ly2-gl-pl: hsl(240, 2%, 40%);
- --color-ly2-gl-hl: hsl(210, 100%, 52%);
- --color-ly2-gl-hl-a: hsl(210, 100%, 42%);
- --color-ly2-gl-shade: hsl(230, 4%, 61%);
-}
-
-@plugin "daisyui/theme" {
- name: "os_light";
- default: false;
- prefersdark: false;
- color-scheme: light;
-
- --color-ly0: hsl(240, 24%, 96%);
- --color-ly0-w: hsl(248, 248%, 250%);
- --color-ly0-a: hsl(240, 6%, 83%);
- --color-ly0-edge: hsl(0, 0%, 87%);
- --color-ly0-blur: hsl(179, 7%, 96%);
- --color-ly0-gl: hsl(240, 2%, 55%);
- --color-ly0-gl-a: hsl(240, 2%, 60%);
- --color-ly0-gl-pl: hsl(240, 2%, 78%);
- --color-ly0-gl-hl: hsl(219, 92%, 59%);
- --color-ly0-gl-hl-a: hsl(211, 100%, 40%);
- --color-ly0-gl-shade: hsl(230, 3%, 54%);
- --color-ly0-gl-label: hsl(240, 2%, 53%);
- --color-ly1: hsl(0, 0%, 100%);
- --color-ly1-a: hsl(240, 6%, 83%);
- --color-ly1-edge: hsl(274, 4%, 90%);
- --color-ly1-err: hsl(0, 0%, 0%);
- --color-ly1-focus: hsl(240, 15%, 94%);
- --color-ly1-gl: hsl(0, 0%, 10%);
- --color-ly1-gl-a: hsl(0, 0%, 10%);
- --color-ly1-gl-d: hsl(0, 0%, 20%);
- --color-ly1-gl-pl: hsl(240, 2%, 78%);
- --color-ly1-gl-hl: hsl(211, 100%, 50%);
- --color-ly1-gl-hl-a: hsl(211, 100%, 40%);
- --color-ly1-gl-shade: hsl(240, 2%, 55%);
- --color-ly1-gl-label: hsl(240, 2%, 53%);
- --color-ly2: hsl(240, 5%, 90%);
- --color-ly2-a: hsl(240, 5%, 95%);
- --color-ly2-edge: hsl(242, 2%, 88%);
- --color-ly2-gl: hsl(240, 2%, 55%);
- --color-ly2-gl-a: hsl(240, 2%, 45%);
- --color-ly2-gl-d: hsl(240, 2%, 65%);
- --color-ly2-gl-pl: hsl(240, 2%, 78%);
- --color-ly2-gl-hl: hsl(211, 100%, 50%);
- --color-ly2-gl-hl-a: hsl(211, 100%, 40%);
- --color-ly2-gl-shade: hsl(240, 2%, 55%);
-}
-