diff --git a/pkgs/flake-module.nix b/pkgs/flake-module.nix index 52ff2084d..fb8b1536c 100644 --- a/pkgs/flake-module.nix +++ b/pkgs/flake-module.nix @@ -3,6 +3,7 @@ ./clan-cli/flake-module.nix ./installer/flake-module.nix ./ui/flake-module.nix + ./theme/flake-module.nix ]; perSystem = { pkgs, config, ... }: { diff --git a/pkgs/theme/.editorconfig b/pkgs/theme/.editorconfig new file mode 100644 index 000000000..4e89cb0e9 --- /dev/null +++ b/pkgs/theme/.editorconfig @@ -0,0 +1,3 @@ +[*.{js,jsx,ts,tsx,json}] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/pkgs/theme/.envrc b/pkgs/theme/.envrc new file mode 100644 index 000000000..2933b5bd2 --- /dev/null +++ b/pkgs/theme/.envrc @@ -0,0 +1,12 @@ +# Because we depend on nixpkgs sources, uploading to builders takes a long time + +source_up + +files=(flake-module.nix package.json package-lock.json) +if type nix_direnv_watch_file &>/dev/null; then + nix_direnv_watch_file "${files[@]}" +else + watch_file "${files[@]}" +fi + +use flake .#theme --builders '' diff --git a/pkgs/theme/.gitignore b/pkgs/theme/.gitignore new file mode 100644 index 000000000..9e29a683b --- /dev/null +++ b/pkgs/theme/.gitignore @@ -0,0 +1,43 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# nix +.floco +src/fonts + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# Generated api code +openapi.json +api/ diff --git a/pkgs/theme/default.nix b/pkgs/theme/default.nix new file mode 100644 index 000000000..d66639194 --- /dev/null +++ b/pkgs/theme/default.nix @@ -0,0 +1,41 @@ +{ floco +, system +, pkgs +, clanPkgs +}: +let + + lib = floco.lib; + + pjs = + let + msg = "default.nix: Expected to find `package.json' to lookup " + + "package name/version, but no such file exists at: " + + (toString ./package.json); + in + if builtins.pathExists ./package.json then lib.importJSON ./package.json + else throw msg; + ident = pjs.name; + inherit (pjs) version; + + + fmod = lib.evalModules { + modules = [ + floco.nixosModules.floco + { config.floco.settings = { inherit system; basedir = ./.; }; } + ./nix/floco-cfg.nix + ]; + specialArgs = { + inherit pkgs clanPkgs; + }; + }; + + # This attrset holds a few derivations related to our package. + # We'll expose these below to the CLI. + pkg = fmod.config.floco.packages.${ident}.${version}; + + +in +{ + inherit pkg fmod; +} diff --git a/pkgs/theme/flake-module.nix b/pkgs/theme/flake-module.nix new file mode 100644 index 000000000..864cea516 --- /dev/null +++ b/pkgs/theme/flake-module.nix @@ -0,0 +1,18 @@ +{ self, ... }: +{ + perSystem = { self', pkgs, ... }: + let + inherit (self.inputs) floco; + base = pkgs.callPackage ./default.nix { inherit floco; clanPkgs = self'.packages; }; + in + { + packages = { + theme = base.pkg.global; + }; + devShells.theme = pkgs.callPackage ./shell.nix { + inherit pkgs; + inherit (base) fmod pkg; + clanPkgs = self'.packages; + }; + }; +} diff --git a/pkgs/theme/index.html b/pkgs/theme/index.html new file mode 100644 index 000000000..35eadad0e --- /dev/null +++ b/pkgs/theme/index.html @@ -0,0 +1,962 @@ + + + + Page Title + + +
+
+ neutral0 +
+
+ neutral10 +
+
+ neutral20 +
+
+ neutral30 +
+
+ neutral40 +
+
+ neutral50 +
+
+ neutral51 +
+
+ neutral60 +
+
+ neutral70 +
+
+ neutral80 +
+
+ neutral90 +
+
+ neutral98 +
+
+ neutral100 +
+
+
+
+ red0 +
+
+ red10 +
+
+ red20 +
+
+ red30 +
+
+ red40 +
+
+ red50 +
+
+ red60 +
+
+ red70 +
+
+ red80 +
+
+ red90 +
+
+ red95 +
+
+ red100 +
+
+
+
+ green0 +
+
+ green10 +
+
+ green20 +
+
+ green30 +
+
+ green40 +
+
+ green50 +
+
+ green60 +
+
+ green70 +
+
+ green72 +
+
+ green80 +
+
+ green90 +
+
+ green98 +
+
+ green100 +
+
+
+
+ yellow0 +
+
+ yellow10 +
+
+ yellow20 +
+
+ yellow30 +
+
+ yellow40 +
+
+ yellow50 +
+
+ yellow60 +
+
+ yellow70 +
+
+ yellow80 +
+
+ yellow87 +
+
+ yellow90 +
+
+ yellow98 +
+
+ yellow100 +
+
+
+
+ purple0 +
+
+ purple10 +
+
+ purple20 +
+
+ purple30 +
+
+ purple33 +
+
+ purple40 +
+
+ purple50 +
+
+ purple60 +
+
+ purple70 +
+
+ purple80 +
+
+ purple90 +
+
+ purple100 +
+
+
+
+ blue0 +
+
+ blue10 +
+
+ blue20 +
+
+ blue30 +
+
+ blue40 +
+
+ blue50 +
+
+ blue60 +
+
+ blue70 +
+
+ blue80 +
+
+ blue90 +
+
+ blue95 +
+
+ blue100 +
+
+ + diff --git a/pkgs/theme/nix/floco-cfg.nix b/pkgs/theme/nix/floco-cfg.nix new file mode 100644 index 000000000..e5b5d8719 --- /dev/null +++ b/pkgs/theme/nix/floco-cfg.nix @@ -0,0 +1,26 @@ +# ============================================================================ # +# +# Aggregates configs making them available to `default.nix', `flake.nix', +# or other projects that want to consume this module/package as a dependency. +# +# ---------------------------------------------------------------------------- # +{ + _file = "theme/nix/floco-cfg.nix"; + imports = + let + ifExist = builtins.filter builtins.pathExists [ + ./pdefs.nix # Generated `pdefs.nix' + ./foverrides.nix # Explicit config + ]; + in + ifExist + ++ [ + + ]; +} +# ---------------------------------------------------------------------------- # +# +# +# +# ============================================================================ # + diff --git a/pkgs/theme/nix/foverrides.nix b/pkgs/theme/nix/foverrides.nix new file mode 100644 index 000000000..acdafbe3b --- /dev/null +++ b/pkgs/theme/nix/foverrides.nix @@ -0,0 +1,12 @@ +{ lib, config, ... }: +let + pjs = lib.importJSON ../package.json; + ident = pjs.name; + inherit (pjs) version; +in +{ + config.floco.packages.${ident}.${version} = + { + source = lib.libfloco.cleanLocalSource ../.; + }; +} diff --git a/pkgs/theme/nix/pdefs.nix b/pkgs/theme/nix/pdefs.nix new file mode 100644 index 000000000..d3567754a --- /dev/null +++ b/pkgs/theme/nix/pdefs.nix @@ -0,0 +1,90 @@ +{ + floco = { + pdefs = { + "@clan/colors" = { + "1.0.0" = { + depInfo = { + "@material/material-color-utilities" = { + descriptor = "^0.2.6"; + pin = "0.2.7"; + }; + "@types/node" = { + descriptor = "^20.3.2"; + pin = "20.8.2"; + }; + typescript = { + descriptor = "^5.1.5"; + pin = "5.2.2"; + }; + }; + fetchInfo = "path:.."; + ident = "@clan/colors"; + lifecycle = { + build = true; + }; + ltype = "dir"; + treeInfo = { + "node_modules/@material/material-color-utilities" = { + dev = true; + key = "@material/material-color-utilities/0.2.7"; + }; + "node_modules/@types/node" = { + dev = true; + key = "@types/node/20.8.2"; + }; + "node_modules/typescript" = { + dev = true; + key = "typescript/5.2.2"; + }; + }; + version = "1.0.0"; + }; + }; + "@material/material-color-utilities" = { + "0.2.7" = { + fetchInfo = { + narHash = "sha256-hRYXqtkoXHoB30v1hstWz7dO7dNeBb6EJqZG66hHi94="; + type = "tarball"; + url = "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.2.7.tgz"; + }; + ident = "@material/material-color-utilities"; + ltype = "file"; + treeInfo = { }; + version = "0.2.7"; + }; + }; + "@types/node" = { + "20.8.2" = { + fetchInfo = { + narHash = "sha256-o4hyob1kLnm0OE8Rngm0d6XJxobpMlYSoquusktmLPk="; + type = "tarball"; + url = "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz"; + }; + ident = "@types/node"; + ltype = "file"; + treeInfo = { }; + version = "20.8.2"; + }; + }; + typescript = { + "5.2.2" = { + binInfo = { + binPairs = { + tsc = "bin/tsc"; + tsserver = "bin/tsserver"; + }; + }; + fetchInfo = { + narHash = "sha256-io9rXH9RLRLB0484ZdvcqblLQquLFUBGxDuwSixWxus="; + type = "tarball"; + url = "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz"; + }; + ident = "typescript"; + ltype = "file"; + treeInfo = { }; + version = "5.2.2"; + }; + }; + }; + }; +} diff --git a/pkgs/theme/package-lock.json b/pkgs/theme/package-lock.json new file mode 100644 index 000000000..6a755684b --- /dev/null +++ b/pkgs/theme/package-lock.json @@ -0,0 +1,63 @@ +{ + "name": "@clan/colors", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@clan/colors", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@material/material-color-utilities": "^0.2.6", + "@types/node": "^20.3.2", + "typescript": "^5.1.5" + } + }, + "node_modules/@material/material-color-utilities": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.2.7.tgz", + "integrity": "sha512-0FCeqG6WvK4/Cc06F/xXMd/pv4FeisI0c1tUpBbfhA2n9Y8eZEv4Karjbmf2ZqQCPUWMrGp8A571tCjizxoTiQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", + "dev": true + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + }, + "dependencies": { + "@material/material-color-utilities": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@material/material-color-utilities/-/material-color-utilities-0.2.7.tgz", + "integrity": "sha512-0FCeqG6WvK4/Cc06F/xXMd/pv4FeisI0c1tUpBbfhA2n9Y8eZEv4Karjbmf2ZqQCPUWMrGp8A571tCjizxoTiQ==", + "dev": true + }, + "@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", + "dev": true + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true + } + } +} diff --git a/pkgs/theme/package.json b/pkgs/theme/package.json new file mode 100644 index 000000000..febd95e29 --- /dev/null +++ b/pkgs/theme/package.json @@ -0,0 +1,23 @@ +{ + "name": "@clan/colors", + "version": "1.0.0", + "description": "", + "type": "module", + "files": [ + "colors.json" + ], + "scripts": { + "typecheck": "./node_modules/.bin/tsc -p ./tsconfig.json --noEmit", + "build": "tsc --build --clean && tsc && node ./build/main.js", + "html": "tsc --build --clean && tsc && node ./build/generate.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@material/material-color-utilities": "^0.2.6", + "typescript": "^5.1.5", + "@types/node": "^20.3.2" + } +} diff --git a/pkgs/theme/shell.nix b/pkgs/theme/shell.nix new file mode 100644 index 000000000..697ce02dc --- /dev/null +++ b/pkgs/theme/shell.nix @@ -0,0 +1,24 @@ +{ fmod +, pkg +, pkgs +, clanPkgs +}: +pkgs.mkShell { + buildInputs = [ + fmod.config.floco.settings.nodePackage + ]; + shellHook = '' + ID=${pkg.built.tree} + currID=$(cat .floco/.node_modules_id 2> /dev/null) + + mkdir -p .floco + if [[ "$ID" != "$currID" || ! -d "node_modules" ]]; + then + ${pkgs.rsync}/bin/rsync -a --chmod=ug+w --delete ${pkg.built.tree}/node_modules/ ./node_modules/ + echo -n $ID > .floco/.node_modules_id + echo "floco ok: node_modules updated" + fi + + export PATH="$PATH:$(realpath ./node_modules)/.bin" + ''; +} diff --git a/pkgs/theme/src/config.ts b/pkgs/theme/src/config.ts new file mode 100644 index 000000000..2d2bb39c6 --- /dev/null +++ b/pkgs/theme/src/config.ts @@ -0,0 +1,78 @@ +import { AliasMap, BaseColors, HexString } from "./types.js"; + +export type PaletteConfig = { + baseColors: BaseColors; + tones: number[]; + aliases: AliasMap<"primary" | "secondary" | "error">; + common: { + // Black and white is always constant + // We declare this on the type level + white: "#ffffff"; + black: "#000000"; + // Some other color constants/reservation + [id: string]: HexString; + }; +}; + +export const config: PaletteConfig = { + /** All color shades that are available + * This colors are used as "key colors" to generate a tonal palette from 0 to 100 + * Steps are defined in 'tones' + */ + baseColors: { + neutral: { + keyColor: "#807788", + tones: [98], + }, + red: { + keyColor: "#e82439", + tones: [95], + }, + green: { + keyColor: "#7AC51B", + tones: [98], + }, + yellow: { + keyColor: "#E0E01F", + tones: [98], + }, + purple: { + keyColor: "#661bc5", + tones: [], + }, + blue: { + keyColor: "#1B7AC5", + tones: [95], + }, + }, + + /** Common tones to generate out of all the baseColors + * number equals to the amount of light present in the color (HCT Color Space) + */ + tones: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100], + + /** create aliases from the color palette + * + * @example + * + * primary: "blue" + * -> + * ... + * primary40 -> blue40 + * primary50 -> blue50 + * ... + */ + aliases: { + primary: "purple", + secondary: "green", + error: "red", + }, + /** some color names are reserved + * typically those colors do not change when switching theme + * or are other types of constant in the UI + */ + common: { + white: "#ffffff", + black: "#000000", + }, +}; diff --git a/pkgs/theme/src/generate.ts b/pkgs/theme/src/generate.ts new file mode 100644 index 000000000..353c8bfe6 --- /dev/null +++ b/pkgs/theme/src/generate.ts @@ -0,0 +1,46 @@ +import { writeFile } from "fs"; +import palette from "./out.json" assert { type: "json" }; +import { config } from "./config.js"; + +type PaletteFile = typeof palette; + +const html = (palette: PaletteFile): string => { + const colors = Object.keys(config.baseColors).map((baseName) => { + const colors = Object.entries(palette.ref.palette) + .filter(([name, _]) => name.includes(baseName)) + .sort((a, b) => { + return a[1].meta.color.shade - b[1].meta.color.shade; + }) + .map(([key, color]) => { + console.log({ key, color }); + return `
${key}
`; + }); + return `
${colors.join( + "\n", + )}
`; + }); + + return ` + + +Page Title + + + +${colors.join("\n")} + + + +`; +}; + +writeFile("index.html", html(palette), (err) => { + if (err) { + console.error({ err }); + } else { + console.log("Exported colors to html"); + } +}); diff --git a/pkgs/theme/src/main.ts b/pkgs/theme/src/main.ts new file mode 100644 index 000000000..16cada9b6 --- /dev/null +++ b/pkgs/theme/src/main.ts @@ -0,0 +1,182 @@ +#!usr/bin/node +import * as fs from "fs"; +import { + argbFromHex, + Hct, + hexFromArgb, +} from "@material/material-color-utilities"; +import { + AliasTokenMap, + ColorDesignToken, + ColorSet, + HexString, + RefTokenSystem, + TonalPalette, + TonalPaletteConfig, + TonalPaletteItem, +} from "./types.js"; +import { config } from "./config.js"; + +const { baseColors, tones, aliases, common } = config; + +/** Takes a color, tone and name + * If a tone is given adjust the lightning level accordingly + * + * @returns TonalPaletteItem (meta wrapper around HCT) + */ +const getTonalPaletteItem = ( + value: HexString, + name: string, + tone?: number, +): TonalPaletteItem => { + const aRGB = argbFromHex(value); + const color = Hct.fromInt(aRGB); + if (tone !== undefined) { + color.tone = tone; + } + return { + shade: color.tone, + name: `${name || color.chroma}${Math.round(color.tone)}`, + baseName: name, + value: color, + }; +}; + +/** create a flat list of the cross product from all colors and all tones. + * + * every color is mapped in the range from 0 to 100 + * with the steps configure in `config.tones' + * additionally the key color is added unmodified + * lightning levels are rounded to the next natural number to form the 'name' + * Example: + * + * "blue" x [20.1, 30.3] + * -> + * [blue20, blue30] + */ +const mkTonalPalette = + (config: TonalPaletteConfig) => + (name: string) => + (keyTone: HexString): TonalPalette => { + const { tones } = config; + const aRGB = argbFromHex(keyTone); + const HctColor = Hct.fromInt(aRGB); + const roundedTone = Math.round(HctColor.tone * 100) / 100; + + const localTones = [...tones, roundedTone]; + + return localTones.map((t) => getTonalPaletteItem(keyTone, name, t)); + }; + +/** + * Converts a PaletteItem into a hex color. (Wrapped) + * Adding meta attributes which avoids any information loss. + */ +const toDesignTokenContent = (color: TonalPaletteItem): ColorDesignToken => { + const { value } = color; + return { + type: "color", + value: hexFromArgb(value.toInt()), + meta: { + color, + date: new Date(), + }, + }; +}; + +const color: ColorSet = Object.entries(baseColors) + .map(([name, baseColor]) => ({ + name, + baseColor, + tones: mkTonalPalette({ + tones: [...tones, ...baseColor.tones].sort((a, b) => a - b), + })(name)(baseColor.keyColor), + })) + .reduce((acc, curr) => { + let currTones = curr.tones.reduce( + (o, v) => ({ + ...o, + [v.name]: toDesignTokenContent(v), + }), + {}, + ); + return { + ...acc, + ...currTones, + }; + }, {}); + +/** Generate a set of tokens from a given alias mapping + * + * @param alias A string e.g. Primary -> Blue (Primary is the alias) + * @param name A string; Basename of the referenced value (e.g. Blue) + * @param colors A set of colors + * @returns All aliases from the given color set + */ +function resolveAlias( + alias: string, + name: string, + colors: ColorSet, +): AliasTokenMap { + // All colors from the color map belonging to that single alias + // Example: + // Primary -> "blue" + // => + // [ (blue0) , (blue10) , ..., (blue100) ] + const all = Object.values(colors) + .filter((n) => n.meta.color.name.includes(name)) + .filter((n) => !n.meta.color.name.includes(".")); + + const tokens = all + .map((shade) => { + const shadeNumber = shade.meta.color.shade; + return { + name: `${alias}${Math.round(shadeNumber)}`, + value: { value: `{ref.palette.${shade.meta.color.name}}` }, + // propagate the meta attribute of the actual value + meta: shade.meta, + }; + }) + // sort by tone + .sort((a, b) => a.meta.color.value.tone - b.meta.color.value.tone) + .reduce((acc, { name, value }) => ({ ...acc, [name]: value }), {}); + return tokens; +} + +const aliasMap = Object.entries(aliases).reduce( + (prev, [key, value]) => ({ + ...prev, + ...resolveAlias(key, value, color), + }), + {}, +); + +const commonColors = Object.entries(common) + .map(([name, value]) => + toDesignTokenContent(getTonalPaletteItem(value, name)), + ) + .reduce( + (acc, val) => ({ ...acc, [val.meta.color.baseName]: val }), + {}, + ) as ColorSet; + +const toPaletteToken = (color: ColorSet): RefTokenSystem => ({ + ref: { + palette: color, + alias: aliasMap, + common: commonColors, + }, +}); + +// Dump tokens to json file +fs.writeFile( + "colors.json", + JSON.stringify(toPaletteToken(color), null, 2), + (err) => { + if (err) { + console.error({ err }); + } else { + console.log("tokens successfully exported"); + } + }, +); diff --git a/pkgs/theme/src/types.ts b/pkgs/theme/src/types.ts new file mode 100644 index 000000000..4a7a1888b --- /dev/null +++ b/pkgs/theme/src/types.ts @@ -0,0 +1,90 @@ +import { Hct } from "@material/material-color-utilities"; + +export type BaseColors = { + neutral: BaseColor; + red: BaseColor; + green: BaseColor; + yellow: BaseColor; + purple: BaseColor; + blue: BaseColor; +}; + +export type BaseColor = { + keyColor: HexString; + tones: number[]; + follows?: string; +}; + +export type ColorSet = { [key: string]: ColorDesignToken }; + +/** The resolved alias tokens + * + * @example + * { + * primary: "blue" + * ... + * } + * + */ +export type AliasMap = { + [alias in T]: keyof BaseColors; +}; + +/** The resolved alias tokens + * + * @example + * { + * primary0: "blue40" + * primary10: "blue40" + * ... + * primary100: "blue100" + * } + * + * Unfortunately My Typescript skills lack the ability to express this type any narrower :/ + */ +export type AliasTokenMap = { + [alias: string]: { value: string }; +}; + +export type TonalPaletteConfig = { + tones: number[]; +}; + +export type HexString = string; + +export type TonalPaletteItem = { + /** + * @example + * 20 + */ + shade: number; + /** + * @example + * "blue20" + */ + name: string; + /** + * @example + * "blue" + */ + baseName: string; + value: Hct; +}; +export type TonalPalette = TonalPaletteItem[]; + +export type ColorDesignToken = { + type: "color"; + value: HexString; + meta: { + color: TonalPaletteItem; + date: Date; + }; +}; + +export type RefTokenSystem = { + ref: { + palette: ColorSet; + common: ColorSet; + alias: AliasTokenMap; + }; +}; diff --git a/pkgs/theme/tsconfig.json b/pkgs/theme/tsconfig.json new file mode 100644 index 000000000..4b562c9c5 --- /dev/null +++ b/pkgs/theme/tsconfig.json @@ -0,0 +1,41 @@ +{ + "include": ["src"], + "compilerOptions": { + "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + + "lib": [ + "ESNext", + "dom" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + "module": "NodeNext" /* Specify what module code is generated. */, + "rootDir": "src" /* Specify the root folder within your source files. */, + "moduleResolution": "nodenext" /* Specify how TypeScript looks up a file from a given module specifier. */, + "resolveJsonModule": true /* Enable importing .json files. */, + "outDir": "build", + + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, + "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, + "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, + "strictBindCallApply": true /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */, + "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */, + "noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */, + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + "exactOptionalPropertyTypes": true /* Interpret optional property types as written, rather than adding 'undefined'. */, + "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, + "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, + "noUncheckedIndexedAccess": true /* Add 'undefined' to a type when accessed using an index. */, + "noImplicitOverride": true /* Ensure overriding members in derived classes are marked with an override modifier. */, + "noPropertyAccessFromIndexSignature": true /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + } +} diff --git a/pkgs/ui/nix/floco-cfg.nix b/pkgs/ui/nix/floco-cfg.nix index d8711270a..f0969327e 100644 --- a/pkgs/ui/nix/floco-cfg.nix +++ b/pkgs/ui/nix/floco-cfg.nix @@ -2,5 +2,6 @@ imports = [ ./pdefs.nix ./foverrides.nix + ../../theme/nix/floco-cfg.nix ]; } diff --git a/pkgs/ui/nix/foverrides.nix b/pkgs/ui/nix/foverrides.nix index 3d4393eb6..5fb91a34c 100644 --- a/pkgs/ui/nix/foverrides.nix +++ b/pkgs/ui/nix/foverrides.nix @@ -100,6 +100,12 @@ in optional = false; dev = true; }; + "node_modules/@clan/colors" = { + key = "@clan/colors/1.0.0"; + link = false; + optional = false; + dev = true; + }; }; }); in diff --git a/pkgs/ui/src/app/theme/themes.ts b/pkgs/ui/src/app/theme/themes.ts index edd2786ee..3da1b34d7 100644 --- a/pkgs/ui/src/app/theme/themes.ts +++ b/pkgs/ui/src/app/theme/themes.ts @@ -1,5 +1,7 @@ import { createTheme } from "@mui/material/styles"; +import colors from "@clan/colors/colors.json"; + export const darkTheme = createTheme({ breakpoints: { values: { @@ -15,6 +17,7 @@ export const darkTheme = createTheme({ }, }); +const { palette, common } = colors.ref; export const lightTheme = createTheme({ breakpoints: { values: { @@ -27,5 +30,27 @@ export const lightTheme = createTheme({ }, palette: { mode: "light", + background: { + default: common.white.value, + paper: palette.neutral98.value, + }, + primary: { + main: palette.green50.value, + }, + secondary: { + main: palette.green50.value, + }, + error: { + main: palette.red50.value, + }, + warning: { + main: palette.yellow50.value, + }, + success: { + main: palette.green50.value, + }, + info: { + main: palette.red50.value, + }, }, });