diff --git a/.changeset/angry-zebras-remember.md b/.changeset/angry-zebras-remember.md new file mode 100644 index 000000000..958213932 --- /dev/null +++ b/.changeset/angry-zebras-remember.md @@ -0,0 +1,5 @@ +--- +'svelte-ux': patch +--- + +Add styles (with daisy) as top-level export diff --git a/.changeset/chilled-dingos-sell.md b/.changeset/chilled-dingos-sell.md new file mode 100644 index 000000000..aa081efd0 --- /dev/null +++ b/.changeset/chilled-dingos-sell.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": minor +--- + +Update Settings component to expose each settings key as a component prop diff --git a/.changeset/cool-hotels-own.md b/.changeset/cool-hotels-own.md new file mode 100644 index 000000000..bc91528f8 --- /dev/null +++ b/.changeset/cool-hotels-own.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +[SelectField] Add `stepper` prop to iterate through options (like `MenuField`) diff --git a/.changeset/eight-bottles-eat.md b/.changeset/eight-bottles-eat.md new file mode 100644 index 000000000..4703329e7 --- /dev/null +++ b/.changeset/eight-bottles-eat.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +[TableOfContents] Support changing icon diff --git a/.changeset/fair-trees-sparkle.md b/.changeset/fair-trees-sparkle.md new file mode 100644 index 000000000..3b3d7d390 --- /dev/null +++ b/.changeset/fair-trees-sparkle.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +[MenuField] Expose `selected` option via prop (similar to `SelectField`) diff --git a/.changeset/for-you-sean.md b/.changeset/for-you-sean.md new file mode 100644 index 000000000..308f7b580 --- /dev/null +++ b/.changeset/for-you-sean.md @@ -0,0 +1,7 @@ +--- +'svelte-ux': minor +--- + +- Rename settings `theme` argument to `classes` +- Rename getTheme to getClasses and getComponentTheme to getComponentClasses + diff --git a/.changeset/friendly-pets-reflect.md b/.changeset/friendly-pets-reflect.md new file mode 100644 index 000000000..e86611b37 --- /dev/null +++ b/.changeset/friendly-pets-reflect.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +Add ThemeInit component to prevent flash of unstyled content when SSR is enabled diff --git a/.changeset/healthy-files-search.md b/.changeset/healthy-files-search.md new file mode 100644 index 000000000..dbd7294f6 --- /dev/null +++ b/.changeset/healthy-files-search.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +[MenuButton] Support hiding `menuIcon` and dispatch `change` event diff --git a/.changeset/light-pianos-refuse.md b/.changeset/light-pianos-refuse.md new file mode 100644 index 000000000..015e51aca --- /dev/null +++ b/.changeset/light-pianos-refuse.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +Rename `ThemeButton` to `ThemeSelect` diff --git a/.changeset/light-ways-dress.md b/.changeset/light-ways-dress.md new file mode 100644 index 000000000..1e024620a --- /dev/null +++ b/.changeset/light-ways-dress.md @@ -0,0 +1,5 @@ +--- +'svelte-ux': minor +--- + +BREAKING: removed `dateDisplay()` in favor of `format()` diff --git a/.changeset/modern-pumpkins-march.md b/.changeset/modern-pumpkins-march.md new file mode 100644 index 000000000..3a65d7ac4 --- /dev/null +++ b/.changeset/modern-pumpkins-march.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +Add a store to manage the current theme diff --git a/.changeset/ninety-carpets-cross.md b/.changeset/ninety-carpets-cross.md new file mode 100644 index 000000000..04b6556c5 --- /dev/null +++ b/.changeset/ninety-carpets-cross.md @@ -0,0 +1,5 @@ +--- +'svelte-ux': patch +--- + +add locale management of date leveraging intl diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 000000000..92652bace --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,31 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "create-svelte-ux": "0.2.1", + "svelte-ux": "0.57.1" + }, + "changesets": [ + "angry-zebras-remember", + "chilled-dingos-sell", + "cool-hotels-own", + "fair-trees-sparkle", + "for-you-sean", + "friendly-pets-reflect", + "light-pianos-refuse", + "light-ways-dress", + "modern-pumpkins-march", + "ninety-carpets-cross", + "quick-avocados-hope", + "quick-carrots-grab", + "rare-flowers-flash", + "selfish-hounds-dance", + "shiny-hornets-study", + "shy-peaches-ring", + "sixty-walls-rest", + "strong-flies-provide", + "wicked-melons-fold", + "yellow-nails-vanish", + "yellow-oranges-fly" + ] +} diff --git a/.changeset/quick-carrots-grab.md b/.changeset/quick-carrots-grab.md new file mode 100644 index 000000000..e59206ed5 --- /dev/null +++ b/.changeset/quick-carrots-grab.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": minor +--- + +Add theme selection/creation page and simplify loading themes diff --git a/.changeset/rare-flowers-flash.md b/.changeset/rare-flowers-flash.md new file mode 100644 index 000000000..ab7149d95 --- /dev/null +++ b/.changeset/rare-flowers-flash.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +Map Skeleton themes to Svelte UX themes diff --git a/.changeset/selfish-hounds-dance.md b/.changeset/selfish-hounds-dance.md new file mode 100644 index 000000000..467dc5b31 --- /dev/null +++ b/.changeset/selfish-hounds-dance.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +[SelectField] Fix toggling display of options menu using toggleIcon. Support hiding toggleIcon (`<SelectField toggleIcon={null} /> diff --git a/.changeset/sixty-walls-rest.md b/.changeset/sixty-walls-rest.md new file mode 100644 index 000000000..61b681ddb --- /dev/null +++ b/.changeset/sixty-walls-rest.md @@ -0,0 +1,6 @@ +--- +"svelte-ux": minor +--- + +- Add locale settings to settings object, and allow dynamically changing the current locale. +- Move format function to be a store on the settings object, which updates when the locale changes. diff --git a/.changeset/strong-flies-provide.md b/.changeset/strong-flies-provide.md new file mode 100644 index 000000000..92c7c9f5e --- /dev/null +++ b/.changeset/strong-flies-provide.md @@ -0,0 +1,5 @@ +--- +'svelte-ux': minor +--- + +Support `ux.themes` tailwind config, including Daisy UI diff --git a/.changeset/tidy-gifts-yawn.md b/.changeset/tidy-gifts-yawn.md new file mode 100644 index 000000000..3443e24ff --- /dev/null +++ b/.changeset/tidy-gifts-yawn.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +[Popover|Menu|popover] Support `resize` width or height only diff --git a/.changeset/wicked-melons-fold.md b/.changeset/wicked-melons-fold.md new file mode 100644 index 000000000..6c38d2cc1 --- /dev/null +++ b/.changeset/wicked-melons-fold.md @@ -0,0 +1,5 @@ +--- +"svelte-ux": patch +--- + +Add `ThemeSwitch` component to toggle between light/dark theme diff --git a/.changeset/yellow-nails-vanish.md b/.changeset/yellow-nails-vanish.md new file mode 100644 index 000000000..863f8fdcb --- /dev/null +++ b/.changeset/yellow-nails-vanish.md @@ -0,0 +1,5 @@ +--- +'svelte-ux': minor +--- + +Rename `cssVars` action to `styleVars` and do not prefix properties with `--` by default (more flexible) diff --git a/.changeset/yellow-oranges-fly.md b/.changeset/yellow-oranges-fly.md new file mode 100644 index 000000000..e1e3126c2 --- /dev/null +++ b/.changeset/yellow-oranges-fly.md @@ -0,0 +1,6 @@ +--- +'create-svelte-ux': minor +'svelte-ux': minor +--- + +Theme support diff --git a/.gitignore b/.gitignore index d3f118eb4..5535d8867 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ coverage/ .idea/ .svelte-kit/ .env +.DS_Store test-* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index ae7544dd0..5541e3775 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,14 @@ { "singleQuote": true, "printWidth": 100, - "trailingComma": "es5" + "trailingComma": "es5", + "plugins": ["prettier-plugin-svelte"], + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + } + ] } diff --git a/README.md b/README.md index f9bd09131..2b9b81372 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@  [](https://github.com/techniq/svelte-ux/actions/workflows/ci.yml) [](https://www.npmjs.com/package/svelte-ux) - +[](https://www.npmjs.com/package/svelte-ux) [](https://www.sveltelab.dev/?provider=github&owner=techniq&repo=svelte-ux&branch=main&path=%2Fpackages%2Fcreate-svelte-ux%2Ftemplates%2Fstarter) [](https://stackblitz.com/github/techniq/svelte-ux/tree/main/packages/create-svelte-ux/templates/starter) [](https://codesandbox.io/p/sandbox/github/techniq/svelte-ux/tree/main/packages/create-svelte-ux/templates/starter) diff --git a/packages/create-svelte-ux/CHANGELOG.md b/packages/create-svelte-ux/CHANGELOG.md index 1fac8d9b7..9405fda5f 100644 --- a/packages/create-svelte-ux/CHANGELOG.md +++ b/packages/create-svelte-ux/CHANGELOG.md @@ -1,5 +1,11 @@ # create-svelte-ux +## 0.3.0-next.0 + +### Minor Changes + +- Theme support ([#146](https://github.com/techniq/svelte-ux/pull/146)) + ## 0.2.1 ### Patch Changes diff --git a/packages/create-svelte-ux/package.json b/packages/create-svelte-ux/package.json index 03a0e2f54..8bcc0c693 100644 --- a/packages/create-svelte-ux/package.json +++ b/packages/create-svelte-ux/package.json @@ -1,6 +1,6 @@ { "name": "create-svelte-ux", - "version": "0.2.1", + "version": "0.3.0-next.0", "description": "A CLI for creating new Svelte UX projects", "repository": { "type": "git", @@ -18,12 +18,12 @@ }, "dependencies": { "@clack/prompts": "^0.7.0", - "@kitql/helpers": "^0.8.3", + "@kitql/helpers": "^0.8.8", "commander": "^11.1.0" }, "devDependencies": { - "@types/node": "^20.9.2", - "prettier": "^3.1.0" + "@types/node": "^20.10.6", + "prettier": "^3.1.1" }, "files": [ "fragments", diff --git a/packages/create-svelte-ux/templates/layerchart/src/routes/+layout.svelte b/packages/create-svelte-ux/templates/layerchart/src/routes/+layout.svelte index 53c3f6f7e..f4a92066d 100644 --- a/packages/create-svelte-ux/templates/layerchart/src/routes/+layout.svelte +++ b/packages/create-svelte-ux/templates/layerchart/src/routes/+layout.svelte @@ -5,8 +5,8 @@ import '../app.postcss'; settings({ - theme:{ - AppBar: 'bg-accent-500 text-white shadow-md', + classes: { + AppBar: 'bg-primary text-white shadow-md', AppLayout: { nav: 'bg-neutral-800' }, diff --git a/packages/create-svelte-ux/templates/layerchart/src/routes/+page.svelte b/packages/create-svelte-ux/templates/layerchart/src/routes/+page.svelte index 0d2ccdd74..ca3f9c2b2 100644 --- a/packages/create-svelte-ux/templates/layerchart/src/routes/+page.svelte +++ b/packages/create-svelte-ux/templates/layerchart/src/routes/+page.svelte @@ -9,7 +9,7 @@ href="https://svelte-ux.techniq.dev" target="_blank" variant="fill-light" - color="accent" + color="primary" > Documentation </Button> @@ -17,7 +17,7 @@ href="https://svelte-ux.techniq.dev/customization" target="_blank" variant="fill-light" - color="accent" + color="primary" > Customization </Button> diff --git a/packages/create-svelte-ux/templates/layerchart/src/routes/chart/+page.svelte b/packages/create-svelte-ux/templates/layerchart/src/routes/chart/+page.svelte index 277eabe17..85d199a07 100644 --- a/packages/create-svelte-ux/templates/layerchart/src/routes/chart/+page.svelte +++ b/packages/create-svelte-ux/templates/layerchart/src/routes/chart/+page.svelte @@ -22,7 +22,7 @@ <Svg> <Axis placement="left" grid rule /> <Axis placement="bottom" format={(d) => format(d, PeriodType.Day, 'short')} rule /> - <Area line={{ class: 'stroke-2 stroke-accent-500' }} class="fill-accent-500/30" /> + <Area line={{ class: 'stroke-2 stroke-primary' }} class="fill-primary/30" /> <Highlight points lines /> </Svg> diff --git a/packages/create-svelte-ux/templates/layerchart/tailwind.config.cjs b/packages/create-svelte-ux/templates/layerchart/tailwind.config.cjs index 9ddbe378d..962e73513 100644 --- a/packages/create-svelte-ux/templates/layerchart/tailwind.config.cjs +++ b/packages/create-svelte-ux/templates/layerchart/tailwind.config.cjs @@ -9,11 +9,7 @@ const config = { './node_modules/layerchart/**/*.{svelte,js}' ], theme: { - extend: { - colors: { - accent: colors.blue - } - } + extend: {} }, variants: { extend: {} diff --git a/packages/create-svelte-ux/templates/minimal/tailwind.config.cjs b/packages/create-svelte-ux/templates/minimal/tailwind.config.cjs index 200063ec9..9702b2b4f 100644 --- a/packages/create-svelte-ux/templates/minimal/tailwind.config.cjs +++ b/packages/create-svelte-ux/templates/minimal/tailwind.config.cjs @@ -5,11 +5,7 @@ const svelte_ux = require('svelte-ux/plugins/tailwind.cjs'); const config = { content: ['./src/**/*.{html,svelte}', './node_modules/svelte-ux/**/*.{svelte,js}'], theme: { - extend: { - colors: { - accent: colors.blue - } - } + extend: {} }, variants: { extend: {} diff --git a/packages/create-svelte-ux/templates/starter/src/routes/+layout.svelte b/packages/create-svelte-ux/templates/starter/src/routes/+layout.svelte index d68d9c3d0..cdf1cd426 100644 --- a/packages/create-svelte-ux/templates/starter/src/routes/+layout.svelte +++ b/packages/create-svelte-ux/templates/starter/src/routes/+layout.svelte @@ -5,8 +5,8 @@ import '../app.postcss'; settings({ - theme:{ - AppBar: 'bg-accent-500 text-white shadow-md', + classes: { + AppBar: 'bg-primary text-white shadow-md', AppLayout: { nav: 'bg-neutral-800' }, diff --git a/packages/create-svelte-ux/templates/starter/src/routes/+page.svelte b/packages/create-svelte-ux/templates/starter/src/routes/+page.svelte index 0d2ccdd74..ca3f9c2b2 100644 --- a/packages/create-svelte-ux/templates/starter/src/routes/+page.svelte +++ b/packages/create-svelte-ux/templates/starter/src/routes/+page.svelte @@ -9,7 +9,7 @@ href="https://svelte-ux.techniq.dev" target="_blank" variant="fill-light" - color="accent" + color="primary" > Documentation </Button> @@ -17,7 +17,7 @@ href="https://svelte-ux.techniq.dev/customization" target="_blank" variant="fill-light" - color="accent" + color="primary" > Customization </Button> diff --git a/packages/create-svelte-ux/templates/starter/tailwind.config.cjs b/packages/create-svelte-ux/templates/starter/tailwind.config.cjs index 200063ec9..9702b2b4f 100644 --- a/packages/create-svelte-ux/templates/starter/tailwind.config.cjs +++ b/packages/create-svelte-ux/templates/starter/tailwind.config.cjs @@ -5,11 +5,7 @@ const svelte_ux = require('svelte-ux/plugins/tailwind.cjs'); const config = { content: ['./src/**/*.{html,svelte}', './node_modules/svelte-ux/**/*.{svelte,js}'], theme: { - extend: { - colors: { - accent: colors.blue - } - } + extend: {} }, variants: { extend: {} diff --git a/packages/svelte-ux/CHANGELOG.md b/packages/svelte-ux/CHANGELOG.md index b773152fc..4fb075753 100644 --- a/packages/svelte-ux/CHANGELOG.md +++ b/packages/svelte-ux/CHANGELOG.md @@ -1,5 +1,73 @@ # svelte-ux +## 0.58.0-next.9 + +### Minor Changes + +- Update Settings component to expose each settings key as a component prop ([#167](https://github.com/techniq/svelte-ux/pull/167)) + +- Add theme selection/creation page and simplify loading themes ([#192](https://github.com/techniq/svelte-ux/pull/192)) + +- - Add locale settings to settings object, and allow dynamically changing the current locale. ([#202](https://github.com/techniq/svelte-ux/pull/202)) + - Move format function to be a store on the settings object, which updates when the locale changes. + +- Rename `cssVars` action to `styleVars` and do not prefix properties with `--` by default (more flexible) ([#192](https://github.com/techniq/svelte-ux/pull/192)) + +### Patch Changes + +- [SelectField] Add `stepper` prop to iterate through options (like `MenuField`) ([#192](https://github.com/techniq/svelte-ux/pull/192)) + +- [MenuField] Expose `selected` option via prop (similar to `SelectField`) ([#192](https://github.com/techniq/svelte-ux/pull/192)) + +- Rename `ThemeButton` to `ThemeSelect` ([#167](https://github.com/techniq/svelte-ux/pull/167)) + +- Map Skeleton themes to Svelte UX themes ([#167](https://github.com/techniq/svelte-ux/pull/167)) + +- [SelectField] Fix toggling display of options menu using toggleIcon. Support hiding toggleIcon (`<SelectField toggleIcon={null} /> ([#192](https://github.com/techniq/svelte-ux/pull/192)) + +- Prevent cursor jumping around when backspacing near a decimal point in a number TextField ([#178](https://github.com/techniq/svelte-ux/pull/178)) + +- Update AppLayout nav to only show scrollbar when overflown (Windows, Mac with "Show scrollbars: always) ([#171](https://github.com/techniq/svelte-ux/pull/171)) + +- Add `ThemeSwitch` component to toggle between light/dark theme ([#167](https://github.com/techniq/svelte-ux/pull/167)) + +## 0.58.0-next.8 + +### Minor Changes + +- - Rename settings `theme` argument to `classes` ([#172](https://github.com/techniq/svelte-ux/pull/172)) + - Rename getTheme to getClasses and getComponentTheme to getComponentClasses + +- BREAKING: removed `dateDisplay()` in favor of `format()` ([#137](https://github.com/techniq/svelte-ux/pull/137)) + +### Patch Changes + +- Add ThemeInit component to prevent flash of unstyled content when SSR is enabled ([#176](https://github.com/techniq/svelte-ux/pull/176)) + +- Add a store to manage the current theme ([#174](https://github.com/techniq/svelte-ux/pull/174)) + +- add locale management of date leveraging intl ([#137](https://github.com/techniq/svelte-ux/pull/137)) + +## 0.58.0-next.2 + +### Patch Changes + +- Add styles (with daisy) as top-level export ([#146](https://github.com/techniq/svelte-ux/pull/146)) + +## 0.58.0-next.1 + +### Minor Changes + +- Support `ux.themes` tailwind config, including Daisy UI ([#146](https://github.com/techniq/svelte-ux/pull/146)) + +## 0.58.0-next.0 + +### Minor Changes + +- Removes SelectList. Updates SelectField features to support SelectList's use case via property/attribute overrides. Updates QuickSearch to use SelectField. Defines MenuOption type & updates MenuField & SelectField to use it; this results in renaming of SelectField options' `name` field to become `label`, standardizing the API across the two. Also adds `activeOptionIcon` to SelectField so users can opt-in to dynamically updating the field icon based on the selected option. Also fixed a bug with the `scrollIntoView` action related to its `onlyIfNeeded` flag. ([#127](https://github.com/techniq/svelte-ux/pull/127)) + +- Theme support ([#146](https://github.com/techniq/svelte-ux/pull/146)) + ## 0.57.1 ### Patch Changes diff --git a/packages/svelte-ux/package.json b/packages/svelte-ux/package.json index 8f5121e8c..7d7c05730 100644 --- a/packages/svelte-ux/package.json +++ b/packages/svelte-ux/package.json @@ -4,7 +4,7 @@ "author": "Sean Lynch <techniq35@gmail.com>", "license": "MIT", "repository": "techniq/svelte-ux", - "version": "0.57.2", + "version": "0.58.0-next.9", "scripts": { "dev": "vite dev", "build": "vite build", @@ -13,66 +13,68 @@ "prepublishOnly": "svelte-package", "check": "svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", - "test:unit": "vitest", + "test:unit": "TZ=UTC+4 vitest --coverage", "lint": "prettier --ignore-path ../../.gitignore --check .", "format": "prettier --ignore-path ../../.gitignore --write .", "typedoc": "typedoc", "prepare": "svelte-kit sync" }, "devDependencies": { + "@changesets/cli": "^2.27.1", + "@fortawesome/free-solid-svg-icons": "^6.2.1", + "@skeletonlabs/tw-plugin": "^0.3.1", "@sveltejs/adapter-auto": "^2.1.1", - "@sveltejs/kit": "^1.27.6", - "@sveltejs/package": "^2.2.2", + "@sveltejs/kit": "^1.30.3", + "@sveltejs/package": "^2.2.5", "@tailwindcss/typography": "^0.5.10", + "@types/culori": "^2.0.4", "@types/d3-array": "^3.2.1", "@types/d3-scale": "^4.0.8", - "@types/lodash-es": "^4.17.11", + "@types/lodash-es": "^4.17.12", "@types/marked": "^6.0.0", "@types/prismjs": "^1.26.3", + "@vitest/coverage-v8": "^0.34.6", "autoprefixer": "^10.4.16", + "daisyui": "^4.5.0", "execa": "^8.0.1", "marked": "^10.0.0", "mdsvex": "^0.11.0", - "prettier": "^3.1.0", - "prettier-plugin-svelte": "^3.1.0", - "sveld": "^0.19.1", - "svelte": "^4.2.7", - "svelte-check": "^3.6.0", - "svelte-preprocess": "^5.1.0", - "svelte2tsx": "^0.6.25", - "tailwindcss": "^3.3.5", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "rehype-slug": "^6.0.0", + "svelte": "^4.2.8", + "svelte-check": "^3.6.2", + "svelte-preprocess": "^5.1.3", + "svelte2tsx": "^0.6.27", + "tailwindcss": "^3.4.0", "tslib": "^2.6.2", "typedoc-json-parser": "^9.0.1", - "typescript": "^5.2.2", + "typescript": "^5.3.3", "unist-util-visit": "^5.0.0", - "vite": "^4.5.0", + "vite": "^4.5.1", "vitest": "^0.33.0" }, "type": "module", "dependencies": { - "@changesets/cli": "^2.26.2", "@floating-ui/dom": "^1.5.3", - "@fortawesome/fontawesome-common-types": "^6.4.2", - "clsx": "^2.0.0", + "@fortawesome/fontawesome-common-types": "^6.5.1", + "@mdi/js": "^7.0.96", + "clsx": "^2.1.0", + "culori": "^3.3.0", "d3-array": "^3.2.4", "d3-scale": "^4.0.2", - "d3-time": "^3.1.0", - "date-fns": "^2.30.0", + "date-fns": "^3.0.6", "immer": "^10.0.3", "lodash-es": "^4.17.21", - "posthog-js": "^1.95.1", - "rehype-slug": "^6.0.0", - "tailwind-merge": "^2.0.0", - "zod": "^3.22.4" - }, - "peerDependencies": { - "@fortawesome/free-regular-svg-icons": "^6.2.1", - "@fortawesome/free-solid-svg-icons": "^6.2.1", - "@mdi/js": "^7.0.96", + "posthog-js": "^1.96.1", "prism-svelte": "^0.5.0", "prism-themes": "^1.9.0", "prismjs": "^1.29.0", - "sveld": "^0.19.0", + "sveld": "^0.19.1", + "tailwind-merge": "^2.2.0", + "zod": "^3.22.4" + }, + "peerDependencies": { "svelte": "^3.56.0 || ^4.0.0" }, "main": "./dist/index.js", @@ -85,7 +87,8 @@ "types": "./dist/utils/*.d.ts", "svelte": "./dist/utils/*.js" }, - "./plugins/*": "./dist/plugins/*" + "./plugins/*": "./dist/plugins/*", + "./styles/*": "./dist/styles/*" }, "files": [ "dist" diff --git a/packages/svelte-ux/src/docs/Blockquote.svelte b/packages/svelte-ux/src/docs/Blockquote.svelte index 5caf8d41f..1131a3bcb 100644 --- a/packages/svelte-ux/src/docs/Blockquote.svelte +++ b/packages/svelte-ux/src/docs/Blockquote.svelte @@ -1,11 +1,15 @@ <script lang="ts"> import { mdiInformation } from '@mdi/js'; import Icon from '../lib/components/Icon.svelte'; + import { cls } from '$lib/utils/styles'; </script> <div - class="bg-accent-500/10 border-l-[6px] border-l-accent-500 border-accent-500/30 text-accent-900 px-4 py-2 border my-4 rounded flex items-center gap-2 text-sm" + class={cls( + 'bg-primary/10 border border-l-[6px] border-primary/30 border-l-primary text-primary px-4 py-2 my-4 rounded flex items-center gap-2 text-sm', + '[&>a]:font-medium [&>a]:underline [&>a]:decoration-dashed [&>a]:decoration-primary/50 [&>a]:underline-offset-2' + )} > - <Icon data={mdiInformation} class="text-accent-500" /> + <Icon data={mdiInformation} class="text-primary" /> <slot /> </div> diff --git a/packages/svelte-ux/src/docs/Link.svelte b/packages/svelte-ux/src/docs/Link.svelte index 276343a05..eec570e72 100644 --- a/packages/svelte-ux/src/docs/Link.svelte +++ b/packages/svelte-ux/src/docs/Link.svelte @@ -1,3 +1,3 @@ -<a class="text-accent-500 font-medium" {...$$restProps}> +<a class="text-primary font-medium" {...$$restProps}> <slot /> </a> diff --git a/packages/svelte-ux/src/docs/ViewSourceButton.svelte b/packages/svelte-ux/src/docs/ViewSourceButton.svelte index 28b6b47bd..7a2f2948d 100644 --- a/packages/svelte-ux/src/docs/ViewSourceButton.svelte +++ b/packages/svelte-ux/src/docs/ViewSourceButton.svelte @@ -14,7 +14,7 @@ {#if source} <Toggle let:on={open} let:toggle> - <Button {icon} on:click={toggle} variant="fill-light" color="accent" size="sm">{label}</Button> + <Button {icon} on:click={toggle} variant="fill-light" color="primary" size="sm">{label}</Button> <Dialog {open} on:close={toggle} @@ -23,11 +23,11 @@ <div class="grid grid-cols-[1fr,auto] gap-3 items-center p-4"> <div class="overflow-auto"> <div class="text-lg font-semibold">{label}</div> - <div class="text-xs text-black/50 truncate">{href}</div> + <div class="text-xs text-surface-content/50 truncate">{href}</div> </div> {#if href} - <Button icon={mdiGithub} variant="fill-light" color="accent" {href} target="_blank"> + <Button icon={mdiGithub} variant="fill-light" color="primary" {href} target="_blank"> View on Github </Button> {/if} @@ -38,13 +38,13 @@ </div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> {:else if href} <Tooltip title="Edit this page"> - <Button {icon} {href} target="_blank" variant="fill-light" color="accent" size="sm"> + <Button {icon} {href} target="_blank" variant="fill-light" color="primary" size="sm"> {label} </Button> </Tooltip> diff --git a/packages/svelte-ux/src/lib/actions/dataBackground.ts b/packages/svelte-ux/src/lib/actions/dataBackground.ts index fad06ca3a..23b5e8012 100644 --- a/packages/svelte-ux/src/lib/actions/dataBackground.ts +++ b/packages/svelte-ux/src/lib/actions/dataBackground.ts @@ -95,8 +95,8 @@ export const dataBackground: Action<HTMLElement, DataBackgroundOptions> = (node, linear-gradient( to right, transparent var(--baseline), - #999 var(--baseline), - #999 calc(var(--baseline) + 1px), + currentColor var(--baseline), + currentColor calc(var(--baseline) + 1px), transparent 0%, transparent 100% ), diff --git a/packages/svelte-ux/src/lib/actions/index.ts b/packages/svelte-ux/src/lib/actions/index.ts index f698df4b2..ff4bb0486 100644 --- a/packages/svelte-ux/src/lib/actions/index.ts +++ b/packages/svelte-ux/src/lib/actions/index.ts @@ -1,4 +1,3 @@ -export * from './cssVars'; export * from './dataBackground'; export * from './input'; export * from './layout'; @@ -9,4 +8,5 @@ export * from './portal'; export * from './scroll'; export * from './spotlight'; export * from './sticky'; +export * from './styleProps'; export * from './table'; diff --git a/packages/svelte-ux/src/lib/actions/popover.ts b/packages/svelte-ux/src/lib/actions/popover.ts index a731111e9..4cd84d324 100644 --- a/packages/svelte-ux/src/lib/actions/popover.ts +++ b/packages/svelte-ux/src/lib/actions/popover.ts @@ -14,14 +14,14 @@ import { import { portal } from './portal'; -type PopoverOptions = { +export type PopoverOptions = { anchorEl?: HTMLElement; placement?: Placement; offset?: number; padding?: number; autoPlacement?: boolean; matchWidth?: boolean; - resize?: boolean; + resize?: boolean | 'width' | 'height'; }; export const popover: Action<HTMLElement, PopoverOptions> = (node, options) => { @@ -53,8 +53,12 @@ export const popover: Action<HTMLElement, PopoverOptions> = (node, options) => { padding: options?.padding, apply({ availableWidth, availableHeight, elements }) { Object.assign(elements.floating.style, { - maxWidth: `${availableWidth}px`, - maxHeight: `${availableHeight}px`, + ...((options?.resize === true || options?.resize === 'width') && { + maxWidth: `${availableWidth}px`, + }), + ...((options?.resize === true || options?.resize === 'height') && { + maxHeight: `${availableHeight}px`, + }), }); }, }), diff --git a/packages/svelte-ux/src/lib/actions/cssVars.ts b/packages/svelte-ux/src/lib/actions/styleProps.ts similarity index 70% rename from packages/svelte-ux/src/lib/actions/cssVars.ts rename to packages/svelte-ux/src/lib/actions/styleProps.ts index f2f698b87..539ea95cc 100644 --- a/packages/svelte-ux/src/lib/actions/cssVars.ts +++ b/packages/svelte-ux/src/lib/actions/styleProps.ts @@ -2,12 +2,12 @@ import type { Action } from 'svelte/action'; type CSSProps = { [key: string]: string | number | boolean | null | undefined }; -export const cssVars: Action<HTMLElement, CSSProps> = (node, props) => { +export const styleProps: Action<HTMLElement, CSSProps> = (node, props) => { Object.entries(props ?? {}).forEach(([key, value]) => { // Ignore if null or undefined if (value != null) { value = typeof value === 'boolean' ? (value ? 1 : 0) : value; - node.style.setProperty(`--${key}`, `${value}`); + node.style.setProperty(key, `${value}`); } }); @@ -17,13 +17,13 @@ export const cssVars: Action<HTMLElement, CSSProps> = (node, props) => { update(newProps: CSSProps) { const newKeys = Object.keys(newProps); Object.keys(lastProps) - .filter((name) => !newKeys.includes(name)) - .forEach((name) => node.style.removeProperty(`--${name}`)); + .filter((key) => !newKeys.includes(key)) + .forEach((key) => node.style.removeProperty(key)); Object.entries(newProps).forEach(([key, value]) => { // Ignore if null or undefined if (value != null) { - node.style.setProperty(`--${key}`, `${value}`); + node.style.setProperty(key, `${value}`); } if (props) { delete props[key]; diff --git a/packages/svelte-ux/src/lib/components/ApiDocs.svelte b/packages/svelte-ux/src/lib/components/ApiDocs.svelte index 938f55f9c..ab69bcfe6 100644 --- a/packages/svelte-ux/src/lib/components/ApiDocs.svelte +++ b/packages/svelte-ux/src/lib/components/ApiDocs.svelte @@ -25,17 +25,19 @@ <div class="ApiDocs grid gap-8"> <div> - <h2 id="props" class="text-xs uppercase leading-8 tracking-widest text-black/50">Props</h2> - <div class="border"> + <h2 id="props" class="text-xs uppercase leading-8 tracking-widest text-surface-content/50"> + Props + </h2> + <div> {#each api.props as prop} <ListItem list="type" icon={mdiCodeBraces} - avatar={{ size: 'sm', class: 'text-xs text-white bg-accent-500' }} + avatar={{ size: 'sm', class: 'text-xs text-white bg-blue-500' }} > <div slot="title">{prop.name}</div> - <div slot="subheading" class="text-black/50 text-xs"> + <div slot="subheading" class="text-surface-content/50 text-xs"> {#if prop.description} <span class="whitespace-pre-line"> {prop.description} @@ -46,7 +48,7 @@ <div slot="actions" class="flex flex-wrap justify-end gap-1"> {#if prop.isRequired} <div - class="inline-block border bg-red-100 border-red-500 text-red-600 px-2 rounded-full text-xs" + class="inline-block border bg-red-500/10 border-red-500 text-red-600 px-2 rounded-full text-xs" > Required </div> @@ -54,7 +56,7 @@ <Tooltip title="default" offset={2}> <div - class="inline-block border bg-gray-100 border-gray-500 text-gray-600 px-2 rounded-full text-xs cursor-help" + class="inline-block border bg-gray-500/5 border-gray-500 text-gray-600 px-2 rounded-full text-xs cursor-help" > {prop.value} </div> @@ -62,7 +64,7 @@ <Tooltip title="type" offset={2}> <div - class="inline-block border bg-orange-100 border-orange-500 text-orange-600 px-2 rounded-full text-xs cursor-help" + class="inline-block border bg-orange-500/10 border-orange-500 text-orange-600 px-2 rounded-full text-xs cursor-help" > {prop.type ?? 'unknown'} </div> @@ -75,7 +77,7 @@ </div> {#if api.rest_props} - <div class="text-black/50 text-xs flex gap-2 mt-2 ml-4 items-center"> + <div class="text-surface-content/50 text-xs flex gap-2 mt-2 ml-4 items-center"> <Icon path={mdiInformationOutline} /> <span> Remaining props are passed to underlying @@ -84,7 +86,7 @@ href="/docs/components/{api.rest_props.name}#props" target="_blank" variant="none" - class="text-xs font-semibold bg-white border border-black/30 px-2 rounded-full" + class="text-xs font-semibold bg-surface-100 border px-2 rounded-full" > <{api.rest_props.name}> </Button> @@ -95,7 +97,7 @@ .name}#attributes" target="_blank" variant="none" - class="text-xs font-semibold bg-white border border-black/30 px-2 rounded-full" + class="text-xs font-semibold bg-surface-100 border px-2 rounded-full" > <{api.rest_props.name}> </Button> @@ -107,8 +109,10 @@ </div> <div> - <h2 id="slots" class="text-xs uppercase leading-8 tracking-widest text-black/50">Slots</h2> - <div class="border"> + <h2 id="slots" class="text-xs uppercase leading-8 tracking-widest text-surface-content/50"> + Slots + </h2> + <div> {#each api.slots as slot} <ListItem list="type" @@ -123,7 +127,7 @@ {/if} </div> - <div slot="subheading" class="text-black/50 text-xs"> + <div slot="subheading" class="text-surface-content/50 text-xs"> {slot.description ?? ''} </div> @@ -132,7 +136,7 @@ {#each parseSlotProps(slot.slot_props) as { key, value }} <Tooltip title="slot prop" offset={2}> <div - class="inline-block border bg-orange-100 border-orange-500 text-orange-600 px-2 rounded-full text-xs cursor-help" + class="inline-block border bg-orange-500/10 border-orange-500 text-orange-600 px-2 rounded-full text-xs cursor-help" > {key}: {value} </div> @@ -148,8 +152,10 @@ </div> <div> - <h2 id="events" class="text-xs uppercase leading-8 tracking-widest text-black/40">Events</h2> - <div class="border"> + <h2 id="events" class="text-xs uppercase leading-8 tracking-widest text-surface-content/50"> + Events + </h2> + <div> {#each api.events as event} <ListItem list="type" @@ -161,13 +167,13 @@ <div slot="actions" class="flex flex-wrap justify-end gap-1"> {#if event.element != null} <div - class="inline-block border bg-gray-100 border-gray-500 text-gray-600 px-2 rounded-full text-xs" + class="inline-block border bg-gray-500/5 border-gray-500 text-gray-600 px-2 rounded-full text-xs" > {event.element} </div> {/if} <div - class="inline-block border bg-orange-100 border-orange-500 text-orange-600 px-2 rounded-full text-xs" + class="inline-block border bg-orange-500/10 border-orange-500 text-orange-600 px-2 rounded-full text-xs" > {event.type} </div> @@ -180,19 +186,22 @@ </div> <div> - <h2 id="module_exports" class="text-xs uppercase leading-8 tracking-widest text-black/50"> + <h2 + id="module_exports" + class="text-xs uppercase leading-8 tracking-widest text-surface-content/50" + > Module Exports </h2> - <div class="border"> + <div> {#each api.moduleExports as prop} <ListItem list="type" icon={mdiCodeBraces} - avatar={{ size: 'sm', class: 'text-xs text-white bg-accent-500' }} + avatar={{ size: 'sm', class: 'text-xs text-white bg-blue-500' }} > <div slot="title">{prop.name}</div> - <div slot="subheading" class="text-black/50 text-xs"> + <div slot="subheading" class="text-surface-content/50 text-xs"> {#if prop.description} <span class="whitespace-pre-line"> {prop.description} @@ -203,7 +212,7 @@ <div slot="actions" class="flex flex-wrap justify-end gap-1"> {#if prop.isRequired} <div - class="inline-block border bg-red-100 border-red-500 text-red-600 px-2 rounded-full text-xs" + class="inline-block border bg-red-500/10 border-red-500 text-red-600 px-2 rounded-full text-xs" > Required </div> @@ -211,7 +220,7 @@ <Tooltip title="value" offset={2}> <div - class="inline-block border bg-gray-100 border-gray-500 text-gray-600 px-2 rounded-full text-xs cursor-help" + class="inline-block border bg-gray-500/5 border-gray-500 text-gray-600 px-2 rounded-full text-xs cursor-help" > {prop.value} </div> @@ -219,7 +228,7 @@ <Tooltip title="type" offset={2}> <div - class="inline-block border bg-orange-100 border-orange-500 text-orange-600 px-2 rounded-full text-xs cursor-help" + class="inline-block border bg-orange-500/10 border-orange-500 text-orange-600 px-2 rounded-full text-xs cursor-help" > {prop.type ?? 'unknown'} </div> diff --git a/packages/svelte-ux/src/lib/components/AppBar.svelte b/packages/svelte-ux/src/lib/components/AppBar.svelte index 9995b9afc..c3b6f7f6d 100644 --- a/packages/svelte-ux/src/lib/components/AppBar.svelte +++ b/packages/svelte-ux/src/lib/components/AppBar.svelte @@ -6,7 +6,7 @@ import Button from './Button.svelte'; import { browser } from '../utils/env'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let title: string | number | Array<string | number> = ''; @@ -15,7 +15,7 @@ */ export let head = true; - const theme = getComponentTheme('AppBar'); + const settingsClasses = getComponentClasses('AppBar'); $: titleString = Array.isArray(title) ? title.filter((x) => x).join(' › ') : title.toString(); @@ -26,13 +26,18 @@ </script> <header - class={cls('AppBar', 'px-4 flex items-center relative z-50', theme.root, $$restProps.class)} + class={cls( + 'AppBar', + 'px-4 flex items-center relative z-50', + settingsClasses.root, + $$restProps.class + )} > <Button icon={mdiMenu} on:click={() => ($showDrawer = !$showDrawer)} class="p-3" /> {#if $$slots.title} <slot name="title" /> {:else} - <div class="ml-2 text-lg"> + <div class="ml-2 text-lg font-medium"> {#if typeof title === 'string' || typeof title === 'number'} {title} {:else} diff --git a/packages/svelte-ux/src/lib/components/AppLayout.svelte b/packages/svelte-ux/src/lib/components/AppLayout.svelte index a6f255967..5ccd04859 100644 --- a/packages/svelte-ux/src/lib/components/AppLayout.svelte +++ b/packages/svelte-ux/src/lib/components/AppLayout.svelte @@ -9,7 +9,7 @@ import { breakpoints, mdScreen } from '../stores/matchMedia'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let navWidth = 240; export let headerHeight = 64; @@ -28,7 +28,7 @@ aside?: string; nav?: string; } = {}; - const theme = getComponentTheme('AppLayout'); + const settingsClasses = getComponentClasses('AppLayout'); $: temporaryDrawer = browser ? !$mdScreen : false; </script> @@ -41,7 +41,7 @@ class={cls( 'AppLayout', 'grid grid-cols-[auto,1fr] grid-rows-[var(--headerHeight),1fr] h-screen', - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -58,11 +58,13 @@ class={cls( 'w-[var(--drawerWidth)] transition-all duration-500 overflow-hidden', temporaryDrawer && 'fixed h-full z-50 elevation-10', - theme.aside, + settingsClasses.aside, classes.aside )} > - <nav class={cls('nav h-full overflow-auto w-[var(--navWidth)]', theme.nav, classes.nav)}> + <nav + class={cls('nav h-full overflow-auto w-[var(--navWidth)]', settingsClasses.nav, classes.nav)} + > <slot name="nav" /> </nav> </aside> diff --git a/packages/svelte-ux/src/lib/components/Avatar.svelte b/packages/svelte-ux/src/lib/components/Avatar.svelte index 9864355b6..78d4ea8ac 100644 --- a/packages/svelte-ux/src/lib/components/Avatar.svelte +++ b/packages/svelte-ux/src/lib/components/Avatar.svelte @@ -1,12 +1,12 @@ <script lang="ts"> import { cls } from '../utils/styles'; import Icon from './Icon.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let size: 'sm' | 'md' | 'lg' | 'unset' = 'md'; export let icon: string | undefined = undefined; - const theme = getComponentTheme('Avatar'); + const settingsClasses = getComponentClasses('Avatar'); </script> <div @@ -18,7 +18,7 @@ md: 'w-10 h-10', lg: 'w-14 h-14', }[size], - theme.root, + settingsClasses.root, $$props.class )} > diff --git a/packages/svelte-ux/src/lib/components/Backdrop.svelte b/packages/svelte-ux/src/lib/components/Backdrop.svelte index ff13bd0da..c2ff726ac 100644 --- a/packages/svelte-ux/src/lib/components/Backdrop.svelte +++ b/packages/svelte-ux/src/lib/components/Backdrop.svelte @@ -3,22 +3,22 @@ import { portal as portalAction, type PortalOptions } from '../actions/portal'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let blur: boolean = false; export let portal: PortalOptions = false; export let fadeParams: FadeParams = { duration: 300 }; - const theme = getComponentTheme('Backdrop'); + const settingsClasses = getComponentClasses('Backdrop'); </script> <div class={cls( 'Backdrop', - 'fixed top-0 bottom-0 left-0 right-0 flex items-center justify-center bg-black/50', + 'fixed top-0 bottom-0 left-0 right-0 flex items-center justify-center bg-surface-content/50 dark:bg-surface-300/70', blur && 'backdrop-blur-sm', - theme.root, + settingsClasses.root, $$props.class )} on:keydown diff --git a/packages/svelte-ux/src/lib/components/Badge.svelte b/packages/svelte-ux/src/lib/components/Badge.svelte index f2f1ac939..39b9da4c0 100644 --- a/packages/svelte-ux/src/lib/components/Badge.svelte +++ b/packages/svelte-ux/src/lib/components/Badge.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value: number = $$slots.value ? 1 : 0; export let small = false; @@ -9,7 +9,7 @@ export let placement: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' = 'top-right'; - const theme = getComponentTheme('Badge'); + const settingsClasses = getComponentClasses('Badge'); </script> <div class="inline-grid grid-stack"> @@ -19,7 +19,7 @@ 'Badge', 'rounded-full flex items-center justify-center transform transition-transform', - !$$slots.value && 'bg-accent-500 text-white', + !$$slots.value && 'bg-primary text-primary-content', { 'self-start': placement.startsWith('top'), @@ -50,28 +50,28 @@ 'translate-x-[-10%]': !small && placement.endsWith('right'), } : circle - ? { - 'translate-y-[-10%]': small && placement.startsWith('top'), - 'translate-y-[10%]': small && placement.startsWith('bottom'), - 'translate-x-[-10%]': small && placement.endsWith('left'), - 'translate-x-[10%]': small && placement.endsWith('right'), - 'translate-y-[-20%]': !small && placement.startsWith('top'), - 'translate-y-[20%]': !small && placement.startsWith('bottom'), - 'translate-x-[-20%]': !small && placement.endsWith('left'), - 'translate-x-[20%]': !small && placement.endsWith('right'), - } - : { - '-translate-y-1/3': placement.startsWith('top'), - 'translate-y-1/3': placement.startsWith('bottom'), - '-translate-x-1/3': placement.endsWith('left'), - 'translate-x-1/3': placement.endsWith('right'), - }, + ? { + 'translate-y-[-10%]': small && placement.startsWith('top'), + 'translate-y-[10%]': small && placement.startsWith('bottom'), + 'translate-x-[-10%]': small && placement.endsWith('left'), + 'translate-x-[10%]': small && placement.endsWith('right'), + 'translate-y-[-20%]': !small && placement.startsWith('top'), + 'translate-y-[20%]': !small && placement.startsWith('bottom'), + 'translate-x-[-20%]': !small && placement.endsWith('left'), + 'translate-x-[20%]': !small && placement.endsWith('right'), + } + : { + '-translate-y-1/3': placement.startsWith('top'), + 'translate-y-1/3': placement.startsWith('bottom'), + '-translate-x-1/3': placement.endsWith('left'), + 'translate-x-1/3': placement.endsWith('right'), + }, { 'scale-0': (value ?? 0) === 0, 'scale-100': (value ?? 0) !== 0, }, - theme.root, + settingsClasses.root, $$props.class )} > diff --git a/packages/svelte-ux/src/lib/components/Breadcrumb.svelte b/packages/svelte-ux/src/lib/components/Breadcrumb.svelte index 940da75b5..8b2309d06 100644 --- a/packages/svelte-ux/src/lib/components/Breadcrumb.svelte +++ b/packages/svelte-ux/src/lib/components/Breadcrumb.svelte @@ -3,13 +3,13 @@ import Icon from './Icon.svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let items = []; export let divider: string | undefined = undefined; export let inline = false; - const theme = getComponentTheme('Breadcrumb'); + const settingsClasses = getComponentClasses('Breadcrumb'); $: displayItems = items?.filter((x) => x != null) ?? []; </script> @@ -20,7 +20,7 @@ 'Breadcrumb', inline ? 'inline-flex' : 'flex', 'items-center justify-start flex-wrap', - theme.root, + settingsClasses.root, $$props.class )} > diff --git a/packages/svelte-ux/src/lib/components/Button.svelte b/packages/svelte-ux/src/lib/components/Button.svelte index 5c53299f7..8a9520440 100644 --- a/packages/svelte-ux/src/lib/components/Button.svelte +++ b/packages/svelte-ux/src/lib/components/Button.svelte @@ -1,5 +1,4 @@ <script lang="ts"> - import type { ComponentProps } from 'svelte'; import { slide } from 'svelte/transition'; import Icon from './Icon.svelte'; @@ -7,8 +6,8 @@ import { cls } from '../utils/styles'; import { multi } from '../actions/multi'; import type { Actions } from '../actions/multi'; - import type { TailwindColors } from '$lib/types'; - import { getComponentTheme } from './theme'; + import type { ThemeColors } from '$lib/types'; + import { getComponentClasses } from './theme'; import { getButtonGroup } from './ButtonGroup.svelte'; import { asIconData, type IconInput } from '$lib/utils/icons'; @@ -33,7 +32,7 @@ | 'none' | undefined = undefined; // default in reactive groupContext below export let size: 'sm' | 'md' | 'lg' | undefined = undefined; // default in reactive groupContext below - export let color: TailwindColors | 'default' | undefined = undefined; // default in reactive groupContext below + export let color: ThemeColors | 'default' | undefined = undefined; // default in reactive groupContext below /** @type {{root?: string, icon?: string, loading?: string}} */ export let classes: { @@ -41,7 +40,7 @@ icon?: string; loading?: string; } = {}; - const theme = getComponentTheme('Button'); + const settingsClasses = getComponentClasses('Button'); // Override default from `ButtonGroup` if set const groupContext = getButtonGroup(); @@ -52,7 +51,7 @@ $: _class = cls( 'Button', - 'transition duration-200 ring-black/20', + 'transition duration-200 ring-surface-content/60', 'focus:outline-none focus-visible:ring-1', fullWidth ? 'flex w-full' : 'inline-flex', loading ? 'gap-2' : 'gap-1', @@ -84,154 +83,367 @@ text: 'p-0', none: '', }[variant ?? 'none'], + // Variant specific colors { default: { - default: 'hover:bg-black/5 ring-black/10', - accent: 'text-accent-500 hover:bg-accent-500/10 ring-accent-500/60', - red: 'text-red-500 hover:bg-red-500/10 ring-red-500/60', - orange: 'text-orange-500 hover:bg-orange-500/10 ring-orange-500/60', - amber: 'text-amber-500 hover:bg-amber-500/10 ring-amber-500/60', - yellow: 'text-yellow-500 hover:bg-yellow-500/10 ring-yellow-500/60', - lime: 'text-lime-500 hover:bg-lime-500/10 ring-lime-500/60', - green: 'text-green-500 hover:bg-green-500/10 ring-green-500/60', - emerald: 'text-emerald-500 hover:bg-emerald-500/10 ring-emerald-500/60', - teal: 'text-teal-500 hover:bg-teal-500/10 ring-teal-500/60', - cyan: 'text-cyan-500 hover:bg-cyan-500/10 ring-cyan-500/60', - sky: 'text-sky-500 hover:bg-sky-500/10 ring-sky-500/60', - blue: 'text-blue-500 hover:bg-blue-500/10 ring-blue-500/60', - indigo: 'text-indigo-500 hover:bg-indigo-500/10 ring-indigo-500/60', - violet: 'text-violet-500 hover:bg-violet-500/10 ring-violet-500/60', - purple: 'text-purple-500 hover:bg-purple-500/10 ring-purple-500/60', - fuchsia: 'text-fuchsia-500 hover:bg-fuchsia-500/10 ring-fuchsia-500/60', - pink: 'text-pink-500 hover:bg-pink-500/10 ring-pink-500/60', - rose: 'text-rose-500 hover:bg-rose-500/10 ring-rose-500/60', - gray: 'text-gray-500 hover:bg-gray-500/10 ring-gray-500/60', + default: [ + 'hover:[--bg-color:theme(colors.surface-content/10%)]', + // '[--text-color:theme(colors.surface-content)]', // inherit + '[--ring-color:theme(colors.surface-content/60%)]', + ], + primary: [ + 'hover:[--bg-color:theme(colors.primary/10%)]', + '[--text-color:theme(colors.primary)]', + '[--ring-color:theme(colors.primary/60%)]', + ], + secondary: [ + 'hover:[--bg-color:theme(colors.secondary/10%)]', + '[--text-color:theme(colors.secondary)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + accent: [ + 'hover:[--bg-color:theme(colors.accent/10%)]', + '[--text-color:theme(colors.accent)]', + '[--ring-color:theme(colors.accent/60%)]', + ], + neutral: [ + 'hover:[--bg-color:theme(colors.neutral/10%)]', + '[--text-color:theme(colors.neutral)]', + '[--ring-color:theme(colors.neutral/60%)]', + ], + info: [ + 'hover:[--bg-color:theme(colors.info/10%)]', + '[--text-color:theme(colors.info)]', + '[--ring-color:theme(colors.info/60%)]', + ], + success: [ + 'hover:[--bg-color:theme(colors.success/10%)]', + '[--text-color:theme(colors.success)]', + '[--ring-color:theme(colors.success/60%)]', + ], + warning: [ + 'hover:[--bg-color:theme(colors.warning/10%)]', + '[--text-color:theme(colors.warning)]', + '[--ring-color:theme(colors.warning/60%)]', + ], + danger: [ + 'hover:[--bg-color:theme(colors.danger/10%)]', + '[--text-color:theme(colors.danger)]', + '[--ring-color:theme(colors.danger/60%)]', + ], }, outline: { - default: 'bg-white hover:bg-black/5 ring-black/10', - accent: 'text-accent-500 border-accent-500 hover:bg-accent-500/10 ring-accent-500/60', - red: 'text-red-500 border-red-500 hover:bg-red-500/10 ring-red-500/60', - orange: 'text-orange-500 border-orange-500 hover:bg-orange-500/10 ring-orange-500/60', - amber: 'text-amber-500 border-amber-500 hover:bg-amber-500/10 ring-amber-500/60', - yellow: 'text-yellow-500 border-yellow-500 hover:bg-yellow-500/10 ring-yellow-500/60', - lime: 'text-lime-500 border-lime-500 hover:bg-lime-500/10 ring-lime-500/60', - green: 'text-green-500 border-green-500 hover:bg-green-500/10 ring-green-500/60', - emerald: 'text-emerald-500 border-emerald-500 hover:bg-emerald-500/10 ring-emerald-500/60', - teal: 'text-teal-500 border-teal-500 hover:bg-teal-500/10 ring-teal-500/60', - cyan: 'text-cyan-500 border-cyan-500 hover:bg-cyan-500/10 ring-cyan-500/60', - sky: 'text-sky-500 border-sky-500 hover:bg-sky-500/10 ring-sky-500/60', - blue: 'text-blue-500 border-blue-500 hover:bg-blue-500/10 ring-blue-500/60', - indigo: 'text-indigo-500 border-indigo-500 hover:bg-indigo-500/10 ring-indigo-500/60', - violet: 'text-violet-500 border-violet-500 hover:bg-violet-500/10 ring-violet-500/60', - purple: 'text-purple-500 border-purple-500 hover:bg-purple-500/10 ring-purple-500/60', - fuchsia: 'text-fuchsia-500 border-fuchsia-500 hover:bg-fuchsia-500/10 ring-fuchsia-500/60', - pink: 'text-pink-500 border-pink-500 hover:bg-pink-500/10 ring-pink-500/60', - rose: 'text-rose-500 border-rose-500 hover:bg-rose-500/10 ring-rose-500/60', - gray: 'text-gray-500 border-gray-500 hover:bg-gray-500/10 ring-gray-500/60', + default: [ + 'hover:[--bg-color:theme(colors.surface-content/10%)]', + '[--border-color:theme(colors.surface-content)]', + '[--text-color:theme(colors.surface-content)]', + '[--ring-color:theme(colors.surface-content/60%)]', + ], + primary: [ + 'hover:[--bg-color:theme(colors.primary/10%)]', + '[--border-color:theme(colors.primary)]', + '[--text-color:theme(colors.primary)]', + '[--ring-color:theme(colors.primary/60%)]', + ], + secondary: [ + 'hover:[--bg-color:theme(colors.secondary/10%)]', + '[--border-color:theme(colors.secondary)]', + '[--text-color:theme(colors.secondary)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + accent: [ + 'hover:[--bg-color:theme(colors.accent/10%)]', + '[--border-color:theme(colors.accent)]', + '[--text-color:theme(colors.accent)]', + '[--ring-color:theme(colors.accent/60%)]', + ], + neutral: [ + 'hover:[--bg-color:theme(colors.neutral/10%)]', + '[--border-color:theme(colors.neutral)]', + '[--text-color:theme(colors.neutral)]', + '[--ring-color:theme(colors.neutral/60%)]', + ], + info: [ + 'hover:[--bg-color:theme(colors.info/10%)]', + '[--border-color:theme(colors.info)]', + '[--text-color:theme(colors.info)]', + '[--ring-color:theme(colors.info/60%)]', + ], + success: [ + 'hover:[--bg-color:theme(colors.success/10%)]', + '[--border-color:theme(colors.success)]', + '[--text-color:theme(colors.success)]', + '[--ring-color:theme(colors.success/60%)]', + ], + warning: [ + 'hover:[--bg-color:theme(colors.warning/10%)]', + '[--border-color:theme(colors.warning)]', + '[--text-color:theme(colors.warning)]', + '[--ring-color:theme(colors.warning/60%)]', + ], + danger: [ + 'hover:[--bg-color:theme(colors.danger/10%)]', + '[--border-color:theme(colors.danger)]', + '[--text-color:theme(colors.danger)]', + '[--ring-color:theme(colors.danger/60%)]', + ], }, fill: { - default: 'text-black bg-black/5 hover:bg-black/10 ring-black/10', - accent: 'text-white bg-accent-500 hover:bg-accent-600 ring-accent-500/60', - red: 'text-white bg-red-500 hover:bg-red-600 ring-red-500/60', - orange: 'text-white bg-orange-500 hover:bg-orange-600 ring-orange-500/60', - amber: 'text-white bg-amber-500 hover:bg-amber-600 ring-amber-500/60', - yellow: 'text-white bg-yellow-500 hover:bg-yellow-600 ring-yellow-500/60', - lime: 'text-white bg-lime-500 hover:bg-lime-600 ring-lime-500/60', - green: 'text-white bg-green-500 hover:bg-green-600 ring-green-500/60', - emerald: 'text-white bg-emerald-500 hover:bg-emerald-600 ring-emerald-500/60', - teal: 'text-white bg-teal-500 hover:bg-teal-600 ring-teal-500/60', - cyan: 'text-white bg-cyan-500 hover:bg-cyan-600 ring-cyan-500/60', - sky: 'text-white bg-sky-500 hover:bg-sky-600 ring-sky-500/60', - blue: 'text-white bg-blue-500 hover:bg-blue-600 ring-blue-500/60', - indigo: 'text-white bg-indigo-500 hover:bg-indigo-600 ring-indigo-500/60', - violet: 'text-white bg-violet-500 hover:bg-violet-600 ring-violet-500/60', - purple: 'text-white bg-purple-500 hover:bg-purple-600 ring-purple-500/60', - fuchsia: 'text-white bg-fuchsia-500 hover:bg-fuchsia-600 ring-fuchsia-500/60', - pink: 'text-white bg-pink-500 hover:bg-pink-600 ring-pink-500/60', - rose: 'text-white bg-rose-500 hover:bg-rose-600 ring-rose-500/60', - gray: 'text-white bg-gray-500 hover:bg-gray-600 ring-gray-500/60', + default: [ + `[--bg-color:theme(colors.surface-content)]`, + 'hover:[--bg-color:theme(colors.surface-content/80%)]', + '[--text-color:theme(colors.surface-200)]', + '[--ring-color:theme(colors.surface-content/60%)]', + ], + primary: [ + `[--bg-color:theme(colors.primary)]`, + 'hover:[--bg-color:theme(colors.primary-600)]', + '[--text-color:theme(colors.primary-content)]', + '[--ring-color:theme(colors.primary/60%)]', + ], + secondary: [ + '[--bg-color:theme(colors.secondary)]', + 'hover:[--bg-color:theme(colors.secondary-600)]', + '[--text-color:theme(colors.secondary-content)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + accent: [ + '[--bg-color:theme(colors.accent)]', + 'hover:[--bg-color:theme(colors.accent-600)]', + '[--text-color:theme(colors.accent-content)]', + '[--ring-color:theme(colors.accent/60%)]', + ], + neutral: [ + '[--bg-color:theme(colors.neutral)]', + 'hover:[--bg-color:theme(colors.neutral-600)]', + '[--text-color:theme(colors.neutral-content)]', + '[--ring-color:theme(colors.neutral/60%)]', + ], + info: [ + `[--bg-color:theme(colors.info)]`, + 'hover:[--bg-color:theme(colors.info-600)]', + '[--text-color:theme(colors.info-content)]', + '[--ring-color:theme(colors.info/60%)]', + ], + success: [ + `[--bg-color:theme(colors.success)]`, + 'hover:[--bg-color:theme(colors.success-600)]', + '[--text-color:theme(colors.success-content)]', + '[--ring-color:theme(colors.success/60%)]', + ], + warning: [ + `[--bg-color:theme(colors.warning)]`, + 'hover:[--bg-color:theme(colors.warning-600)]', + '[--text-color:theme(colors.warning-content)]', + '[--ring-color:theme(colors.warning/60%)]', + ], + danger: [ + `[--bg-color:theme(colors.danger)]`, + 'hover:[--bg-color:theme(colors.danger-600)]', + '[--text-color:theme(colors.danger-content)]', + '[--ring-color:theme(colors.danger/60%)]', + ], }, 'fill-light': { - default: 'text-black bg-black/5 hover:bg-black/10 ring-black/20', - accent: - 'text-accent-500 bg-accent-500/10 hover:bg-accent-500/20 ring-accent-400 ring-accent-500/60', - red: 'text-red-500 bg-red-500/10 hover:bg-red-500/20 ring-red-500/60', - orange: 'text-orange-500 bg-orange-500/10 hover:bg-orange-500/20 ring-orange-500/60', - amber: 'text-amber-500 bg-amber-500/10 hover:bg-amber-500/20 ring-amber-500/60', - yellow: 'text-yellow-500 bg-yellow-500/10 hover:bg-yellow-500/20 ring-yellow-500/60', - lime: 'text-lime-500 bg-lime-500/10 hover:bg-lime-500/20 ring-lime-500/60', - green: 'text-green-500 bg-green-500/10 hover:bg-green-500/20 ring-green-500/60', - emerald: 'text-emerald-500 bg-emerald-500/10 hover:bg-emerald-500/20 ring-emerald-500/60', - teal: 'text-teal-500 bg-teal-500/10 hover:bg-teal-500/20 ring-teal-500/60', - cyan: 'text-cyan-500 bg-cyan-500/10 hover:bg-cyan-500/20 ring-cyan-500/60', - sky: 'text-sky-500 bg-sky-500/10 hover:bg-sky-500/20 ring-sky-500/60', - blue: 'text-blue-500 bg-blue-500/10 hover:bg-blue-500/20 ring-blue-500/60', - indigo: 'text-indigo-500 bg-indigo-500/10 hover:bg-indigo-500/20 ring-indigo-500/60', - violet: 'text-violet-500 bg-violet-500/10 hover:bg-violet-500/20 ring-violet-500/60', - purple: 'text-purple-500 bg-purple-500/10 hover:bg-purple-500/20 ring-purple-500/60', - fuchsia: 'text-fuchsia-500 bg-fuchsia-500/10 hover:bg-fuchsia-500/20 ring-fuchsia-500/60', - pink: 'text-pink-500 bg-pink-500/10 hover:bg-pink-500/20 ring-pink-500/60', - rose: 'text-rose-500 bg-rose-500/10 hover:bg-rose-500/20 ring-rose-500/60', - gray: 'text-gray-500 bg-gray-500/10 hover:bg-gray-500/20 ring-gray-500/60', + default: [ + '[--bg-color:theme(colors.surface-content/10%)]', + 'hover:[--bg-color:theme(colors.surface-content/20%)]', + '[--text-color:theme(colors.surface-content)]', + '[--ring-color:theme(colors.surface-content/60%)]', + ], + primary: [ + '[--bg-color:theme(colors.primary/10%)]', + 'hover:[--bg-color:theme(colors.primary/20%)]', + '[--text-color:theme(colors.primary)]', + '[--ring-color:theme(colors.primary/60%)]', + ], + secondary: [ + '[--bg-color:theme(colors.secondary/10%)]', + 'hover:[--bg-color:theme(colors.secondary/20%)]', + '[--text-color:theme(colors.secondary)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + accent: [ + '[--bg-color:theme(colors.accent/10%)]', + 'hover:[--bg-color:theme(colors.accent/20%)]', + '[--text-color:theme(colors.accent)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + neutral: [ + '[--bg-color:theme(colors.neutral/10%)]', + 'hover:[--bg-color:theme(colors.neutral/20%)]', + '[--text-color:theme(colors.neutral)]', + '[--ring-color:theme(colors.neutral/60%)]', + ], + info: [ + '[--bg-color:theme(colors.info/10%)]', + 'hover:[--bg-color:theme(colors.info/20%)]', + '[--text-color:theme(colors.info)]', + '[--ring-color:theme(colors.info/60%)]', + ], + success: [ + '[--bg-color:theme(colors.success/10%)]', + 'hover:[--bg-color:theme(colors.success/20%)]', + '[--text-color:theme(colors.success)]', + '[--ring-color:theme(colors.success/60%)]', + ], + warning: [ + '[--bg-color:theme(colors.warning/10%)]', + 'hover:[--bg-color:theme(colors.warning/20%)]', + '[--text-color:theme(colors.warning)]', + '[--ring-color:theme(colors.warning/60%)]', + ], + danger: [ + '[--bg-color:theme(colors.danger/10%)]', + 'hover:[--bg-color:theme(colors.danger/20%)]', + '[--text-color:theme(colors.danger)]', + '[--ring-color:theme(colors.danger/60%)]', + ], }, 'fill-outline': { - default: 'text-black bg-black/5 hover:bg-black/10 border-black/20 ring-black/10', - accent: - 'text-accent-500 border-accent-500 bg-accent-500/10 hover:bg-accent-500/20 ring-accent-500/60', - red: 'text-red-500 border-red-500 bg-red-500/10 hover:bg-red-500/20 ring-red-500/60', - orange: - 'text-orange-500 border-orange-500 bg-orange-500/10 hover:bg-orange-500/20 ring-orange-500/60', - amber: - 'text-amber-500 border-amber-500 bg-amber-500/10 hover:bg-amber-500/20 ring-amber-500/60', - yellow: - 'text-yellow-500 border-yellow-500 bg-yellow-500/10 hover:bg-yellow-500/20 ring-yellow-500/60', - lime: 'text-lime-500 border-lime-500 bg-lime-500/10 hover:bg-lime-500/20 ring-lime-500/60', - green: - 'text-green-500 border-green-500 bg-green-500/10 hover:bg-green-500/20 ring-green-500/60', - emerald: - 'text-emerald-500 border-emerald-500 bg-emerald-500/10 hover:bg-emerald-500/20 ring-emerald-500/60', - teal: 'text-teal-500 border-teal-500 bg-teal-500/10 hover:bg-teal-500/20 ring-teal-500/60', - cyan: 'text-cyan-500 border-cyan-500 bg-cyan-500/10 hover:bg-cyan-500/20 ring-cyan-500/60', - sky: 'text-sky-500 border-sky-500 bg-sky-500/10 hover:bg-sky-500/20 ring-sky-500/60', - blue: 'text-blue-500 border-blue-500 bg-blue-500/10 hover:bg-blue-500/20 ring-blue-500/60', - indigo: - 'text-indigo-500 border-indigo-500 bg-indigo-500/10 hover:bg-indigo-500/20 ring-indigo-500/60', - violet: - 'text-violet-500 border-violet-500 bg-violet-500/10 hover:bg-violet-500/20 ring-violet-500/60', - purple: - 'text-purple-500 border-purple-500 bg-purple-500/10 hover:bg-purple-500/20 ring-purple-500/60', - fuchsia: - 'text-fuchsia-500 border-fuchsia-500 bg-fuchsia-500/10 hover:bg-fuchsia-500/20 ring-fuchsia-500/60', - pink: 'text-pink-500 border-pink-500 bg-pink-500/10 hover:bg-pink-500/20 ring-pink-500/60', - rose: 'text-rose-500 border-rose-500 bg-rose-500/10 hover:bg-rose-500/20 ring-rose-500/60', - gray: 'text-gray-500 border-gray-500 bg-gray-500/10 hover:bg-gray-500/20 ring-gray-500/60', + default: [ + '[--bg-color:theme(colors.surface-content/10%)]', + 'hover:[--bg-color:theme(colors.surface-content/20%)]', + '[--border-color:theme(colors.surface-content)]', + '[--text-color:theme(colors.surface-content)]', + '[--ring-color:theme(colors.surface-content/60%)]', + ], + primary: [ + '[--bg-color:theme(colors.primary/10%)]', + 'hover:[--bg-color:theme(colors.primary/20%)]', + '[--border-color:theme(colors.primary)]', + '[--text-color:theme(colors.primary)]', + '[--ring-color:theme(colors.primary/60%)]', + ], + secondary: [ + '[--bg-color:theme(colors.secondary/10%)]', + 'hover:[--bg-color:theme(colors.secondary/20%)]', + '[--border-color:theme(colors.secondary)]', + '[--text-color:theme(colors.secondary)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + accent: [ + '[--bg-color:theme(colors.accent/10%)]', + 'hover:[--bg-color:theme(colors.accent/20%)]', + '[--border-color:theme(colors.accent)]', + '[--text-color:theme(colors.accent)]', + '[--ring-color:theme(colors.accent/60%)]', + ], + neutral: [ + '[--bg-color:theme(colors.neutral/10%)]', + 'hover:[--bg-color:theme(colors.neutral/20%)]', + '[--border-color:theme(colors.neutral)]', + '[--text-color:theme(colors.neutral)]', + '[--ring-color:theme(colors.neutral/60%)]', + ], + info: [ + '[--bg-color:theme(colors.info/10%)]', + 'hover:[--bg-color:theme(colors.info/20%)]', + '[--border-color:theme(colors.info)]', + '[--text-color:theme(colors.info)]', + '[--ring-color:theme(colors.info/60%)]', + ], + success: [ + '[--bg-color:theme(colors.success/10%)]', + 'hover:[--bg-color:theme(colors.success/20%)]', + '[--border-color:theme(colors.success)]', + '[--text-color:theme(colors.success)]', + '[--ring-color:theme(colors.success/60%)]', + ], + warning: [ + '[--bg-color:theme(colors.warning/10%)]', + 'hover:[--bg-color:theme(colors.warning/20%)]', + '[--border-color:theme(colors.warning)]', + '[--text-color:theme(colors.warning)]', + '[--ring-color:theme(colors.warning/60%)]', + ], + danger: [ + '[--bg-color:theme(colors.danger/10%)]', + 'hover:[--bg-color:theme(colors.danger/20%)]', + '[--border-color:theme(colors.danger)]', + '[--text-color:theme(colors.danger)]', + '[--ring-color:theme(colors.danger/60%)]', + ], }, text: { - default: 'hover:text-black/70 ring-black/10', - accent: 'text-accent-500 hover:text-accent-700 ring-accent-500/60', - red: 'text-red-500 hover:text-red-700 ring-red-500/60', - orange: 'text-orange-500 hover:text-orange-700 ring-orange-500/60', - amber: 'text-amber-500 hover:text-amber-700 ring-amber-500/60', - yellow: 'text-yellow-500 hover:text-yellow-700 ring-yellow-500/60', - lime: 'text-lime-500 hover:text-lime-700 ring-lime-500/60', - green: 'text-green-500 hover:text-green-700 ring-green-500/60', - emerald: 'text-emerald-500 hover:text-emerald-700 ring-emerald-500/60', - teal: 'text-teal-500 hover:text-teal-700 ring-teal-500/60', - cyan: 'text-cyan-500 hover:text-cyan-700 ring-cyan-500/60', - sky: 'text-sky-500 hover:text-sky-700 ring-sky-500/60', - blue: 'text-blue-500 hover:text-blue-700 ring-blue-500/60', - indigo: 'text-indigo-500 hover:text-indigo-700 ring-indigo-500/60', - violet: 'text-violet-500 hover:text-violet-700 ring-violet-500/60', - purple: 'text-purple-500 hover:text-purple-700 ring-purple-500/60', - fuchsia: 'text-fuchsia-500 hover:text-fuchsia-700 ring-fuchsia-500/60', - pink: 'text-pink-500 hover:text-pink-700 ring-pink-500/60', - rose: 'text-rose-500 hover:text-rose-700 ring-rose-500/60', - gray: 'text-gray-500 hover:text-gray-700 ring-gray-500/60', + default: [ + '[--text-color:theme(colors.surface-content)]', + 'hover:[--text-color:theme(colors.surface-content/80%)]', + '[--ring-color:theme(colors.surface-content/60%)]', + ], + primary: [ + '[--text-color:theme(colors.primary)]', + 'hover:[--text-color:theme(colors.primary-700)]', + '[--ring-color:theme(colors.primary/60%)]', + ], + secondary: [ + '[--text-color:theme(colors.secondary)]', + 'hover:[--text-color:theme(colors.secondary-700)]', + '[--ring-color:theme(colors.secondary/60%)]', + ], + accent: [ + '[--text-color:theme(colors.accent)]', + 'hover:[--text-color:theme(colors.accent-700)]', + '[--ring-color:theme(colors.accent/60%)]', + ], + neutral: [ + '[--text-color:theme(colors.neutral)]', + 'hover:[--text-color:theme(colors.neutral-700)]', + '[--ring-color:theme(colors.neutral/60%)]', + ], + info: [ + '[--text-color:theme(colors.info)]', + 'hover:[--text-color:theme(colors.info-700)]', + '[--ring-color:theme(colors.info/60%)]', + ], + success: [ + '[--text-color:theme(colors.success)]', + 'hover:[--text-color:theme(colors.success-700)]', + '[--ring-color:theme(colors.success/60%)]', + ], + warning: [ + '[--text-color:theme(colors.warning)]', + 'hover:[--text-color:theme(colors.warning-700)]', + '[--ring-color:theme(colors.warning/60%)]', + ], + danger: [ + '[--text-color:theme(colors.danger)]', + 'hover:[--text-color:theme(colors.danger-700)]', + '[--ring-color:theme(colors.danger/60%)]', + ], + }, + none: { + default: '', + primary: '', + secondary: '', + accent: '', + neutral: '', + info: '', + success: '', + warning: '', + danger: '', }, - none: {}, }[variant ?? 'none']?.[color ?? 'default'], - theme.root, + + // text color + ['default', 'outline', 'fill', 'fill-outline', 'fill-light', 'text'].includes( + variant ?? 'none' + ) && 'text-[--text-color]', + + // background color + ['default', 'outline', 'fill', 'fill-outline', 'fill-light'].includes(variant ?? 'none') && + 'bg-[--bg-color] ', + + // border color + ['outline', 'fill-outline'].includes(variant ?? 'none') && 'border-[--border-color]', + + // ring color + ['default', 'outline', 'fill', 'fill-outline', 'fill-light', 'text'].includes( + variant ?? 'none' + ) && 'ring-[--ring-color]', + + settingsClasses.root, classes?.root, $$props.class ); @@ -256,15 +468,18 @@ > {#if loading} <span transition:slide={{ axis: 'x', duration: 200 }}> - <ProgressCircle size={16} width={2} class={cls(theme.loading, classes.loading)} /> + <ProgressCircle size={16} width={2} class={cls(settingsClasses.loading, classes.loading)} /> </span> {:else if icon} <span in:slide={{ axis: 'x', duration: 200 }}> {#if typeof icon === 'string' || 'icon' in icon} <!-- font path/url/etc or font-awesome IconDefinition --> - <Icon data={asIconData(icon)} class={cls('pointer-events-none', theme.icon, classes.icon)} /> + <Icon + data={asIconData(icon)} + class={cls('pointer-events-none', settingsClasses.icon, classes.icon)} + /> {:else} - <Icon class={cls('pointer-events-none', theme.icon, classes.icon)} {...icon} /> + <Icon class={cls('pointer-events-none', settingsClasses.icon, classes.icon)} {...icon} /> {/if} </span> {/if} diff --git a/packages/svelte-ux/src/lib/components/ButtonGroup.svelte b/packages/svelte-ux/src/lib/components/ButtonGroup.svelte index 8fafc4195..26cf68619 100644 --- a/packages/svelte-ux/src/lib/components/ButtonGroup.svelte +++ b/packages/svelte-ux/src/lib/components/ButtonGroup.svelte @@ -1,7 +1,7 @@ <script lang="ts" context="module"> import { type ComponentProps, setContext, getContext } from 'svelte'; import type Button from './Button.svelte'; - import type { TailwindColors } from '$lib/types'; + import type { ThemeColors } from '$lib/types'; // TODO: Use `ButtonProps['...']` if can work around circular reference (Button <-> ButtonGroup) type ButtonProps = ComponentProps<Button>; @@ -16,7 +16,7 @@ | 'none' | undefined; // ButtonProps['variant']; size: 'sm' | 'md' | 'lg' | undefined; //ButtonProps['size']; - color: TailwindColors | 'default' | undefined; //ButtonProps['color']; + color: ThemeColors | 'default' | undefined; //ButtonProps['color']; rounded: boolean | 'full' | undefined; // ButtonProps['rounded'] }; @@ -33,7 +33,7 @@ <script lang="ts"> import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let variant: ComponentProps<Button>['variant'] = undefined; export let size: ComponentProps<Button>['size'] | undefined = undefined; @@ -41,7 +41,7 @@ export let rounded: ComponentProps<Button>['rounded'] | undefined = undefined; export let disabled: boolean = false; - const theme = getComponentTheme('ButtonGroup'); + const settingsClasses = getComponentClasses('ButtonGroup'); $: _class = cls( 'ButtonGroup', @@ -69,7 +69,7 @@ '[&.variant-fill-light_.Button:not(:first-child)]:ml-px', '[&.variant-fill-light_:not(:first-child)_.Button]:ml-px', - theme.root, + settingsClasses.root, $$props.class ); diff --git a/packages/svelte-ux/src/lib/components/Card.svelte b/packages/svelte-ux/src/lib/components/Card.svelte index 39b163f23..eace93d23 100644 --- a/packages/svelte-ux/src/lib/components/Card.svelte +++ b/packages/svelte-ux/src/lib/components/Card.svelte @@ -3,13 +3,13 @@ import Header from './Header.svelte'; import Overlay from './Overlay.svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let title: string | string[] | null = null; export let subheading: string | string[] | null = null; export let loading: boolean | null = null; - const theme = getComponentTheme('Card'); + const settingsClasses = getComponentClasses('Card'); </script> <!-- @@ -23,8 +23,8 @@ {...$$restProps} class={cls( 'Card', - 'relative z-0 bg-white border rounded elevation-1 flex flex-col justify-between', - theme.root, + 'relative z-0 bg-surface-100 border rounded elevation-1 flex flex-col justify-between', + settingsClasses.root, $$props.class )} > diff --git a/packages/svelte-ux/src/lib/components/Checkbox.svelte b/packages/svelte-ux/src/lib/components/Checkbox.svelte index 593262ba8..dbce66955 100644 --- a/packages/svelte-ux/src/lib/components/Checkbox.svelte +++ b/packages/svelte-ux/src/lib/components/Checkbox.svelte @@ -4,7 +4,7 @@ import Icon from './Icon.svelte'; import { uniqueId } from '../utils/string'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let id = uniqueId('checkbox-'); export let name = ''; @@ -22,7 +22,7 @@ label?: string; icon?: string; } = {}; - const theme = getComponentTheme('Checkbox'); + const settingsClasses = getComponentClasses('Checkbox'); // Update when group changes. Separate function to break reactivity loop $: if (group !== null) { @@ -47,7 +47,15 @@ } </script> -<div class={cls('Checkbox', 'inline-flex items-center', theme.root, classes.root, $$props.class)}> +<div + class={cls( + 'Checkbox', + 'inline-flex items-center', + settingsClasses.root, + classes.root, + $$props.class + )} +> <input {id} {name} @@ -66,23 +74,23 @@ circle ? 'rounded-full' : 'rounded', 'peer-disabled:opacity-50 transition-shadow duration-300', !disabled && - 'peer-hover:border-accent-500 peer-focus-visible:border-accent-500 peer-focus-visible:ring-2 ring-accent-400 ring-offset-1', - !checked && !disabled && 'peer-hover:bg-accent-100', + 'peer-hover:border-primary peer-focus-visible:border-primary peer-focus-visible:ring-2 ring-primary/60 ring-offset-1', + !checked && !disabled && 'peer-hover:bg-primary/10', checked ? disabled ? 'bg-gray-500 border-gray-500' - : 'bg-accent-500 border-accent-500' + : 'bg-primary border-primary' : 'border-gray-500', - theme.checkbox, + settingsClasses.checkbox, classes.checkbox )} > <Icon path={indeterminate ? mdiMinus : mdiCheck} class={cls( - 'pointer-events-none text-white transition-transform', + 'pointer-events-none text-primary-content transition-transform', checked ? 'scale-100' : 'scale-0', - theme.icon, + settingsClasses.icon, classes.icon )} size={{ @@ -105,7 +113,7 @@ md: 'text-md', // 16px lg: 'text-lg', // 18px }[size], - theme.label, + settingsClasses.label, classes.label )} > diff --git a/packages/svelte-ux/src/lib/components/Code.svelte b/packages/svelte-ux/src/lib/components/Code.svelte index bca13d977..6ee38af8c 100644 --- a/packages/svelte-ux/src/lib/components/Code.svelte +++ b/packages/svelte-ux/src/lib/components/Code.svelte @@ -3,7 +3,7 @@ import 'prism-svelte'; import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import CopyButton from './CopyButton.svelte'; export let source: string | null = null; @@ -12,20 +12,28 @@ ? Prism.highlight(source, Prism.languages[language] ?? Prism.languages.text, language) : ''; - const theme = getComponentTheme('Code'); + export let classes: { + root?: string; + pre?: string; + code?: string; + } = {}; + + const settingsClasses = getComponentClasses('Code'); </script> -<div class={cls('Code', 'rounded', theme.root, $$props.class)}> +<div class={cls('Code', 'rounded', settingsClasses.root, classes.root, $$props.class)}> {#if source} <div class="relative"> - <pre class="language-{language} rounded" style="margin: 0; white-space: normal;"> - <code class="language-{language}">{@html highlightedSource}</code> + <pre + class={cls('language-{language} rounded', classes.pre)} + style="margin: 0; white-space: normal;"> + <code class={cls('language-{language}', classes.code)}>{@html highlightedSource}</code> </pre> <div class="absolute top-0 right-0 p-2 z-10"> <CopyButton value={source ?? ''} - class="text-white/70 hover:bg-white/20 py-1 backdrop-blur-md" + class="text-white/70 hover:bg-surface-100/20 py-1 backdrop-blur-md" size="sm" /> </div> diff --git a/packages/svelte-ux/src/lib/components/Collapse.svelte b/packages/svelte-ux/src/lib/components/Collapse.svelte index 10eabeb6b..20f8f95f2 100644 --- a/packages/svelte-ux/src/lib/components/Collapse.svelte +++ b/packages/svelte-ux/src/lib/components/Collapse.svelte @@ -6,7 +6,7 @@ import Icon from './Icon.svelte'; import type { TransitionParams } from '$lib/types'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; /** * @slot {{ active: number }} trigger - Primary content to trigger the show/hide @@ -31,7 +31,7 @@ icon?: string; content?: string; } = {}; - const theme = getComponentTheme('Collapse'); + const settingsClasses = getComponentClasses('Collapse'); /** * Controls how first, last, and gap between are calculated @@ -54,7 +54,7 @@ popout && list === 'type' && 'first-of-type:mt-0 last-of-type:mb-0', popout && list === 'parent' && 'first:mt-0 last:mb-0', popout && list === 'group' && 'group-first:mt-0 group-last:mb-0', - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -70,7 +70,7 @@ }} > <slot name="trigger" {open} - ><span class={cls('flex-1', theme.trigger, classes.trigger)}>{name}</span></slot + ><span class={cls('flex-1', settingsClasses.trigger, classes.trigger)}>{name}</span></slot > <slot name="icon" {open}> @@ -80,7 +80,7 @@ class={cls( 'transition-all duration-[var(--duration)] transform', 'data-[open=true]:-rotate-180', - theme.icon, + settingsClasses.icon, classes.icon )} > @@ -90,7 +90,10 @@ </button> {#if open} - <div transition:transition={transitionParams} class={cls(theme.content, classes.content)}> + <div + transition:transition={transitionParams} + class={cls(settingsClasses.content, classes.content)} + > <slot {open} /> </div> {/if} diff --git a/packages/svelte-ux/src/lib/components/CopyButton.svelte b/packages/svelte-ux/src/lib/components/CopyButton.svelte index 7cdd86174..ef6e4a480 100644 --- a/packages/svelte-ux/src/lib/components/CopyButton.svelte +++ b/packages/svelte-ux/src/lib/components/CopyButton.svelte @@ -3,7 +3,7 @@ import { cls } from '../utils/styles'; import Button from './Button.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { slide } from 'svelte/transition'; export let value: string; @@ -13,13 +13,13 @@ setTimeout(() => (showMessage = false), 3000); } - const theme = getComponentTheme('CopyButton'); + const settingsClasses = getComponentClasses('CopyButton'); </script> <Button icon={mdiContentCopy} {...$$restProps} - class={cls('CopyButton', theme.root, $$props.class)} + class={cls('CopyButton', settingsClasses.root, $$props.class)} on:click={() => { navigator.clipboard.writeText(value); showMessage = true; diff --git a/packages/svelte-ux/src/lib/components/DateButton.svelte b/packages/svelte-ux/src/lib/components/DateButton.svelte index 7a8b35aa5..94ac20538 100644 --- a/packages/svelte-ux/src/lib/components/DateButton.svelte +++ b/packages/svelte-ux/src/lib/components/DateButton.svelte @@ -1,12 +1,13 @@ <script lang="ts"> import { createEventDispatcher } from 'svelte'; - import { format as dateFormat, isWithinInterval } from 'date-fns'; + import { isWithinInterval } from 'date-fns'; import Button from './Button.svelte'; - import { getDateFuncsByPeriodType, PeriodType } from '../utils/date'; + import { DateToken, getDateFuncsByPeriodType, PeriodType } from '../utils/date'; import type { SelectedDate } from '../utils/date'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getSettings } from './settings'; + import { getComponentClasses } from './theme'; const dispatch = createEventDispatcher(); @@ -16,57 +17,54 @@ export let selected: SelectedDate; export let hidden: boolean = false; export let fade: boolean = false; - export let format = getDefaultFormat(periodType); + export let format = getCustomFormat(periodType); - const theme = getComponentTheme('DateButton'); + const { format: format_ux, localeSettings } = getSettings(); + const settingsClasses = getComponentClasses('DateButton'); - function getDefaultFormat(periodType: PeriodType) { + function getCustomFormat(periodType: PeriodType) { switch (periodType) { - case PeriodType.CalendarYear: - case PeriodType.FiscalYearOctober: - return 'yyyy'; - case PeriodType.Month: - return 'MMM'; case PeriodType.Day: - return 'd'; + return DateToken.DayOfMonth_numeric; default: - return 'MM/dd/yyyy'; + // returning undefined will use the default format of PeriodType + return undefined; } } - const { start, end, isSame } = getDateFuncsByPeriodType(periodType); + const { start, end, isSame } = getDateFuncsByPeriodType($localeSettings, periodType); $: isSelected = selected instanceof Date ? isSame(date, selected) : selected instanceof Array - ? selected.some((d) => isSame(date, d)) - : selected instanceof Object - ? selected.from - ? isWithinInterval(date, { - start: start(selected.from), - end: end(selected.to ?? selected.from), - }) - : false - : false; + ? selected.some((d) => isSame(date, d)) + : selected instanceof Object + ? selected.from + ? isWithinInterval(date, { + start: start(selected.from), + end: end(selected.to ?? selected.from), + }) + : false + : false; $: isSelectedStart = selected instanceof Date ? isSame(date, selected) : selected instanceof Array - ? selected.some((d) => isSame(date, d)) - : selected instanceof Object - ? isSame(date, selected.from ?? selected.to) - : false; + ? selected.some((d) => isSame(date, d)) + : selected instanceof Object + ? isSame(date, selected.from ?? selected.to) + : false; $: isSelectedEnd = selected instanceof Date ? isSame(date, selected) : selected instanceof Array - ? selected.some((d) => isSame(date, d)) - : selected instanceof Object - ? isSame(date, selected.to ?? selected.from) - : false; + ? selected.some((d) => isSame(date, d)) + : selected instanceof Object + ? isSame(date, selected.to ?? selected.from) + : false; $: isCurrent = isSame(date, new Date()); @@ -81,13 +79,11 @@ 'inline-flex items-center justify-center', isSelectedStart ? '[--tw-gradient-from:transparent]' - : '[--tw-gradient-from:theme(colors.accent.500)]', - isSelectedEnd - ? '[--tw-gradient-to:transparent]' - : '[--tw-gradient-to:theme(colors.accent.500)]', + : '[--tw-gradient-from:theme(colors.primary)]', + isSelectedEnd ? '[--tw-gradient-to:transparent]' : '[--tw-gradient-to:theme(colors.primary)]', isSelected && (isVerticalSelection ? 'bg-gradient-to-b' : 'bg-gradient-to-r'), hidden && 'opacity-0 pointer-events-none', - theme.root, + settingsClasses.root, $$props.class )} > @@ -99,7 +95,7 @@ isCurrent ? 'font-bold' : 'font-normal' )} variant={isSelected ? 'fill' : 'default'} - color={isSelected || isCurrent ? 'accent' : 'default'} + color={isSelected || isCurrent ? 'primary' : 'default'} {disabled} on:click={() => { // Do not set selected date as this is causing issues with controlled selected (ex. date ranges, arrays, etc) / changing from date to { from: ..., to: ... } @@ -107,6 +103,6 @@ dispatch('dateChange', date); }} > - {dateFormat(date, format)} + {$format_ux(date, periodType, { custom: format })} </Button> </div> diff --git a/packages/svelte-ux/src/lib/components/DateField.svelte b/packages/svelte-ux/src/lib/components/DateField.svelte index f8a0d4fea..91b34adff 100644 --- a/packages/svelte-ux/src/lib/components/DateField.svelte +++ b/packages/svelte-ux/src/lib/components/DateField.svelte @@ -1,19 +1,26 @@ <script lang="ts"> import { createEventDispatcher } from 'svelte'; - import { parse as parseDate, format as formatDate } from 'date-fns'; + import { parse as parseDate } from 'date-fns'; + import { PeriodType } from '../utils'; + import { getSettings } from './settings'; import Field from './Field.svelte'; import Input from './Input.svelte'; import DatePickerField from './DatePickerField.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; - export let value: Date = null; - export let format = 'MM/dd/yyyy'; - export let mask = format.toLowerCase(); + const { format: format_ux } = getSettings(); + + export let value: Date | null = null; + export let format: string | undefined = undefined; + export let mask: string | undefined = undefined; export let replace = 'dmyh'; export let picker = false; + $: actualFormat = format ?? $format_ux.settings.formats.dates.baseParsing ?? 'MM/dd/yyyy'; + $: actualMask = mask ?? actualFormat.toLowerCase(); + // Field props export let label = ''; export let error = ''; @@ -25,16 +32,16 @@ export let dense = false; export let icon: string | null = null; - const theme = getComponentTheme('DateField'); + const settingsClasses = getComponentClasses('DateField'); - let inputValue = ''; + let inputValue: string | undefined = ''; const dispatch = createEventDispatcher(); - function onInputChange(e) { + function onInputChange(e: any) { inputValue = e.detail.value; const lastValue = value; - const parsedValue = parseDate(inputValue, format, new Date()); + const parsedValue = parseDate(inputValue ?? '', actualFormat, new Date()); value = isNaN(parsedValue.valueOf()) ? null : parsedValue; if (value != lastValue) { dispatch('change', { value }); @@ -55,14 +62,14 @@ {clearable} on:clear={() => { value = null; - inputValue = null; + inputValue = undefined; dispatch('change', { value }); }} let:id > <Input - value={value ? formatDate(value, format) : inputValue} - {mask} + value={value ? $format_ux(value, PeriodType.Day, { custom: actualFormat }) : inputValue} + mask={actualMask} {replace} {id} on:change={onInputChange} @@ -76,7 +83,7 @@ value = e.detail; dispatch('change', { value }); }} - class="p-1 text-black/50" + class="p-1 text-surface-content/50" /> {/if} </span> diff --git a/packages/svelte-ux/src/lib/components/DatePickerField.svelte b/packages/svelte-ux/src/lib/components/DatePickerField.svelte index bb3076319..e0a48ca8b 100644 --- a/packages/svelte-ux/src/lib/components/DatePickerField.svelte +++ b/packages/svelte-ux/src/lib/components/DatePickerField.svelte @@ -6,10 +6,10 @@ import Button from './Button.svelte'; import Field from './Field.svelte'; import Dialog from './Dialog.svelte'; - import { getDateFuncsByPeriodType, PeriodType } from '../utils/date'; + import { DateToken, getDateFuncsByPeriodType, PeriodType } from '../utils/date'; import DateSelect from './DateSelect.svelte'; - import { dateDisplay } from '../utils/dateDisplay'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; + import { getSettings } from './settings'; const dispatch = createEventDispatcher(); @@ -31,24 +31,31 @@ export let icon: string | null = null; export let center = false; - const theme = getComponentTheme('DatePickerField'); + const settingsClasses = getComponentClasses('DatePickerField'); + const { format, localeSettings } = getSettings(); + $: dictionary = $format.settings.dictionary; let open: boolean = false; // let format: string = 'EEE, MMM d'; // Show "Day of Week", "Year", etc based on perioType (see DayStepper, MonthStepper) - let primaryFormat = ''; - let secondaryFormat = ''; + let primaryFormat: string | string[] = ''; + let secondaryFormat: string | string[] = ''; $: switch (periodType) { case PeriodType.Month: - primaryFormat = 'MMMM'; - secondaryFormat = 'yyyy'; + primaryFormat = DateToken.Month_long; + secondaryFormat = DateToken.Year_numeric; break; case PeriodType.Day: default: - primaryFormat = 'MMMM do, yyyy'; - secondaryFormat = 'eeee'; + primaryFormat = [ + DateToken.Month_long, + DateToken.DayOfMonth_withOrdinal, + DateToken.Year_numeric, + ]; + + secondaryFormat = DateToken.DayOfWeek_long; } $: currentValue = value; @@ -58,7 +65,7 @@ <Button icon={mdiCalendar} on:click={() => (open = true)} {...$$restProps} /> {:else} <Field - label={label ?? dateDisplay(value, { format: secondaryFormat })} + label={label ?? $format(value, PeriodType.Day, { custom: secondaryFormat })} {icon} {error} {hint} @@ -76,7 +83,7 @@ class="p-2" on:click={() => { if (value && periodType) { - const { add } = getDateFuncsByPeriodType(periodType); + const { add } = getDateFuncsByPeriodType($localeSettings, periodType); value = add(value, -1); dispatch('change', value); } @@ -92,14 +99,14 @@ on:click={() => (open = true)} {id} > - {dateDisplay(value, { format: primaryFormat })} + {$format(value, PeriodType.Day, { custom: primaryFormat })} </button> <div slot="append"> {#if clearable && value} <Button icon={mdiClose} - class="text-black/50 p-1" + class="text-surface-content/50 p-1" on:click={() => { value = null; dispatch('clear'); @@ -114,7 +121,7 @@ class="p-2" on:click={() => { if (value && periodType) { - const { add } = getDateFuncsByPeriodType(periodType); + const { add } = getDateFuncsByPeriodType($localeSettings, periodType); value = add(value, 1); dispatch('change', value); } @@ -127,12 +134,15 @@ <Dialog bind:open> {#if currentValue} - <div class="flex flex-col justify-center bg-accent-500 text-white px-6 h-24" transition:slide> - <div class="text-sm text-white/50"> - {dateDisplay(currentValue, { format: secondaryFormat })} + <div + class="flex flex-col justify-center bg-primary text-primary-content px-6 h-24" + transition:slide + > + <div class="text-sm opacity-50"> + {$format(currentValue, PeriodType.Day, { custom: secondaryFormat })} </div> - <div class="text-3xl text-white"> - {dateDisplay(currentValue, { format: primaryFormat })} + <div class="text-3xl"> + {$format(currentValue, PeriodType.Day, { custom: primaryFormat })} </div> </div> {/if} @@ -153,13 +163,14 @@ value = currentValue; dispatch('change', value); }} - class="bg-accent-500 text-white hover:bg-accent-600">OK</Button + variant="fill" + color="primary">{dictionary.Ok}</Button > <Button on:click={() => { open = false; currentValue = value; - }}>Cancel</Button + }}>{dictionary.Cancel}</Button > </div> </Dialog> diff --git a/packages/svelte-ux/src/lib/components/DateRange.svelte b/packages/svelte-ux/src/lib/components/DateRange.svelte index 6962eb284..7d253f6ba 100644 --- a/packages/svelte-ux/src/lib/components/DateRange.svelte +++ b/packages/svelte-ux/src/lib/components/DateRange.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { format, isAfter, isBefore, isSameDay } from 'date-fns'; + import { isAfter, isBefore, isSameDay } from 'date-fns'; import { PeriodType, @@ -7,7 +7,6 @@ getDateFuncsByPeriodType, hasDayOfWeek, replaceDayOfWeek, - getPeriodTypeName, } from '../utils/date'; import { getDateRangePresets } from '../utils/dateRange'; import type { DateRange } from '../utils/dateRange'; @@ -18,17 +17,17 @@ import MenuField from './MenuField.svelte'; import ToggleGroup from './ToggleGroup.svelte'; import ToggleOption from './ToggleOption.svelte'; - import DateField from './DateField.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { mdScreen } from '$lib/stores/matchMedia'; + import { getSettings } from './settings'; export let selected: DateRange | null = { from: null, to: null, periodType: null }; /** Period types to show */ export let periodTypes: PeriodType[] = [ PeriodType.Day, - PeriodType.WeekSun, - PeriodType.BiWeek1Sun, + PeriodType.Week, + PeriodType.BiWeek1, // PeriodType.BiWeek2Sun, PeriodType.Month, PeriodType.Quarter, @@ -37,22 +36,24 @@ ]; export let getPeriodTypePresets = getDateRangePresets; - const theme = getComponentTheme('DateRange'); + const settingsClasses = getComponentClasses('DateRange'); + const { format, localeSettings } = getSettings(); let selectedPeriodType = selected?.periodType ?? periodTypes[0]; let selectedPreset: string | null = null; - let selectedDayOfWeek: DayOfWeek = DayOfWeek.SUN; + let selectedDayOfWeek: DayOfWeek = + $format.settings.formats.dates.weekStartsOn ?? DayOfWeek.Sunday; let activeDate: 'from' | 'to' = 'from'; $: periodTypeOptions = periodTypes.map((pt) => { const value = adjustPeriodType(pt); return { - label: getPeriodTypeName(adjustPeriodType(pt)), + label: $format.getPeriodTypeName(adjustPeriodType(pt)), value, }; }); - $: presetOptions = getPeriodTypePresets(selectedPeriodType).map((preset) => { + $: presetOptions = getPeriodTypePresets($localeSettings, selectedPeriodType).map((preset) => { return { label: preset.label, value: getDateRangeStr(preset.value), @@ -69,35 +70,37 @@ // Apply date-fns function based on type and from/to. let newSelected = { ...selected, periodType: selectedPeriodType }; - const { start, end } = getDateFuncsByPeriodType(selectedPeriodType); + const { start, end } = getDateFuncsByPeriodType($localeSettings, selectedPeriodType); let newActiveDate: typeof activeDate = activeDate === 'from' ? 'to' : 'from'; if (activeDate === 'from') { newSelected.from = start(date); - if (selected.to != null && isAfter(date, selected.to)) { + if (selected!.to != null && isAfter(date, selected!.to)) { newSelected.to = end(date); } } else { newSelected.to = end(date); - if (selected.from != null && isBefore(date, selected.from)) { + if (selected!.from != null && isBefore(date, selected!.from)) { newSelected.from = start(date); newActiveDate = 'to'; } } + // TODO + // @ts-expect-error (null / undefined issue...) selected = newSelected; activeDate = newActiveDate; } // Expand selection range to match period type (day => month, etc) function onPeriodTypeChange(periodType: PeriodType) { - const { start, end } = getDateFuncsByPeriodType(periodType); - if (selected.from) { - selected.from = start(selected.from); + const { start, end } = getDateFuncsByPeriodType($localeSettings, periodType); + if (selected!.from) { + selected!.from = start(selected!.from); } - if (selected.to) { - selected.to = end(selected.to); + if (selected!.to) { + selected!.to = end(selected!.to); } } @@ -117,19 +120,21 @@ const newSelected = { ...selected, periodType: newPeriodType }; // Attempt to maintain selected preset if labels match - if (selected.from && selected.to && selected.periodType) { - const prevPeriodTypePreset = [...getPeriodTypePresets(selected.periodType)].find( + if (selected?.from && selected?.to && selected.periodType) { + const prevPeriodTypePreset = [ + ...getPeriodTypePresets($localeSettings, selected.periodType), + ].find( (x) => x.value.from && - isSameDay(x.value.from, selected.from) && + isSameDay(x.value.from, selected!.from!) && x.value.to && - isSameDay(x.value.to, selected.to) + isSameDay(x.value.to, selected!.to!) ); if (prevPeriodTypePreset && newPeriodType) { - const newPeriodTypePreset = [...getPeriodTypePresets(newPeriodType)].find( - (x) => x.label === prevPeriodTypePreset.label - ); + const newPeriodTypePreset = [ + ...getPeriodTypePresets($localeSettings, newPeriodType), + ].find((x) => x.label === prevPeriodTypePreset.label); if (newPeriodTypePreset) { newSelected.from = newPeriodTypePreset.value.from; @@ -138,6 +143,8 @@ } } + // TODO + // @ts-expect-error (null / undefined issue...) selected = newSelected; } } @@ -159,18 +166,18 @@ 'DateRange grid gap-2', 'w-[min(90vw,384px)]', showSidebar && 'md:w-[640px] md:grid-cols-[2fr,3fr]', - theme.root, + settingsClasses.root, $$props.class )} > <div class={cls(showSidebar && 'md:col-start-2')}> - <ToggleGroup bind:value={activeDate} variant="outline" inset class="bg-white"> + <ToggleGroup bind:value={activeDate} variant="outline" inset class="bg-surface-100"> <ToggleOption value="from" class="flex-1"> - <div class="text-xs text-black/50">Start</div> - {#if selected.from} - <div class="font-medium">{format(selected.from, 'M/d/yyyy')}</div> + <div class="text-xs text-surface-content/50">{$localeSettings.dictionary.Date.Start}</div> + {#if selected?.from} + <div class="font-medium">{$format(selected.from, PeriodType.Day)}</div> {:else} - <div class="italic">Empty</div> + <div class="italic">{$localeSettings.dictionary.Date.Empty}</div> {/if} <!-- <div class="p-1"> <DateField @@ -188,11 +195,11 @@ </ToggleOption> <ToggleOption value="to" class="flex-1"> - <div class="text-xs text-black/50">End</div> - {#if selected.to} - <div class="font-medium">{format(selected.to, 'M/d/yyyy')}</div> + <div class="text-xs text-surface-content/50">{$localeSettings.dictionary.Date.End}</div> + {#if selected?.to} + <div class="font-medium">{$format(selected.to, PeriodType.Day)}</div> {:else} - <div class="italic">Empty</div> + <div class="italic">{$localeSettings.dictionary.Date.Empty}</div> {/if} <!-- <div class="p-1"> <DateField @@ -216,14 +223,13 @@ {#if showPeriodTypes} {#if $mdScreen} <div> - <div class="text-xs text-black/50 uppercase mb-1">Type</div> + <div class="text-xs text-surface-content/50 uppercase mb-1">Type</div> <ToggleGroup bind:value={selectedPeriodType} on:change={(e) => onPeriodTypeChange(e.detail.value)} variant="outline" inset vertical - class="bg-white" > {#each periodTypeOptions as option} <ToggleOption value={option.value}> @@ -246,14 +252,8 @@ {#key selectedPeriodType} {#if $mdScreen} <div> - <div class="text-xs text-black/50 uppercase mb-1">Presets</div> - <ToggleGroup - bind:value={selectedPreset} - variant="outline" - inset - vertical - class="bg-white" - > + <div class="text-xs text-surface-content/50 uppercase mb-1">Presets</div> + <ToggleGroup bind:value={selectedPreset} variant="outline" inset vertical> {#each presetOptions as option} <ToggleOption value={option.value} @@ -281,27 +281,23 @@ {#if hasDayOfWeek(selectedPeriodType)} <div> - <div class="text-xs text-black/50 uppercase mb-1">Start day of week</div> + <div class="text-xs text-surface-content/50 uppercase mb-1">Start day of week</div> <ToggleGroup bind:value={selectedDayOfWeek} variant="outline" inset - classes={{ root: 'bg-white', option: 'px-0' }} + classes={{ root: 'bg-surface-100', option: 'px-0' }} > - <ToggleOption value={DayOfWeek.SUN}>Sun</ToggleOption> - <ToggleOption value={DayOfWeek.MON}>Mon</ToggleOption> - <ToggleOption value={DayOfWeek.TUE}>Tue</ToggleOption> - <ToggleOption value={DayOfWeek.WED}>Wed</ToggleOption> - <ToggleOption value={DayOfWeek.THU}>Thu</ToggleOption> - <ToggleOption value={DayOfWeek.FRI}>Fri</ToggleOption> - <ToggleOption value={DayOfWeek.SAT}>Sat</ToggleOption> + {#each [DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday, DayOfWeek.Thursday, DayOfWeek.Friday, DayOfWeek.Saturday] as day} + <ToggleOption value={day}>{$format.getDayOfWeekName(day)}</ToggleOption> + {/each} </ToggleGroup> </div> {/if} </div> {/if} - <div class="bg-white border rounded overflow-auto"> + <div class="bg-surface-100 border rounded overflow-auto"> <DateSelect {selected} periodType={selectedPeriodType} diff --git a/packages/svelte-ux/src/lib/components/DateRangeDisplay.svelte b/packages/svelte-ux/src/lib/components/DateRangeDisplay.svelte index a7d95b70e..45c2d593e 100644 --- a/packages/svelte-ux/src/lib/components/DateRangeDisplay.svelte +++ b/packages/svelte-ux/src/lib/components/DateRangeDisplay.svelte @@ -1,18 +1,16 @@ <script lang="ts"> - import { formatDate, PeriodType, getDateFuncsByPeriodType } from '../utils/date'; + import { PeriodType, getDateFuncsByPeriodType, type FormatDateOptions } from '../utils/date'; import type { DateRange } from '../utils/dateRange'; - - import { dateDisplay } from '../utils/dateDisplay'; + import { getSettings } from './settings'; export let value: DateRange | null | undefined; - export let variant: Parameters<typeof formatDate>[2] = undefined; - export let format: string = undefined; - export let utc: boolean = undefined; + + const { format: format_ux, localeSettings } = getSettings(); let showToValue = false; $: if (value?.to) { if (value?.from && value?.periodType) { - const { isSame } = getDateFuncsByPeriodType(value.periodType); + const { isSame } = getDateFuncsByPeriodType($localeSettings, value.periodType); switch (value.periodType) { case PeriodType.Day: @@ -30,49 +28,54 @@ } } - $: periodType = value?.periodType; - - // Override periodTypes that show ranges for individual values - $: switch (periodType) { - case PeriodType.WeekSun: - case PeriodType.WeekMon: - case PeriodType.WeekTue: - case PeriodType.WeekWed: - case PeriodType.WeekThu: - case PeriodType.WeekFri: - case PeriodType.WeekSat: + const getPeriodType = (value: DateRange | null | undefined) => { + let periodType = value?.periodType ?? PeriodType.Day; + // Override periodTypes that show ranges for individual values + switch (periodType) { + case PeriodType.WeekSun: + case PeriodType.WeekMon: + case PeriodType.WeekTue: + case PeriodType.WeekWed: + case PeriodType.WeekThu: + case PeriodType.WeekFri: + case PeriodType.WeekSat: + case PeriodType.Week: - case PeriodType.BiWeek1Sun: - case PeriodType.BiWeek1Mon: - case PeriodType.BiWeek1Tue: - case PeriodType.BiWeek1Wed: - case PeriodType.BiWeek1Thu: - case PeriodType.BiWeek1Fri: - case PeriodType.BiWeek1Sat: + case PeriodType.BiWeek1Sun: + case PeriodType.BiWeek1Mon: + case PeriodType.BiWeek1Tue: + case PeriodType.BiWeek1Wed: + case PeriodType.BiWeek1Thu: + case PeriodType.BiWeek1Fri: + case PeriodType.BiWeek1Sat: + case PeriodType.BiWeek1: - case PeriodType.BiWeek2Sun: - case PeriodType.BiWeek2Mon: - case PeriodType.BiWeek2Tue: - case PeriodType.BiWeek2Wed: - case PeriodType.BiWeek2Thu: - case PeriodType.BiWeek2Fri: - case PeriodType.BiWeek2Sat: - periodType = PeriodType.Day; - break; + case PeriodType.BiWeek2Sun: + case PeriodType.BiWeek2Mon: + case PeriodType.BiWeek2Tue: + case PeriodType.BiWeek2Wed: + case PeriodType.BiWeek2Thu: + case PeriodType.BiWeek2Fri: + case PeriodType.BiWeek2Sat: + case PeriodType.BiWeek2: + periodType = PeriodType.Day; + break; - case PeriodType.Quarter: - periodType = PeriodType.Month; - break; - } + case PeriodType.Quarter: + periodType = PeriodType.Month; + break; + } + return periodType; + }; </script> {#if value?.from} - {dateDisplay(value.from, { periodType, format, variant, utc })} + {$format_ux(value.from, getPeriodType(value), { variant: 'long' })} {:else} <div> </div> {/if} {#if value?.to && showToValue} <span> - </span> - {dateDisplay(value.to, { periodType, format, variant, utc })} + {$format_ux(value.to, getPeriodType(value), { variant: 'long' })} {/if} diff --git a/packages/svelte-ux/src/lib/components/DateRangeField.svelte b/packages/svelte-ux/src/lib/components/DateRangeField.svelte index 573c9c0bb..e048a1572 100644 --- a/packages/svelte-ux/src/lib/components/DateRangeField.svelte +++ b/packages/svelte-ux/src/lib/components/DateRangeField.svelte @@ -8,11 +8,13 @@ import Dialog from './Dialog.svelte'; import Field from './Field.svelte'; - import { PeriodType, getDateFuncsByPeriodType, getPeriodTypeName } from '../utils/date'; + import { PeriodType, getDateFuncsByPeriodType } from '../utils/date'; import { getDateRangePresets, type DateRange as DateRangeType } from '../utils/dateRange'; import { cls } from '../utils/styles'; + import { getSettings } from './settings'; const dispatch = createEventDispatcher(); + const { format, localeSettings } = getSettings(); const _defaultValue: DateRangeType = { from: null, @@ -25,9 +27,9 @@ export let center: boolean = false; export let periodTypes: PeriodType[] = [ PeriodType.Day, - PeriodType.WeekSun, - PeriodType.BiWeek1Sun, - // PeriodType.BiWeek2Sun, + PeriodType.Week, + PeriodType.BiWeek1, + // PeriodType.BiWeek2, PeriodType.Month, PeriodType.Quarter, PeriodType.CalendarYear, @@ -53,13 +55,12 @@ export let icon: string | null = null; let open: boolean = false; - let format: string = undefined; let currentValue = value; </script> <Field - label={label ?? (value.periodType ? getPeriodTypeName(value.periodType) : '')} + label={label ?? (value.periodType ? $format.getPeriodTypeName(value.periodType) : '')} {icon} {error} {hint} @@ -81,7 +82,10 @@ class="p-2" on:click={() => { if (value && value.from && value.to && value.periodType) { - const { difference, start, end, add } = getDateFuncsByPeriodType(value.periodType); + const { difference, start, end, add } = getDateFuncsByPeriodType( + $localeSettings, + value.periodType + ); const offset = difference(value.from, value.to) - 1; value = { from: start(add(value.from, offset)), @@ -104,14 +108,14 @@ on:click={() => (open = true)} {id} > - <DateRangeDisplay {value} {format} /> + <DateRangeDisplay {value} /> </button> <div slot="append" class="flex items-center"> {#if clearable && (value?.periodType || value?.from || value?.to)} <Button icon={mdiClose} - class="text-black/50 p-1" + class="text-surface-content/50 p-1" on:click={() => { value = _defaultValue; dispatch('clear'); @@ -128,7 +132,10 @@ class="p-2" on:click={() => { if (value && value.from && value.to && value.periodType) { - const { difference, start, end, add } = getDateFuncsByPeriodType(value.periodType); + const { difference, start, end, add } = getDateFuncsByPeriodType( + $localeSettings, + value.periodType + ); const offset = difference(value.to, value.from) + 1; value = { from: start(add(value.from, offset)), @@ -150,11 +157,11 @@ }} bind:open > - <div class="flex flex-col justify-center bg-accent-500 text-white px-6 h-24"> - <div class="text-sm text-white/50"> - {currentValue.periodType ? getPeriodTypeName(currentValue.periodType) : ''} + <div class="flex flex-col justify-center bg-primary text-primary-content px-6 h-24"> + <div class="text-sm opacity-50"> + {currentValue.periodType ? $format.getPeriodTypeName(currentValue.periodType) : ''} </div> - <div class="text-xl sm:text-2xl text-white"> + <div class="text-xl sm:text-2xl"> <DateRangeDisplay value={currentValue} /> </div> </div> @@ -171,10 +178,10 @@ value = currentValue; dispatch('change', value); }} - color="blue" + color="primary" variant="fill" > - OK + {$localeSettings.dictionary.Ok} </Button> <Button @@ -183,7 +190,7 @@ currentValue = value; }} > - Cancel + {$localeSettings.dictionary.Cancel} </Button> </div> </Dialog> diff --git a/packages/svelte-ux/src/lib/components/Dialog.svelte b/packages/svelte-ux/src/lib/components/Dialog.svelte index 108e774a1..f6bf027dc 100644 --- a/packages/svelte-ux/src/lib/components/Dialog.svelte +++ b/packages/svelte-ux/src/lib/components/Dialog.svelte @@ -12,7 +12,7 @@ import Backdrop from './Backdrop.svelte'; import ProgressCircle from './ProgressCircle.svelte'; import Overlay from './Overlay.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; const dispatch = createEventDispatcher(); @@ -28,7 +28,7 @@ actions?: string; backdrop?: string; } = {}; - const theme = getComponentTheme('Dialog'); + const settingsClasses = getComponentClasses('Dialog'); let dialogEl: HTMLDivElement; let actionsEl: HTMLDivElement; @@ -76,7 +76,7 @@ // Do not allow event to reach Popover's on:mouseup (clickOutside) e.stopPropagation(); }} - class={cls('z-50', theme.backdrop, classes.backdrop)} + class={cls('z-50', settingsClasses.backdrop, classes.backdrop)} fadeParams={{ duration: 150 }} {portal} /> @@ -85,7 +85,7 @@ class={cls( 'Dialog', 'fixed top-0 left-0 w-full h-full z-50 flex items-center justify-center pointer-events-none', - theme.root, + settingsClasses.root, classes.root )} on:click={onClick} @@ -108,8 +108,8 @@ > <div class={cls( - 'dialog rounded bg-white elevation-4 overflow-y-auto pointer-events-auto relative outline-none', - theme.dialog, + 'dialog rounded bg-surface-100 elevation-4 overflow-y-auto pointer-events-auto relative outline-none', + settingsClasses.dialog, classes.dialog, $$props.class )} @@ -131,7 +131,9 @@ <slot name="header"> {#if $$slots.title} - <div class={cls('text-xl font-bold pt-4 pb-2 px-6', theme.title, classes.title)}> + <div + class={cls('text-xl font-bold pt-4 pb-2 px-6', settingsClasses.title, classes.title)} + > <slot name="title" /> </div> {/if} @@ -142,8 +144,8 @@ {#if $$slots.actions} <div class={cls( - 'actions flex w-full justify-end p-2 bg-black/5 border-t', - theme.actions, + 'actions flex w-full justify-end p-2 bg-surface-content/5 border-t', + settingsClasses.actions, classes.actions )} bind:this={actionsEl} diff --git a/packages/svelte-ux/src/lib/components/DividerDot.svelte b/packages/svelte-ux/src/lib/components/DividerDot.svelte index 674ea3da8..13b715be4 100644 --- a/packages/svelte-ux/src/lib/components/DividerDot.svelte +++ b/packages/svelte-ux/src/lib/components/DividerDot.svelte @@ -1,8 +1,8 @@ <script lang="ts"> import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; - const theme = getComponentTheme('DividerDot'); + const settingsClasses = getComponentClasses('DividerDot'); </script> -<span class={cls('DividerDot mx-1', theme.root, $$props.class)}> • </span> +<span class={cls('DividerDot mx-1', settingsClasses.root, $$props.class)}> • </span> diff --git a/packages/svelte-ux/src/lib/components/Drawer.svelte b/packages/svelte-ux/src/lib/components/Drawer.svelte index 16a61fd82..8ac3a07f9 100644 --- a/packages/svelte-ux/src/lib/components/Drawer.svelte +++ b/packages/svelte-ux/src/lib/components/Drawer.svelte @@ -9,7 +9,7 @@ import { focusMove } from '../actions/focus'; import { portal as portalAction, type PortalOptions } from '../actions/portal'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; const dispatch = createEventDispatcher(); @@ -22,8 +22,9 @@ export let classes: { root?: string; backdrop?: string; + actions?: string; } = {}; - const theme = getComponentTheme('Drawer'); + const settingsClasses = getComponentClasses('Drawer'); $: dispatch('change', { open }); @@ -44,14 +45,14 @@ // Do not allow event to reach Popover's on:mouseup (clickOutside) e.stopPropagation(); }} - class={cls('z-50', theme.backdrop, classes.backdrop)} + class={cls('z-50', settingsClasses.backdrop, classes.backdrop)} {portal} /> <div class={cls( 'Drawer', - 'bg-white fixed overflow-auto transform z-50 outline-none', + 'bg-surface-100 fixed overflow-auto transform z-50 outline-none', { 'h-full': ['left', 'right'].includes(placement), 'w-full': ['top', 'bottom'].includes(placement), @@ -60,7 +61,7 @@ 'left-0': ['top', 'top', 'bottom'].includes(placement), 'right-0': placement === 'right', }, - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -102,5 +103,17 @@ {/if} <slot {open} /> + + {#if $$slots.actions} + <div + class={cls( + 'actions fixed bottom-0 w-full flex justify-center bg-surface-content/5 p-1 border-t', + settingsClasses.actions, + classes.actions + )} + > + <slot name="actions" /> + </div> + {/if} </div> {/if} diff --git a/packages/svelte-ux/src/lib/components/Duration.svelte b/packages/svelte-ux/src/lib/components/Duration.svelte index b0e76bbd5..979036727 100644 --- a/packages/svelte-ux/src/lib/components/Duration.svelte +++ b/packages/svelte-ux/src/lib/components/Duration.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { DurationUnits, getDuration, humanizeDuration } from '../utils/duration'; import timerStore from '../stores/timerStore'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { cls } from '$lib/utils/styles'; export let start: Date | undefined = undefined; @@ -11,7 +11,7 @@ export let totalUnits: number = 99; export let variant: 'short' | 'long' = 'short'; - const theme = getComponentTheme('Duration'); + const settingsClasses = getComponentClasses('Duration'); function getDelay() { const newDuration = getDuration(start, end ?? $timer, duration); @@ -57,4 +57,4 @@ }); </script> -<span class={cls('Duration', theme.root, $$props.class)}>{displayDuration}</span> +<span class={cls('Duration', settingsClasses.root, $$props.class)}>{displayDuration}</span> diff --git a/packages/svelte-ux/src/lib/components/EmptyMessage.svelte b/packages/svelte-ux/src/lib/components/EmptyMessage.svelte index 9f7ea1590..bbd8296d4 100644 --- a/packages/svelte-ux/src/lib/components/EmptyMessage.svelte +++ b/packages/svelte-ux/src/lib/components/EmptyMessage.svelte @@ -1,8 +1,8 @@ <script lang="ts"> import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; - const theme = getComponentTheme('EmptyMessage'); + const settingsClasses = getComponentClasses('EmptyMessage'); </script> <div @@ -10,10 +10,10 @@ class={cls( 'EmptyMessage', 'grid place-items-center', - 'p-1 bg-black/10 shadow-inner ring-1 ring-black/30', - 'text-black/50 text-xs tracking-wider', - 'border rounded', - theme.root, + 'p-1 bg-surface-300 _shadow-inner _ring-1 ring-surface-200/30', + 'text-surface-content/50 text-xs tracking-wider', + 'border border-surface-100/80 rounded', + settingsClasses.root, $$props.class )} > diff --git a/packages/svelte-ux/src/lib/components/ErrorNotification.svelte b/packages/svelte-ux/src/lib/components/ErrorNotification.svelte index 945e77043..0675503cc 100644 --- a/packages/svelte-ux/src/lib/components/ErrorNotification.svelte +++ b/packages/svelte-ux/src/lib/components/ErrorNotification.svelte @@ -40,12 +40,12 @@ e.stopPropagation(); toggle(); }} - class="text-accent-500" + class="primary" > View Details </Button> {/if} - <Button class={hasDetails ? '' : 'text-accent-500'}>Dismiss</Button> + <Button color={hasDetails ? 'default' : 'primary'}>Dismiss</Button> </div> </Notification> @@ -61,7 +61,7 @@ <div class="grid gap-4 p-6"> {#if stackTrace} <div> - <div class="text-xs text-black/50 mb-1">Stacktrace:</div> + <div class="text-xs text-surface-content/50 mb-1">Stacktrace:</div> <pre class="bg-gray-100 border rounded p-2 text-xs"> {stackTrace ?? '<Empty>'} </pre> @@ -70,7 +70,7 @@ </div> <div slot="actions"> - <Button on:click={toggle} class="text-accent-500 hover:bg-accent-50">Close</Button> + <Button color="primary" on:click={toggle}>Close</Button> </div> </Dialog> </Toggle> diff --git a/packages/svelte-ux/src/lib/components/ExpansionPanel.svelte b/packages/svelte-ux/src/lib/components/ExpansionPanel.svelte index e58b769b0..b6669289d 100644 --- a/packages/svelte-ux/src/lib/components/ExpansionPanel.svelte +++ b/packages/svelte-ux/src/lib/components/ExpansionPanel.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import Collapse from './Collapse.svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; /** * Controls how first, last, and gap between are calculated @@ -21,7 +21,7 @@ root?: string; toggle?: string; } = {}; - const theme = getComponentTheme('ExpansionPanel'); + const settingsClasses = getComponentClasses('ExpansionPanel'); </script> <Collapse @@ -29,16 +29,16 @@ classes={{ root: cls( 'ExpansionPanel', - 'bg-white elevation-1 border-t', + 'bg-surface-100 elevation-1 border-t', 'relative', // Match ListItem (used for loading) so Stacking Context is consistent (else causes a solid line between ExpansionPanel and ListItem) list === 'type' && 'first-of-type:border-t-0 first-of-type:rounded-t last-of-type:rounded-b', list === 'parent' && 'first:border-t-0 first:rounded-t last:rounded-b', list === 'group' && 'group-first:border-t-0 group-first:rounded-t group-last:rounded-b', - theme.root, + settingsClasses.root, classes.root, $$props.class ), - icon: cls('text-gray-500 px-2', !enabled && 'hidden'), + icon: cls('text-surface-content/30 px-2', !enabled && 'hidden'), }} popout {list} @@ -49,7 +49,7 @@ <slot name="actions" /> {#if enabled} - <div class={cls('px-3 pt-2 pb-3', theme.toggle, classes.toggle)}> + <div class={cls('px-3 pt-2 pb-3', settingsClasses.toggle, classes.toggle)}> <slot /> </div> {/if} diff --git a/packages/svelte-ux/src/lib/components/Field.svelte b/packages/svelte-ux/src/lib/components/Field.svelte index 4ccc88161..eeb1632bc 100644 --- a/packages/svelte-ux/src/lib/components/Field.svelte +++ b/packages/svelte-ux/src/lib/components/Field.svelte @@ -4,7 +4,7 @@ import { uniqueId } from 'lodash-es'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import Button from './Button.svelte'; import Icon from './Icon.svelte'; @@ -41,7 +41,7 @@ prepend?: string; append?: string; } = {}; - const theme = getComponentTheme('Field'); + const settingsClasses = getComponentClasses('Field'); $: hasValue = Array.isArray(value) ? value.length > 0 @@ -61,10 +61,10 @@ 'Field', 'group flex gap-1', labelPlacement !== 'left' ? 'flex-col' : 'items-center', - error ? '[--color:theme(colors.red.500)]' : '[--color:theme(colors.accent.500)]', + error ? '[--color:theme(colors.danger)]' : '[--color:theme(colors.primary)]', disabled && 'opacity-50 pointer-events-none', !base && (rounded ? 'rounded-full' : 'rounded'), - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -73,10 +73,10 @@ <label class={cls( 'block text-sm font-medium', - 'truncate group-hover:text-gray-700 group-focus-within:text-accent-500 group-hover:group-focus-within:text-[var(--color)] cursor-pointer', - error ? 'text-red-500/80' : 'text-black/50', + 'truncate group-hover:text-surface-content/70 group-focus-within:text-primary group-hover:group-focus-within:text-[var(--color)] cursor-pointer', + error ? 'text-danger/80' : 'text-surface-content/50', `placement-${labelPlacement}`, - theme.label, + settingsClasses.label, classes.label )} for={id} @@ -91,15 +91,15 @@ class={cls( 'border py-0 transition-shadow', disabled ? '' : 'hover:shadow', - disabled ? '' : error ? 'hover:border-red-700' : 'hover:border-gray-700', + disabled ? '' : error ? 'hover:border-danger' : 'hover:border-surface-content', { 'px-2': !rounded, 'px-6': rounded && !hasPrepend, }, - !base && ['bg-white', rounded ? 'rounded-full' : 'rounded'], - error ? 'border-red-500' : 'border-black/20', + !base && ['bg-surface-100', rounded ? 'rounded-full' : 'rounded'], + error && 'border-danger', 'group-focus-within:shadow-md group-focus-within:border-[var(--color)]', - theme.container, + settingsClasses.container, classes.container )} > @@ -108,7 +108,7 @@ <div class={cls( 'prepend whitespace-nowrap flex items-center', - theme.prepend, + settingsClasses.prepend, classes.prepend )} > @@ -116,7 +116,7 @@ {#if icon} <span class={cls('mr-3', rounded && !$$slots.prepend && 'ml-3')}> - <Icon path={icon} class="text-black/50" /> + <Icon path={icon} class="text-surface-content/50" /> </span> {/if} </div> @@ -127,12 +127,12 @@ {#if label && ['inset', 'float'].includes(labelPlacement)} <label class={cls( - 'col-span-full row-span-full z-[1] flex items-center h-full truncate origin-top-left transition-all duration-200 group-hover:text-gray-700 group-focus-within:text-[var(--color)] group-hover:group-focus-within:text-[var(--color)] cursor-pointer', + 'col-span-full row-span-full z-[1] flex items-center h-full truncate origin-top-left transition-all duration-200 group-hover:text-surface-content/70 group-focus-within:text-[var(--color)] group-hover:group-focus-within:text-[var(--color)] cursor-pointer', center && 'justify-center', - error ? 'text-red-500/80' : 'text-black/50', + error ? 'text-danger/80' : 'text-surface-content/50', `placement-${labelPlacement}`, (labelPlacement === 'inset' || hasValue) && 'shrink', - theme.label, + settingsClasses.label, classes.label )} for={id} @@ -148,7 +148,7 @@ hasInsetLabel && 'pt-4', dense ? 'my-1' : 'my-2', center && 'text-center', - theme.input, + settingsClasses.input, classes.input )} > @@ -161,12 +161,12 @@ </div> {#if hasAppend} - <div class={cls('append whitespace-nowrap', theme.append, classes.append)}> + <div class={cls('append whitespace-nowrap', settingsClasses.append, classes.append)}> {#if clearable && hasValue} <Button icon={mdiClose} {disabled} - class="text-black/50 p-1" + class="text-surface-content/50 p-1" on:click={() => { value = Array.isArray(value) ? [] : typeof value === 'string' ? '' : null; dispatch('clear'); @@ -178,9 +178,9 @@ <slot name="append" /> {#if error} - <Icon path={mdiInformationOutline} class="text-red-500" /> + <Icon path={mdiInformationOutline} class="text-danger" /> {:else if iconRight} - <Icon path={iconRight} class="text-black/50" /> + <Icon path={iconRight} class="text-surface-content/50" /> {/if} </div> {/if} @@ -190,8 +190,8 @@ class={cls( error ? 'error' : 'hint', 'text-xs ml-2 transition-transform ease-out overflow-hidden origin-top transform group-focus-within:scale-y-100', - error ? 'text-red-500' : 'text-black/50 scale-y-0', - theme.error, + error ? 'text-danger' : 'text-surface-content/50 scale-y-0', + settingsClasses.error, classes.error )} > diff --git a/packages/svelte-ux/src/lib/components/Form.svelte b/packages/svelte-ux/src/lib/components/Form.svelte index 58882c429..5a8e10919 100644 --- a/packages/svelte-ux/src/lib/components/Form.svelte +++ b/packages/svelte-ux/src/lib/components/Form.svelte @@ -3,7 +3,7 @@ import type { Schema } from 'zod'; import formStore from '../stores/formStore'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { cls } from '$lib/utils/styles'; const dispatch = createEventDispatcher(); @@ -11,7 +11,7 @@ export let initial: any = {}; export let schema: Schema | undefined = undefined; - const theme = getComponentTheme('Form'); + const settingsClasses = getComponentClasses('Form'); const [state, draft, errors] = formStore(initial, { schema }); $: current = draft.current; @@ -26,7 +26,7 @@ on:reset|preventDefault={(e) => { draft.revert(); }} - class={cls(theme.root, $$props.class)} + class={cls(settingsClasses.root, $$props.class)} {...$$restProps} > <slot diff --git a/packages/svelte-ux/src/lib/components/Gooey.svelte b/packages/svelte-ux/src/lib/components/Gooey.svelte index e08a0bc0b..375980c49 100644 --- a/packages/svelte-ux/src/lib/components/Gooey.svelte +++ b/packages/svelte-ux/src/lib/components/Gooey.svelte @@ -3,7 +3,7 @@ import { uniqueId } from '$lib/utils/string'; import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; /** Apply gaussian blur. Required unless blurring externally (`filter: blur()`, etc) */ export let blur: number | undefined = undefined; @@ -21,12 +21,12 @@ root?: string; svg?: string; } = {}; - const theme = getComponentTheme('Gooey'); + const settingsClasses = getComponentClasses('Gooey'); const filterId = uniqueId('filter-'); </script> -<svg class={cls('fixed inset-0 pointer-events-none', theme.svg, classes?.svg)}> +<svg class={cls('fixed inset-0 pointer-events-none', settingsClasses.svg, classes?.svg)}> <filter id={filterId}> {#if blur} <feGaussianBlur in="SourceGraphic" stdDeviation={blur} result="blur" /> @@ -51,7 +51,7 @@ <div style:filter="url(#{filterId})" {...$$restProps} - class={cls('inline-block', theme.root, classes?.root, $$props.class)} + class={cls('inline-block', settingsClasses.root, classes?.root, $$props.class)} > <slot /> </div> diff --git a/packages/svelte-ux/src/lib/components/Grid.svelte b/packages/svelte-ux/src/lib/components/Grid.svelte index 6ce3c11bf..c1b37168d 100644 --- a/packages/svelte-ux/src/lib/components/Grid.svelte +++ b/packages/svelte-ux/src/lib/components/Grid.svelte @@ -1,6 +1,4 @@ <script lang="ts"> - import { cssVars } from '../actions/cssVars'; - export let columns = 0; export let gap = 0; export let columnGap = gap; @@ -38,28 +36,23 @@ templateColumns ?? template ?? (autoColumns ? `repeat(auto-fill, minmax(${autoColumns}, 1fr))` : `repeat(${columns}, 1fr)`); - - $: styleVars = { - templateColumns: templateColumnsResolved, - templateRows, - gap, - columnGap, - rowGap, - autoFlow, - items, // TODO: Map start: flex-start?, end: flex-end? - justify, // TODO: Map start: flex-start?, end: flex-end?, between: space-between, around: space-around, evenly: space-evenly - justifyItems, // TODO: Map start: flex-start?, end: flex-end?, between: space-between, around: space-around, evenly: space-evenly - content, // TODO: Map start: flex-start?, end: flex-end?, between: space-between, around: space-around, evenly: space-evenly - // place, // TODO: Map start: flex-start?, end: flex-end?, between: space-between, around: space-around, evenly: space-evenly - }; </script> <div - use:cssVars={styleVars} class="Grid" class:grid={!inline} class:inline-grid={inline} class:stack + style:--templateColumns={templateColumnsResolved} + style:--templateRows={templateRows} + style:--gap={gap} + style:--columnGap={columnGap} + style:--rowGap={rowGap} + style:--autoFlow={autoFlow} + style:--items={items} + style:--justify={justify} + style:--justifyItems={justifyItems} + style:--content={content} on:click {...$$restProps} > diff --git a/packages/svelte-ux/src/lib/components/Header.svelte b/packages/svelte-ux/src/lib/components/Header.svelte index d1396280e..c3e5c64aa 100644 --- a/packages/svelte-ux/src/lib/components/Header.svelte +++ b/packages/svelte-ux/src/lib/components/Header.svelte @@ -1,15 +1,15 @@ <script lang="ts"> import { cls } from '$lib/utils/styles'; import Breadcrumb from './Breadcrumb.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let title: string | string[] | null = null; export let subheading: string | string[] | null = null; - const theme = getComponentTheme('Header'); + const settingsClasses = getComponentClasses('Header'); </script> -<div class={cls('Header', 'flex items-center gap-4', theme.root, $$props.class)}> +<div class={cls('Header', 'flex items-center gap-4', settingsClasses.root, $$props.class)}> <slot name="avatar" /> <div class="flex-1"> @@ -26,9 +26,9 @@ <slot name="subheading"> {#if subheading} {#if Array.isArray(subheading)} - <Breadcrumb items={subheading} class="text-sm text-black/50" /> + <Breadcrumb items={subheading} class="text-sm text-surface-content/50" /> {:else} - <div class="text-sm text-black/50">{subheading}</div> + <div class="text-sm text-surface-content/50">{subheading}</div> {/if} {/if} </slot> diff --git a/packages/svelte-ux/src/lib/components/Icon.svelte b/packages/svelte-ux/src/lib/components/Icon.svelte index c29608ee2..361ce64fa 100644 --- a/packages/svelte-ux/src/lib/components/Icon.svelte +++ b/packages/svelte-ux/src/lib/components/Icon.svelte @@ -7,7 +7,7 @@ import { uniqueId } from '../utils/string'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let size: string | number = '1.5em'; export let width = size; @@ -29,7 +29,7 @@ root?: string; path?: string | string[]; } = {}; - const theme = getComponentTheme('Icon'); + const settingsClasses = getComponentClasses('Icon'); $: if (typeof data === 'object' && data && 'icon' in data) { // Font Awesome @@ -65,12 +65,12 @@ .then((resp) => resp.text()) .catch(() => { // Failed request, remove promise so fetched again - if (svgUrl && typeof(svgUrl) === "string") { + if (svgUrl && typeof svgUrl === 'string') { cache.delete(svgUrl); } // TODO: Consider showing error icon // throw e; - return ""; + return ''; }); cache.set(svgUrl, promise); promise.then((text) => { @@ -85,7 +85,7 @@ class={cls( 'Icon', 'icon-container inline-block flex-shrink-0 align-middle fill-current', - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -110,7 +110,7 @@ class={cls( 'Icon', 'inline-block flex-shrink-0 fill-current', - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -131,7 +131,7 @@ {d} fill="currentColor" class={cls( - Array.isArray(theme.path) ? theme.path[i] : theme.path, + Array.isArray(settingsClasses.path) ? settingsClasses.path[i] : settingsClasses.path, Array.isArray(classes.path) ? classes.path[i] : classes.path )} /> diff --git a/packages/svelte-ux/src/lib/components/Input.svelte b/packages/svelte-ux/src/lib/components/Input.svelte index 866a6968d..868586081 100644 --- a/packages/svelte-ux/src/lib/components/Input.svelte +++ b/packages/svelte-ux/src/lib/components/Input.svelte @@ -11,7 +11,7 @@ import { multi } from '../actions/multi'; import type { Actions } from '../actions/multi'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value = ''; export let type: HTMLInputTypeAttribute = 'text'; @@ -24,10 +24,13 @@ export let mask = ''; export let replace = '_'; export let accept: string | RegExp = '\\d'; - export let placeholder = mask; + let placeholderProp: string | undefined = undefined; + export { placeholderProp as placeholder }; export let disabled = false; - const theme = getComponentTheme('Input'); + $: placeholder = placeholderProp ?? mask; + + const settingsClasses = getComponentClasses('Input'); let isFocused = false; @@ -61,7 +64,11 @@ function onInput(e: Event & { currentTarget: HTMLInputElement }) { const el = e.currentTarget; + applyMask(el, mask); + dispatch('change', { value }); + } + function applyMask(el: HTMLInputElement, mask: string) { if (mask) { // For selection (including just cursor position), ... const [i, j] = [el.selectionStart, el.selectionEnd].map((i) => { @@ -73,10 +80,10 @@ el.setSelectionRange(i, j); backspace = false; } - - dispatch('change', { value }); } + $: if (inputEl) applyMask(inputEl, mask); + onMount(() => { // Format on initial to handle partial values as well as different (but compatible) formats (ex. phone numbers) if (mask) { @@ -124,9 +131,9 @@ {...$$restProps} class={cls( 'Input', - 'text-sm w-full outline-none bg-transparent selection:bg-gray-500/30', + 'text-sm w-full outline-none bg-transparent placeholder-surface/50 selection:bg-surface-content/10', mask && (mask == placeholder || isFocused || value) && 'font-mono', - theme.root, + settingsClasses.root, $$props.class )} /> diff --git a/packages/svelte-ux/src/lib/components/Kbd.svelte b/packages/svelte-ux/src/lib/components/Kbd.svelte new file mode 100644 index 000000000..f1aa66f0e --- /dev/null +++ b/packages/svelte-ux/src/lib/components/Kbd.svelte @@ -0,0 +1,37 @@ +<script lang="ts"> + import { cls } from '$lib/utils/styles'; + + // keys + export let control = false; + export let option = false; + export let shift = false; + export let command = false; + + export let variant: 'filled' | 'none' = 'filled'; +</script> + +<kbd + class={cls( + 'font-sans inline-flex gap-1', + variant === 'filled' && 'border border-b-2 bg-surface-200 rounded py-1 px-1', + $$props.class + )} +> + {#if control} + <abbr title="Control" class="no-underline">⌃</abbr> + {/if} + + {#if option} + <abbr title="Option" class="no-underline">⌥</abbr> + {/if} + + {#if shift} + <abbr title="Shift" class="no-underline">⇧</abbr> + {/if} + + {#if command} + <abbr title="Command" class="no-underline">⌘</abbr> + {/if} + + <slot /> +</kbd> diff --git a/packages/svelte-ux/src/lib/components/LanguageSelect.svelte b/packages/svelte-ux/src/lib/components/LanguageSelect.svelte new file mode 100644 index 000000000..a3e777416 --- /dev/null +++ b/packages/svelte-ux/src/lib/components/LanguageSelect.svelte @@ -0,0 +1,49 @@ +<script lang="ts"> + import Button from './Button.svelte'; + import Menu from './Menu.svelte'; + import MenuItem from './MenuItem.svelte'; + import { cls } from '../utils/styles'; + import { getSettings } from './settings'; + const { locale } = getSettings(); + + let open = false; + + type Language = { + name: string; + code: string; + flag: string; + }; + + export let languagesDemo: Language[] = [ + { name: 'English', code: 'en', flag: '🇺🇸' }, + { name: 'Français', code: 'fr', flag: '🇫🇷' }, + // add more for the demo + ]; + $: languageSelected = languagesDemo.find((c) => c.code === $locale)!; +</script> + +<Button on:click={() => (open = !open)} class="font-mono font-semibold" iconOnly={true}> + {languageSelected.code} + <Menu bind:open on:close={() => (open = false)} offset={4} explicitClose resize> + <div class="grid gap-2 p-2 border-b border-surface-content/10"> + {#each languagesDemo as language} + <MenuItem + on:click={() => { + languageSelected = language; + locale.set(language.code); + }} + class={cls( + 'bg-surface-100 text-surface-content font-semibold border shadow', + languageSelected === language && 'ring-2 ring-surface-content' + )} + > + {language.flag} - {language.name} + </MenuItem> + {/each} + </div> + + <div class="p-2 grid grid-cols-[auto,1fr] gap-2 items-center text-xs"> + <span class="font-medium">Affect dates & numbers formats</span> + </div> + </Menu> +</Button> diff --git a/packages/svelte-ux/src/lib/components/Lazy.svelte b/packages/svelte-ux/src/lib/components/Lazy.svelte index cbd75079d..ffbd37416 100644 --- a/packages/svelte-ux/src/lib/components/Lazy.svelte +++ b/packages/svelte-ux/src/lib/components/Lazy.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { cls } from '$lib/utils/styles'; import { intersection } from '../actions/observer'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; /** * Placeholder height. Should match closely to resulting height to reducing scroll bouncing @@ -24,7 +24,7 @@ export let offset: Offset = {}; - const theme = getComponentTheme('Lazy'); + const settingsClasses = getComponentClasses('Lazy'); </script> <div @@ -44,7 +44,7 @@ on:intersecting style:min-height={typeof height === 'number' ? `${height}px` : height} {...$$restProps} - class={cls('Lazy', theme.root, $$props.class)} + class={cls('Lazy', settingsClasses.root, $$props.class)} > {#if show} <slot /> diff --git a/packages/svelte-ux/src/lib/components/ListItem.svelte b/packages/svelte-ux/src/lib/components/ListItem.svelte index ce230a55c..fe8808152 100644 --- a/packages/svelte-ux/src/lib/components/ListItem.svelte +++ b/packages/svelte-ux/src/lib/components/ListItem.svelte @@ -5,7 +5,7 @@ import Overlay from './Overlay.svelte'; import type { ComponentProps } from '../types'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let title: string | number | null = null; export let subheading: string | number | null = null; @@ -41,7 +41,7 @@ title?: string; subheading?: string; } = {}; - const theme = getComponentTheme('ListItem'); + const settingsClasses = getComponentClasses('ListItem'); /** * Show loading overlay @@ -53,14 +53,14 @@ <li class={cls( 'ListItem', - 'flex gap-4 items-center border-t py-2 px-4', + 'flex gap-4 items-center border-t border-surface-content/10 py-2 px-4', 'relative', // Needed for loading overlay list === 'type' && 'first-of-type:border-t-0 first-of-type:rounded-t last-of-type:rounded-b', list === 'parent' && 'first:border-t-0 first:rounded-t last:rounded-b', list === 'group' && 'group-first:border-t-0 group-first:rounded-t group-last:rounded-b', noShadow !== true && 'elevation-1', - noBackground !== true && 'bg-white', - theme.root, + noBackground !== true && 'bg-surface-100', + settingsClasses.root, classes.root, $$props.class )} @@ -75,11 +75,11 @@ <slot name="avatar"> {#if icon != null} {#if avatar} - <Avatar class={cls(theme.avatar, classes.avatar)} {...avatar}> - <Icon path={icon} class={cls(theme.icon, classes.icon)} /> + <Avatar class={cls(settingsClasses.avatar, classes.avatar)} {...avatar}> + <Icon path={icon} class={cls(settingsClasses.icon, classes.icon)} /> </Avatar> {:else} - <Icon path={icon} class={cls(theme.icon, classes.icon)} /> + <Icon path={icon} class={cls(settingsClasses.icon, classes.icon)} /> {/if} {/if} </slot> @@ -87,13 +87,19 @@ <div class="flex-grow"> <slot name="title"> {#if title != null} - <div class={cls(theme.title, classes.title)}>{title}</div> + <div class={cls(settingsClasses.title, classes.title)}>{title}</div> {/if} </slot> <slot name="subheading"> {#if subheading != null} - <div class={cls('text-sm text-black/50', theme.subheading, classes.subheading)}> + <div + class={cls( + 'text-sm text-surface-content/50', + settingsClasses.subheading, + classes.subheading + )} + > {subheading} </div> {/if} diff --git a/packages/svelte-ux/src/lib/components/Maybe.svelte b/packages/svelte-ux/src/lib/components/Maybe.svelte index df7b0d0d0..168bb12e3 100644 --- a/packages/svelte-ux/src/lib/components/Maybe.svelte +++ b/packages/svelte-ux/src/lib/components/Maybe.svelte @@ -1,15 +1,14 @@ <script lang="ts"> - let self: ConstructorOfATypedSvelteComponent | undefined | null = undefined; - export { self as this } - - let component; + let self: ConstructorOfATypedSvelteComponent | undefined | null = undefined; + export { self as this }; + let component; </script> {#if self} - <svelte:component bind:this={component} this={self} {...$$restProps}> - <slot {component} /> - </svelte:component> + <svelte:component this={self} bind:this={component} {...$$restProps}> + <slot {component} /> + </svelte:component> {:else} - <slot /> -{/if} \ No newline at end of file + <slot /> +{/if} diff --git a/packages/svelte-ux/src/lib/components/Menu.svelte b/packages/svelte-ux/src/lib/components/Menu.svelte index ddb9cd017..5db677533 100644 --- a/packages/svelte-ux/src/lib/components/Menu.svelte +++ b/packages/svelte-ux/src/lib/components/Menu.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { createEventDispatcher } from 'svelte'; + import { createEventDispatcher, type ComponentProps } from 'svelte'; import { slide } from 'svelte/transition'; import type { TransitionConfig } from 'svelte/transition'; import type { Placement } from '@floating-ui/dom'; @@ -9,7 +9,7 @@ import Popover from './Popover.svelte'; import type { TransitionParams } from '$lib/types'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; const dispatch = createEventDispatcher(); @@ -19,10 +19,10 @@ export let matchWidth: boolean = false; export let placement: Placement = matchWidth ? 'bottom-start' : 'bottom'; export let autoPlacement = false; - export let resize = false; + export let resize: ComponentProps<Popover>['resize'] = false; export let disableTransition = false; export let transition = disableTransition - ? (node: HTMLElement, params: TransitionParams) => ({} as TransitionConfig) + ? (node: HTMLElement, params: TransitionParams) => ({}) as TransitionConfig : slide; export let transitionParams: TransitionParams = {}; export let explicitClose = false; @@ -32,7 +32,7 @@ root?: string; menu?: string; } = {}; - const theme = getComponentTheme('Menu'); + const settingsClasses = getComponentClasses('Menu'); export let menuItemsEl: HTMLMenuElement | undefined = undefined; @@ -62,8 +62,8 @@ {open} class={cls( 'Menu', - 'bg-white rounded shadow border overflow-auto', - theme.root, + 'bg-surface-100 rounded shadow border overflow-auto', + settingsClasses.root, classes.root, $$props.class )} @@ -73,7 +73,7 @@ > <!-- svelte-ignore a11y-click-events-have-key-events --> <menu - class={cls('menu-items outline-none max-h-screen', theme.menu, classes.menu)} + class={cls('menu-items outline-none max-h-screen', settingsClasses.menu, classes.menu)} bind:this={menuItemsEl} on:click={onClick} on:mouseup={(e) => { diff --git a/packages/svelte-ux/src/lib/components/MenuButton.svelte b/packages/svelte-ux/src/lib/components/MenuButton.svelte index c5cba6659..abcf5e7db 100644 --- a/packages/svelte-ux/src/lib/components/MenuButton.svelte +++ b/packages/svelte-ux/src/lib/components/MenuButton.svelte @@ -1,4 +1,5 @@ <script lang="ts"> + import { createEventDispatcher } from 'svelte'; import type { ComponentProps } from '$lib/types'; import { mdiMenuDown } from '@mdi/js'; @@ -8,12 +9,14 @@ import Icon from './Icon.svelte'; import Menu from './Menu.svelte'; import MenuItem from './MenuItem.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; + + const dispatch = createEventDispatcher<{ change: { value: any } }>(); export let options: Array<{ label: string; value: any; icon?: string }>; export let value: any = null; export let menuProps: ComponentProps<Menu> = { placement: 'bottom-start' }; - export let menuIcon = mdiMenuDown; + export let menuIcon: string | null = mdiMenuDown; $: selected = options?.find((x) => x.value === value); export let classes: { @@ -21,7 +24,7 @@ label?: string; icon?: string; } = {}; - const theme = getComponentTheme('MenuButton'); + const settingsClasses = getComponentClasses('MenuButton'); let open = false; </script> @@ -29,23 +32,25 @@ <Button on:click={() => (open = !open)} {...$$restProps} - class={cls('MenuButton', theme.root, classes.root, $$props.class)} + class={cls('MenuButton', settingsClasses.root, classes.root, $$props.class)} > <slot name="selection"> - <span class={cls('truncate', theme.label, classes.label)}> + <span class={cls('truncate', settingsClasses.label, classes.label)}> {selected?.label ?? 'No selection'} </span> </slot> - <Icon - path={menuIcon} - class={cls( - 'opacity-50 transform transition-all -mr-2 duration-300', - open && '-rotate-180', - theme.icon, - classes.icon - )} - /> + {#if menuIcon} + <Icon + path={menuIcon} + class={cls( + 'opacity-50 transform transition-all -mr-2 duration-300', + open && '-rotate-180', + settingsClasses.icon, + classes.icon + )} + /> + {/if} <Menu {open} @@ -60,7 +65,10 @@ <MenuItem icon={option.icon} selected={option.value === value} - on:click={() => (value = option.value)} + on:click={() => { + value = option.value; + dispatch('change', { value }); + }} > {option.label} </MenuItem> diff --git a/packages/svelte-ux/src/lib/components/MenuField.svelte b/packages/svelte-ux/src/lib/components/MenuField.svelte index e028a8e66..df0d66212 100644 --- a/packages/svelte-ux/src/lib/components/MenuField.svelte +++ b/packages/svelte-ux/src/lib/components/MenuField.svelte @@ -10,7 +10,7 @@ import Menu from './Menu.svelte'; import MenuItem from './MenuItem.svelte'; import Button from './Button.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import type { MenuOption } from '$lib/types/options'; export let options: MenuOption[] = []; @@ -29,9 +29,10 @@ menuIcon?: string; group?: string; } = {}; - const theme = getComponentTheme('MenuField'); + const settingsClasses = getComponentClasses('MenuField'); let open = false; + export let selected: any = undefined; $: selected = options?.find((x) => x.value === value); $: previous = () => { @@ -89,11 +90,11 @@ <Icon path={menuIcon} class={cls( - 'text-black/50 mr-1 transform transition-all duration-300', + 'text-surface-content/50 mr-1 transform transition-all duration-300', { '-rotate-180': open, }, - theme.menuIcon, + settingsClasses.menuIcon, classes.menuIcon )} on:click={() => (open = !open)} @@ -120,8 +121,8 @@ {#if option.group && option.group !== previousOption?.group} <div class={cls( - 'group-header text-xs leading-8 tracking-widest text-black/50 px-2', - theme.group, + 'group-header text-xs leading-8 tracking-widest text-surface-content/50 px-2', + settingsClasses.group, classes.group )} > @@ -132,7 +133,7 @@ <MenuItem icon={option.icon} selected={option.value === value} - class={cls(option.group ? 'px-4' : 'px-2', theme.option, classes.option)} + class={cls(option.group ? 'px-4' : 'px-2', settingsClasses.option, classes.option)} classes={classes.menuItem} on:click={() => (value = option.value)} > diff --git a/packages/svelte-ux/src/lib/components/MenuItem.svelte b/packages/svelte-ux/src/lib/components/MenuItem.svelte index befcad634..796fa71f4 100644 --- a/packages/svelte-ux/src/lib/components/MenuItem.svelte +++ b/packages/svelte-ux/src/lib/components/MenuItem.svelte @@ -2,9 +2,12 @@ import Button from './Button.svelte'; import type { ComponentProps } from '../types'; import { cls } from '../utils/styles'; - import { scrollIntoView as scrollIntoViewAction, type ScrollIntoViewOptions } from '../actions/scroll'; + import { + scrollIntoView as scrollIntoViewAction, + type ScrollIntoViewOptions, + } from '../actions/scroll'; import { setButtonGroup } from './ButtonGroup.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { settings, getSettings } from './settings'; type ButtonProps = ComponentProps<Button>; @@ -16,19 +19,22 @@ export let classes: ButtonProps['classes'] & { selected?: string } = { root: 'text-sm gap-3', - icon: 'text-black/50', - selected: 'font-semibold [:not(.group:hover)>&]:bg-black/5', + icon: 'text-surface-content/50', + selected: 'font-semibold [:not(.group:hover)>&]:bg-surface-content/5', }; - const theme = getComponentTheme('MenuItem'); + const settingsClasses = getComponentClasses('MenuItem'); let scrollOptions: ScrollIntoViewOptions; - $: scrollOptions = typeof(scrollIntoView) === "boolean" ? { condition: scrollIntoView } as ScrollIntoViewOptions : scrollIntoView; + $: scrollOptions = + typeof scrollIntoView === 'boolean' + ? ({ condition: scrollIntoView } as ScrollIntoViewOptions) + : scrollIntoView; // Clear ButtonGroup if set setButtonGroup(undefined); // Clear theme to not expose to Button - settings({ ...getSettings(), theme: {} }); + settings({ ...getSettings(), classes: {} }); </script> <Button @@ -41,9 +47,9 @@ {...$$restProps} class={cls( 'MenuItem', - 'text-left items-center p-2 hover:bg-black/5 rounded duration-75', + 'text-left items-center p-2 hover:bg-surface-content/5 rounded duration-75', selected && classes?.selected, - theme.root, + settingsClasses.root, classes?.root, $$props.class )} diff --git a/packages/svelte-ux/src/lib/components/Month.svelte b/packages/svelte-ux/src/lib/components/Month.svelte index 1348874f9..da3362eca 100644 --- a/packages/svelte-ux/src/lib/components/Month.svelte +++ b/packages/svelte-ux/src/lib/components/Month.svelte @@ -6,7 +6,6 @@ endOfDay as endOfDayFunc, startOfMonth as startOfMonthFunc, endOfMonth as endOfMonthFunc, - format, addMonths, isSameDay, isWithinInterval, @@ -20,6 +19,7 @@ import Button from './Button.svelte'; import DateButton from './DateButton.svelte'; + import { getSettings } from '.'; export let selected: SelectedDate | undefined = undefined; @@ -32,8 +32,11 @@ startOfMonthFunc(selected.from)) || startOfMonthFunc(new Date()); + const { format } = getSettings(); + $: dateFormat = $format.settings.formats.dates; + $: endOfMonth = endOfMonthFunc(startOfMonth); - $: monthDaysByWeek = getMonthDaysByWeek(startOfMonth); + $: monthDaysByWeek = getMonthDaysByWeek(startOfMonth, dateFormat.weekStartsOn); /** * Hide controls and date. Useful to control externally @@ -54,15 +57,15 @@ return disabledDays instanceof Function ? disabledDays(date) : disabledDays instanceof Date - ? isSameDay(date, disabledDays) - : disabledDays instanceof Array - ? disabledDays.some((d) => isSameDay(date, d)) - : disabledDays instanceof Object - ? isWithinInterval(date, { - start: startOfDayFunc(disabledDays.from), - end: endOfDayFunc(disabledDays.to || disabledDays.from), - }) - : false; + ? isSameDay(date, disabledDays) + : disabledDays instanceof Array + ? disabledDays.some((d) => isSameDay(date, d)) + : disabledDays instanceof Object + ? isWithinInterval(date, { + start: startOfDayFunc(disabledDays.from), + end: endOfDayFunc(disabledDays.to || disabledDays.from), + }) + : false; }; $: isDayHidden = (day: Date) => { @@ -91,7 +94,7 @@ /> <div class="flex flex-1 items-center justify-center"> - <span>{format(startOfMonth, 'MMMM yyyy')}</span> + <span>{$format(startOfMonth, PeriodType.MonthYear)}</span> </div> <Button @@ -105,7 +108,9 @@ <div class="flex"> {#each monthDaysByWeek[0] ?? [] as day (day.getDate())} <div class="flex-1 text-center"> - <span class="text-xs text-black/50"> {format(day, 'eee')[0]} </span> + <span class="text-xs text-surface-content/50"> + {$format(day, PeriodType.Day, { custom: 'eee' })} + </span> </div> {/each} </div> diff --git a/packages/svelte-ux/src/lib/components/MonthList.svelte b/packages/svelte-ux/src/lib/components/MonthList.svelte index cf71749b9..1ba6fbd9c 100644 --- a/packages/svelte-ux/src/lib/components/MonthList.svelte +++ b/packages/svelte-ux/src/lib/components/MonthList.svelte @@ -14,15 +14,15 @@ return disabledMonths instanceof Function ? disabledMonths(date) : disabledMonths instanceof Date - ? isSameMonth(date, disabledMonths) - : disabledMonths instanceof Array - ? disabledMonths.some((d) => isSameMonth(date, d)) - : disabledMonths instanceof Object - ? isWithinInterval(date, { - start: startOfMonth(disabledMonths.from), - end: endOfMonth(disabledMonths.to || disabledMonths.from), - }) - : false; + ? isSameMonth(date, disabledMonths) + : disabledMonths instanceof Array + ? disabledMonths.some((d) => isSameMonth(date, d)) + : disabledMonths instanceof Object + ? isWithinInterval(date, { + start: startOfMonth(disabledMonths.from), + end: endOfMonth(disabledMonths.to || disabledMonths.from), + }) + : false; }; </script> diff --git a/packages/svelte-ux/src/lib/components/MultiSelect.svelte b/packages/svelte-ux/src/lib/components/MultiSelect.svelte index c550bc92e..72bd55d22 100644 --- a/packages/svelte-ux/src/lib/components/MultiSelect.svelte +++ b/packages/svelte-ux/src/lib/components/MultiSelect.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { type ComponentProps, createEventDispatcher } from 'svelte'; import { flip } from 'svelte/animate'; @@ -36,7 +36,7 @@ export let classes: { root?: string; } = {}; - const theme = getComponentTheme('MultiSelect'); + const settingsClasses = getComponentClasses('MultiSelect'); export let onApply = async (ctx: { selection: typeof $selection; @@ -105,7 +105,7 @@ </script> {#if inlineSearch} - <div class="border-b border-gray-100 p-4 pb-2"> + <div class="border-b border-surface-content/10 p-4 pb-2"> <TextField {placeholder} iconRight={mdiMagnify} @@ -115,7 +115,7 @@ </div> {/if} -<div class={cls('overflow-auto py-1 px-4', theme.root, classes.root, $$restProps.class)}> +<div class={cls('overflow-auto py-1 px-4', settingsClasses.root, classes.root, $$restProps.class)}> <!-- initially selected options --> <InfiniteScroll items={filteredSelectedOptions} disabled={!infiniteScroll} let:visibleItems> {#each visibleItems as option (get(option, valueProp))} @@ -148,7 +148,7 @@ {#if filteredSelectedOptions.length && filteredUnselectedOptions.length} <!-- separator between selected and deselected --> - <div class="border-b border-gray-100" /> + <div class="border-b border-surface-content/10" /> {/if} <!-- initially unselected options --> @@ -180,13 +180,13 @@ </div> {:else} {#if !filteredSelectedOptions.length} - <div class="text-gray-400 text-xs py-2">There are no matching items.</div> + <div class="text-surface-content/50 text-xs py-2">There are no matching items.</div> {/if} {/each} </InfiniteScroll> </div> -<div class="grid grid-cols-[auto,1fr,auto] border-t border-gray-100 px-4 py-2"> +<div class="grid grid-cols-[auto,1fr,auto] border-t border-surface-content/10 px-4 py-2"> <slot name="actions" {searchText}> <div /> </slot> @@ -208,7 +208,7 @@ <Button variant="fill" - color="accent" + color="primary" class="px-6" loading={applying} disabled={!$isSelectionDirty || applying} diff --git a/packages/svelte-ux/src/lib/components/MultiSelectField.svelte b/packages/svelte-ux/src/lib/components/MultiSelectField.svelte index b5b2cca60..25e24a2e5 100644 --- a/packages/svelte-ux/src/lib/components/MultiSelectField.svelte +++ b/packages/svelte-ux/src/lib/components/MultiSelectField.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { createEventDispatcher, type ComponentProps, type ComponentEvents } from 'svelte'; import { get } from 'lodash-es'; @@ -48,7 +48,7 @@ field?: string; actions?: string; } = {}; - const theme = getComponentTheme('MultiSelectField'); + const settingsClasses = getComponentClasses('MultiSelectField'); const dispatch = createEventDispatcher<{ change: { value: typeof value } }>(); @@ -133,7 +133,7 @@ <!-- svelte-ignore a11y-click-events-have-key-events --> <div - class={cls(disabled && 'pointer-events-none', theme.root, classes.root, $$props.class)} + class={cls(disabled && 'pointer-events-none', settingsClasses.root, classes.root, $$props.class)} on:click={onClick} > <!-- TODO: Setup blur without jank on open or issues when clicking within menu --> @@ -150,7 +150,7 @@ bind:inputEl on:focus={onFocus} on:change={onSearchChange} - class={cls('h-full', theme.field, classes.field)} + class={cls('h-full', settingsClasses.field, classes.field)} {...$$restProps} > <slot slot="prepend" name="prepend" /> @@ -160,14 +160,14 @@ {#if loading} <span class="inline-block w-[29px] h-[28px] text-center"> - <ProgressCircle size={16} width={2} class="text-black/50" /> + <ProgressCircle size={16} width={2} class="text-surface-content/50" /> </span> <!-- {:else if readonly} --> <!-- Do not show chevron or clear buttons --> {:else if value.length && clearable} <Button icon={mdiClose} - class="text-black/50 p-1" + class="text-surface-content/50 p-1" on:click={(e) => { e.stopPropagation(); clear(); @@ -177,7 +177,7 @@ {:else} <Button icon={mdiChevronDown} - class="text-black/50 p-1 transform {open ? 'rotate-180' : ''}" + class="text-surface-content/50 p-1 transform {open ? 'rotate-180' : ''}" tabindex="-1" on:click={(e) => { e.stopPropagation(); diff --git a/packages/svelte-ux/src/lib/components/MultiSelectMenu.svelte b/packages/svelte-ux/src/lib/components/MultiSelectMenu.svelte index 84cf69971..3037a2455 100644 --- a/packages/svelte-ux/src/lib/components/MultiSelectMenu.svelte +++ b/packages/svelte-ux/src/lib/components/MultiSelectMenu.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import type { Placement } from '@floating-ui/dom'; @@ -30,7 +30,7 @@ root?: string; menu?: string; } = {}; - const theme = getComponentTheme('MultiSelectMenu'); + const settingsClasses = getComponentClasses('MultiSelectMenu'); export let menuItemsEl: HTMLMenuElement | undefined = undefined; </script> @@ -44,8 +44,8 @@ let:close {...$$restProps} classes={{ - root: cls('MultiSelectMenu', theme.root, classes.root, $$restProps.class), - menu: cls('flex flex-col', theme.menu, classes.menu), + root: cls('MultiSelectMenu', settingsClasses.root, classes.root, $$restProps.class), + menu: cls('flex flex-col', settingsClasses.menu, classes.menu), }} bind:menuItemsEl > diff --git a/packages/svelte-ux/src/lib/components/MultiSelectOption.svelte b/packages/svelte-ux/src/lib/components/MultiSelectOption.svelte index 2b4bc6665..073310d16 100644 --- a/packages/svelte-ux/src/lib/components/MultiSelectOption.svelte +++ b/packages/svelte-ux/src/lib/components/MultiSelectOption.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import Checkbox from './Checkbox.svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let checked: boolean; export let indeterminate = false; @@ -12,14 +12,14 @@ checkbox?: string; container?: string; } = {}; - const theme = getComponentTheme('MultiSelectOption'); + const settingsClasses = getComponentClasses('MultiSelectOption'); </script> <div class={cls( 'MultiSelectOption', 'grid grid-cols-[1fr,auto] py-2', - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -29,12 +29,12 @@ bind:indeterminate on:change {disabled} - class={cls(theme.checkbox, classes.checkbox)} + class={cls(settingsClasses.checkbox, classes.checkbox)} > <div class={cls( - 'ml-1 inline-block cursor-pointer text-sm text-gray-900', - theme.container, + 'ml-1 inline-block cursor-pointer text-sm text-surface-content', + settingsClasses.container, classes.container )} > diff --git a/packages/svelte-ux/src/lib/components/NavItem.svelte b/packages/svelte-ux/src/lib/components/NavItem.svelte index 108835831..1c96a36f4 100644 --- a/packages/svelte-ux/src/lib/components/NavItem.svelte +++ b/packages/svelte-ux/src/lib/components/NavItem.svelte @@ -5,7 +5,7 @@ import { scrollIntoView } from '../actions/scroll'; import { getScrollParent } from '../utils/dom'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { showDrawer } from './AppLayout.svelte'; import { mdScreen } from '../stores/matchMedia'; @@ -19,7 +19,7 @@ active?: string; icon?: string; } = {}; - const theme = getComponentTheme('NavItem'); + const settingsClasses = getComponentClasses('NavItem'); $: isPathActive = path ? isActive(currentUrl, path) : false; </script> @@ -29,8 +29,8 @@ class={cls( 'NavItem', 'flex items-center', - isPathActive && ['is-active', theme.active, classes.active], - theme.root, + settingsClasses.root, + isPathActive && ['is-active', settingsClasses.active, classes.active], classes.root, $$props.class )} @@ -52,7 +52,7 @@ {/if} {#if icon} - <Icon path={icon} class={cls('mr-3 flex-shrink-0', theme.icon, classes.icon)} /> + <Icon path={icon} class={cls('mr-3 flex-shrink-0', settingsClasses.icon, classes.icon)} /> {/if} {text} diff --git a/packages/svelte-ux/src/lib/components/Notification.svelte b/packages/svelte-ux/src/lib/components/Notification.svelte index bba460072..91c1b4dd1 100644 --- a/packages/svelte-ux/src/lib/components/Notification.svelte +++ b/packages/svelte-ux/src/lib/components/Notification.svelte @@ -41,7 +41,7 @@ {#if open} <div - class="Notification rounded-lg border bg-white shadow-lg z-10" + class="Notification rounded-lg border bg-surface-100 shadow-lg z-10" transition:fly={{ duration: 200, easing: quadIn, x: 100 }} on:outroend={() => dispatch('close')} on:click={onClick} @@ -62,7 +62,7 @@ {/if} {#if $$slots.description} - <div class="text-sm text-black/50"> + <div class="text-sm text-surface-content/50"> <slot name="description" /> </div> {/if} @@ -84,7 +84,7 @@ <Button icon={mdiClose} on:click={() => (open = false)} - class="text-black/25 self-start" + class="text-surface-content/25 self-start" /> {/if} </div> diff --git a/packages/svelte-ux/src/lib/components/NumberStepper.svelte b/packages/svelte-ux/src/lib/components/NumberStepper.svelte index 99368e2b9..09d896556 100644 --- a/packages/svelte-ux/src/lib/components/NumberStepper.svelte +++ b/packages/svelte-ux/src/lib/components/NumberStepper.svelte @@ -4,14 +4,14 @@ import { Button, TextField } from '.'; import { selectOnFocus } from '$lib/actions/input'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { cls } from '$lib/utils/styles'; export let value: number = 0; export let min: number | undefined = undefined; export let max: number | undefined = undefined; - const theme = getComponentTheme('NumberStepper'); + const settingsClasses = getComponentClasses('NumberStepper'); const dispatch = createEventDispatcher(); @@ -22,7 +22,7 @@ type="integer" bind:value align="center" - class={cls('NumberStepper w-24', theme.root, $$props.class)} + class={cls('NumberStepper w-24', settingsClasses.root, $$props.class)} actions={(node) => [selectOnFocus(node)]} {...$$restProps} > diff --git a/packages/svelte-ux/src/lib/components/Overflow.svelte b/packages/svelte-ux/src/lib/components/Overflow.svelte index 5c97c15c9..1ad6d16c4 100644 --- a/packages/svelte-ux/src/lib/components/Overflow.svelte +++ b/packages/svelte-ux/src/lib/components/Overflow.svelte @@ -1,9 +1,9 @@ <script lang="ts"> import { overflow } from '$lib/actions/layout'; import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; - const theme = getComponentTheme('Overflow'); + const settingsClasses = getComponentClasses('Overflow'); let overflowX = 0; let overflowY = 0; @@ -16,7 +16,7 @@ overflowY = e.detail.overflowY; }} {...$$restProps} - class={cls('Overflow', theme.root, $$props.class)} + class={cls('Overflow', settingsClasses.root, $$props.class)} > <slot {overflowX} {overflowY} /> </div> diff --git a/packages/svelte-ux/src/lib/components/Overlay.svelte b/packages/svelte-ux/src/lib/components/Overlay.svelte index fb3becc83..650cae44f 100644 --- a/packages/svelte-ux/src/lib/components/Overlay.svelte +++ b/packages/svelte-ux/src/lib/components/Overlay.svelte @@ -3,15 +3,15 @@ import type { TransitionConfig } from 'svelte/transition'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let center = false; export let transition = [fade, { duration: 100 }] as [ (node: Element, options: any) => TransitionConfig, - object + object, ]; - const theme = getComponentTheme('Overlay'); + const settingsClasses = getComponentClasses('Overlay'); $: [transitionFn, transitionConfig] = transition; </script> @@ -19,9 +19,9 @@ <div class={cls( 'Overlay', - 'absolute top-0 bottom-0 left-0 right-0 z-30 bg-white/75', + 'absolute top-0 bottom-0 left-0 right-0 z-30 bg-surface-100/75', center && 'flex items-center justify-center', - theme.root, + settingsClasses.root, $$props.class )} transition:transitionFn={transitionConfig} diff --git a/packages/svelte-ux/src/lib/components/Pagination.svelte b/packages/svelte-ux/src/lib/components/Pagination.svelte index fbdfb33cc..b8ec0a8f6 100644 --- a/packages/svelte-ux/src/lib/components/Pagination.svelte +++ b/packages/svelte-ux/src/lib/components/Pagination.svelte @@ -3,7 +3,6 @@ import type paginationStore from '../stores/paginationStore'; import { cls } from '../utils/styles'; - import { format as formatValue } from '../utils/format'; import type { StoresValues } from '../types/typeHelpers'; import Button from './Button.svelte'; @@ -12,7 +11,8 @@ import MenuItem from './MenuItem.svelte'; import Toggle from './Toggle.svelte'; import Tooltip from './Tooltip.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; + import { getSettings } from './settings'; type Pagination = ReturnType<typeof paginationStore>; @@ -39,12 +39,19 @@ pagination?: string; perPage?: string; } = {}; - const theme = getComponentTheme('Pagination'); + const { format: formatValue } = getSettings(); + const settingsClasses = getComponentClasses('Pagination'); </script> {#if $pagination.totalPages > 1 || !hideSinglePage} <div - class={cls('Pagination', 'flex items-center gap-1', theme.root, classes.root, $$props.class)} + class={cls( + 'Pagination', + 'flex items-center gap-1', + settingsClasses.root, + classes.root, + $$props.class + )} > {#each show as component} {#if component === 'actions'} @@ -58,7 +65,7 @@ on:click={pagination.firstPage} disabled={$pagination.isFirst} aria-label="First Page" - class={cls('p-2', theme.buttons, classes.buttons)} + class={cls('p-2', settingsClasses.buttons, classes.buttons)} /> </Tooltip> {/if} @@ -70,7 +77,7 @@ on:click={pagination.prevPage} disabled={$pagination.isFirst} aria-label="Previous Page" - class={cls('p-2', theme.buttons, classes.buttons)} + class={cls('p-2', settingsClasses.buttons, classes.buttons)} /> </Tooltip> {/if} @@ -82,7 +89,7 @@ on:click={pagination.nextPage} disabled={$pagination.isLast} aria-label="Next Page" - class={cls('p-2', theme.buttons, classes.buttons)} + class={cls('p-2', settingsClasses.buttons, classes.buttons)} /> </Tooltip> {/if} @@ -94,13 +101,13 @@ on:click={pagination.lastPage} disabled={$pagination.isLast} aria-label="Last Page" - class={cls('p-2', theme.buttons, classes.buttons)} + class={cls('p-2', settingsClasses.buttons, classes.buttons)} /> </Tooltip> {/if} {#if component === 'perPage'} - <div class={cls('text-sm text-center', theme.perPage, classes.perPage)}> + <div class={cls('text-sm text-center', settingsClasses.perPage, classes.perPage)}> Per page: <Toggle let:on={open} let:toggle> <span> @@ -122,7 +129,7 @@ selected={$pagination.perPage === option} on:click={() => pagination.setPerPage(option)} > - {formatValue(option, 'integer')} + {$formatValue(option, 'integer')} </MenuItem> {/each} </Menu> @@ -133,7 +140,7 @@ {#if component === 'pagination'} <slot name="pagination" pagination={$pagination}> - <div class={cls('text-sm tabular-nums', theme.pagination, classes.pagination)}> + <div class={cls('text-sm tabular-nums', settingsClasses.pagination, classes.pagination)}> {format($pagination)} </div> </slot> diff --git a/packages/svelte-ux/src/lib/components/Popover.svelte b/packages/svelte-ux/src/lib/components/Popover.svelte index 1fee07388..8016ecaf1 100644 --- a/packages/svelte-ux/src/lib/components/Popover.svelte +++ b/packages/svelte-ux/src/lib/components/Popover.svelte @@ -2,9 +2,9 @@ import { createEventDispatcher } from 'svelte'; import type { Placement } from '@floating-ui/dom'; - import { popover } from '../actions/popover'; + import { popover, type PopoverOptions } from '../actions/popover'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let open = false; export let placement: Placement | undefined = undefined; @@ -37,10 +37,10 @@ /** * Set max-height of popover element to the remaining height from anchor element to bottom of viewport */ - export let resize = false; + export let resize: PopoverOptions['resize'] = false; const dispatch = createEventDispatcher(); - const theme = getComponentTheme('Popover'); + const settingsClasses = getComponentClasses('Popover'); function close(reason: string = 'unknown') { if (open) { @@ -61,7 +61,7 @@ {#if open} <div - class={cls('Popover absolute z-50 outline-none', theme.root, $$props.class)} + class={cls('Popover absolute z-50 outline-none', settingsClasses.root, $$props.class)} tabindex="-1" use:popover={{ anchorEl, placement, autoPlacement, offset, padding, matchWidth, resize }} on:clickOutside={(e) => { diff --git a/packages/svelte-ux/src/lib/components/Preview.svelte b/packages/svelte-ux/src/lib/components/Preview.svelte index 1fe4f4581..3202a466a 100644 --- a/packages/svelte-ux/src/lib/components/Preview.svelte +++ b/packages/svelte-ux/src/lib/components/Preview.svelte @@ -6,8 +6,8 @@ import { slide } from 'svelte/transition'; import Button from './Button.svelte'; + import Code from './Code.svelte'; import { cls } from '$lib/utils/styles'; - import CopyButton from './CopyButton.svelte'; export let code: string | null = null; export let language = 'svelte'; @@ -15,33 +15,24 @@ export let showCode = false; </script> -<div class={cls('Preview border border-black/20 rounded bg-white', $$props.class)}> +<div class={cls('Preview border rounded bg-surface-100', $$props.class)}> <div class="p-4"> <slot /> </div> {#if code && showCode} - <div class="relative"> - <pre - class="language-{language} rounded" - style="margin: 0; white-space: normal;" - transition:slide> - <code class="language-{language}">{@html highlightedCode}</code> - </pre> - - <div class="absolute top-0 right-0 p-2 z-10"> - <CopyButton - value={code} - class="text-white/70 hover:bg-white/20 py-1 backdrop-blur-md" - size="sm" - /> - </div> + <div transition:slide class="bg-surface-200"> + <Code source={code} highlightedSource={highlightedCode} classes={{ pre: 'rounded-t-none' }} /> </div> {/if} </div> {#if code} - <Button icon={mdiCodeTags} class=" text-black/70 py-1" on:click={() => (showCode = !showCode)}> + <Button + icon={mdiCodeTags} + class=" text-surface-content/70 py-1" + on:click={() => (showCode = !showCode)} + > {showCode ? 'Hide' : 'Show'} Code </Button> {/if} diff --git a/packages/svelte-ux/src/lib/components/Progress.svelte b/packages/svelte-ux/src/lib/components/Progress.svelte index 471a24200..ee8c00630 100644 --- a/packages/svelte-ux/src/lib/components/Progress.svelte +++ b/packages/svelte-ux/src/lib/components/Progress.svelte @@ -1,11 +1,11 @@ <script lang="ts"> import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value: number | null; export let max: number | undefined = undefined; - const theme = getComponentTheme('Progress'); + const settingsClasses = getComponentClasses('Progress'); </script> <progress @@ -17,12 +17,12 @@ 'h-2 w-full', // bar color - '[--color:theme(colors.accent.500)]', + '[--color:theme(colors.primary)]', '[&::-webkit-progress-value]:bg-[--color]', '[&::-moz-progress-bar]:bg-[--color]', // track color - '[--track-color:theme(colors.gray.100)]', + '[--track-color:theme(colors.surface-200)]', '[&::-webkit-progress-bar]:bg-[--track-color]', 'bg-[--track-color]', @@ -32,7 +32,7 @@ '[&::-webkit-progress-bar]:rounded-full', 'rounded-full', - theme.root, + settingsClasses.root, $$props.class )} /> diff --git a/packages/svelte-ux/src/lib/components/ProgressCircle.svelte b/packages/svelte-ux/src/lib/components/ProgressCircle.svelte index f8d5c510d..f23bb69de 100644 --- a/packages/svelte-ux/src/lib/components/ProgressCircle.svelte +++ b/packages/svelte-ux/src/lib/components/ProgressCircle.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value: number | null = null; export let rotate = 0; @@ -8,7 +8,7 @@ export let width = 4; export let track = false; - const theme = getComponentTheme('ProgressCircle'); + const settingsClasses = getComponentClasses('ProgressCircle'); const radius = 20; @@ -25,7 +25,7 @@ class={cls( 'ProgressCircular', 'relative inline-flex justify-center items-center align-middle', - theme.root, + settingsClasses.root, $$props.class )} class:indeterminate diff --git a/packages/svelte-ux/src/lib/components/QuickSearch.svelte b/packages/svelte-ux/src/lib/components/QuickSearch.svelte index 4e1ce196a..aca9d4627 100644 --- a/packages/svelte-ux/src/lib/components/QuickSearch.svelte +++ b/packages/svelte-ux/src/lib/components/QuickSearch.svelte @@ -3,8 +3,9 @@ import Button from '$lib/components/Button.svelte'; import Dialog from '$lib/components/Dialog.svelte'; + import Kbd from './Kbd.svelte'; import SelectField from '$lib/components/SelectField.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { cls } from '$lib/utils/styles'; import { smScreen } from '$lib/stores'; import { autoFocus, selectOnFocus } from '$lib/actions'; @@ -16,7 +17,7 @@ root?: string; button?: string; } = {}; - const theme = getComponentTheme('QuickSearch'); + const settingsClasses = getComponentClasses('QuickSearch'); let open = false; @@ -47,25 +48,22 @@ on:click={() => (open = true)} class={cls( 'sm:bg-black/10 sm:hover:bg-black/20 rounded-full sm:w-56 justify-start', - theme.button, + settingsClasses.button, classes.button )} > <span class="flex-1 text-left max-sm:hidden">Search</span> - <kbd class="ml-2 font-sans text-white/50 max-sm:hidden"> - <abbr title="Command" class="no-underline">⌘</abbr> - K - </kbd> + <Kbd variant="none" class="opacity-50 max-sm:hidden" command>K</Kbd> </Button> <Dialog bind:open classes={{ - root: cls('items-start mt-20', theme.root, classes.root, $$props.class), - backdrop: 'backdrop-blur-sm bg-black/70', + root: cls('items-start mt-20', settingsClasses.root, classes.root, $$props.class), + backdrop: 'backdrop-blur-sm', }} > - <div class="overflow-auto max-h-[min(90dvh,600px)] min-w-[400px] py-1"> + <div class="overflow-auto max-h-[min(90dvh,600px)] w-[400px] max-w-[95vw] py-1"> <SelectField icon={mdiMagnify} placeholder="Search..." diff --git a/packages/svelte-ux/src/lib/components/Radio.svelte b/packages/svelte-ux/src/lib/components/Radio.svelte index 6457e3ae3..dee62b2f8 100644 --- a/packages/svelte-ux/src/lib/components/Radio.svelte +++ b/packages/svelte-ux/src/lib/components/Radio.svelte @@ -4,7 +4,7 @@ import Icon from './Icon.svelte'; import { uniqueId } from '../utils/string'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let id = uniqueId('radio-'); export let name: string = ''; @@ -20,12 +20,20 @@ label?: string; icon?: string; } = {}; - const theme = getComponentTheme('Radio'); + const settingsClasses = getComponentClasses('Radio'); $: checked = group !== undefined ? group === value : checked; </script> -<div class={cls('Radio', 'inline-flex items-center', theme.root, classes.root, $$props.class)}> +<div + class={cls( + 'Radio', + 'inline-flex items-center', + settingsClasses.root, + classes.root, + $$props.class + )} +> <input {id} {name} @@ -39,13 +47,17 @@ <label for={id} class={cls( - 'inline-grid place-items-center border-2 rounded-full bg-white', + 'inline-grid place-items-center border-2 rounded-full bg-surface-100', 'peer-disabled:opacity-50 transition-shadow duration-300', !disabled && - 'peer-focus-visible:ring-2 peer-hover:border-accent-500 peer-focus-visible:border-accent-500 ring-accent-300 ring-offset-0', - !checked && !disabled && 'peer-hover:bg-accent-100', - checked ? (disabled ? ' border-gray-500' : 'border-accent-500') : 'border-gray-500', - theme.checkbox, + 'peer-focus-visible:ring-2 peer-hover:border-primary peer-focus-visible:border-primary ring-primary/20 ring-offset-0', + !checked && !disabled && 'peer-hover:bg-primary/10', + checked + ? disabled + ? 'border-surface-content/30' + : 'border-primary' + : 'border-surface-content/30', + settingsClasses.checkbox, classes.checkbox )} > @@ -53,9 +65,9 @@ path={mdiCheckboxBlankCircle} class={cls( 'pointer-events-none transition-transform', - disabled ? 'text-gray-500' : 'text-accent-500', + disabled ? 'text-surface-content/30 border-surface-content/30' : 'text-primary', checked ? 'scale-100' : 'scale-0', - theme.icon, + settingsClasses.icon, classes.icon )} size={{ @@ -78,7 +90,7 @@ md: 'text-md', // 16px lg: 'text-lg', // 18px }[size], - theme.label, + settingsClasses.label, classes.label )} > diff --git a/packages/svelte-ux/src/lib/components/RangeField.svelte b/packages/svelte-ux/src/lib/components/RangeField.svelte index 822b63d6a..a0e05f092 100644 --- a/packages/svelte-ux/src/lib/components/RangeField.svelte +++ b/packages/svelte-ux/src/lib/components/RangeField.svelte @@ -22,7 +22,7 @@ <input type="range" bind:value {min} {max} {step} {id} class="h-6 w-full" /> - <span class="ml-2 text-sm text-black/50 tabular-nums text-right inline-grid"> + <span class="ml-2 text-sm text-surface-content/50 tabular-nums text-right inline-grid"> <span class="col-span-full row-span-full invisible">{min}</span> <span class="col-span-full row-span-full">{value}</span> <span class="col-span-full row-span-full invisible">{max}</span> diff --git a/packages/svelte-ux/src/lib/components/RangeSlider.svelte b/packages/svelte-ux/src/lib/components/RangeSlider.svelte index 90bfb758e..b0f608d86 100644 --- a/packages/svelte-ux/src/lib/components/RangeSlider.svelte +++ b/packages/svelte-ux/src/lib/components/RangeSlider.svelte @@ -34,7 +34,7 @@ import { decimalCount, round } from '$lib/utils/number'; import Icon from './Icon.svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let min = 0; export let max = 100; @@ -42,7 +42,7 @@ export let value = [min, max]; export let disabled = false; - const theme = getComponentTheme('RangeSlider'); + const settingsClasses = getComponentClasses('RangeSlider'); $: stepPercent = step / (max - min); $: stepDecimals = decimalCount(step); @@ -224,9 +224,9 @@ <div class={cls( 'RangeSlider', - 'group relative h-2 bg-black/10 rounded-full select-none outline-none', + 'group relative h-2 bg-surface-content/10 rounded-full select-none outline-none', disabled && ' pointer-events-none opacity-50', - theme.root, + settingsClasses.root, $$props.class )} style="--start: {$start}; --end: {$end};" @@ -243,7 +243,7 @@ left: calc(var(--start) * 100%); right: calc((1 - var(--end)) * 100%); " - class="range absolute top-0 bottom-0 bg-accent-400 active:bg-accent-500" + class="range absolute top-0 bottom-0 bg-primary" /> <div @@ -264,7 +264,7 @@ 'transition-opacity' )} > - <Icon path={mdiDragHorizontal} class="text-white" /> + <Icon path={mdiDragHorizontal} class="text-primary-content" /> </div> <div @@ -279,10 +279,10 @@ class={cls( 'thumb', 'absolute top-1/2 w-4 h-4 -translate-x-1/2 -translate-y-1/2', - 'border border-black/30 bg-white rounded-full outline-4', - 'hover:outline hover:outline-accent-500/20', + 'border bg-white rounded-full outline-4', + 'hover:outline hover:outline-primary/20', (lastMoved === 'start' || lastMoved === 'range') && - 'group-focus:outline group-focus:outline-accent-500/40' + 'group-focus:outline group-focus:outline-primary/40' )} /> @@ -298,18 +298,18 @@ class={cls( 'thumb', 'absolute top-1/2 w-4 h-4 -translate-x-1/2 -translate-y-1/2', - 'border border-black/30 bg-white rounded-full outline-4', - 'outline-accent-500/20', - 'hover:outline hover:outline-accent-500/20', + 'border bg-white rounded-full outline-4', + 'outline-primary/20', + 'hover:outline hover:outline-primary/20', (lastMoved === 'end' || lastMoved === 'range') && - 'group-focus:outline group-focus:outline-accent-500/40' + 'group-focus:outline group-focus:outline-primary/40' )} /> {#if showStartValue} <output style="left: calc(var(--start) * 100%);" - class="value absolute top-1/2 -translate-x-1/2 -translate-y-[180%] text-xs text-white bg-accent-500 rounded-full px-2 shadow" + class="value absolute top-1/2 -translate-x-1/2 -translate-y-[180%] text-xs text-primary-content bg-primary rounded-full px-2 shadow" transition:fly={{ y: 4, duration: 300 }} > {value[0]} @@ -319,7 +319,7 @@ {#if showEndValue} <output style="left: calc(var(--end) * 100%);" - class="value absolute top-1/2 -translate-x-1/2 -translate-y-[180%] text-xs text-white bg-accent-500 rounded-full px-2 shadow" + class="value absolute top-1/2 -translate-x-1/2 -translate-y-[180%] text-xs text-primary-content bg-primary rounded-full px-2 shadow" transition:fly={{ y: 4, duration: 300 }} > {value[1]} diff --git a/packages/svelte-ux/src/lib/components/ScrollingValue.svelte b/packages/svelte-ux/src/lib/components/ScrollingValue.svelte index f02191f3a..be2db2577 100644 --- a/packages/svelte-ux/src/lib/components/ScrollingValue.svelte +++ b/packages/svelte-ux/src/lib/components/ScrollingValue.svelte @@ -3,7 +3,7 @@ import { elasticOut, backInOut, bounceOut } from 'svelte/easing'; import { cls } from '$lib/utils/styles'; import { modulo } from '$lib/utils/number'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value = 0; export let single = false; @@ -14,7 +14,7 @@ root?: string; value?: string; } = {}; - const theme = getComponentTheme('ScrollingValue'); + const settingsClasses = getComponentClasses('ScrollingValue'); const displayValue = spring(); // const displayValue = tweened(value, { duration: 1000, easing: bounceOut }); @@ -29,13 +29,13 @@ class={cls( 'ScrollingValue', 'inline-grid overflow-hidden', - theme.root, + settingsClasses.root, classes.root, $$props.class )} > <div - class={cls('col-span-full row-span-full', theme.value, classes.value)} + class={cls('col-span-full row-span-full', settingsClasses.value, classes.value)} style:transform={axis === 'x' ? `translateX(${100 + 100 * -offset}%)` : `translateY(${-100 + 100 * offset}%)`} @@ -45,7 +45,7 @@ </slot> </div> <div - class={cls('col-span-full row-span-full', theme.value, classes.value)} + class={cls('col-span-full row-span-full', settingsClasses.value, classes.value)} style:transform={axis === 'x' ? `translateX(${100 * -offset}%)` : `translateY(${100 * offset}%)`} diff --git a/packages/svelte-ux/src/lib/components/SectionDivider.svelte b/packages/svelte-ux/src/lib/components/SectionDivider.svelte index 9b3a49457..ea078da92 100644 --- a/packages/svelte-ux/src/lib/components/SectionDivider.svelte +++ b/packages/svelte-ux/src/lib/components/SectionDivider.svelte @@ -1,17 +1,17 @@ <script lang="ts"> import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; - const theme = getComponentTheme('SectionDivider'); + const settingsClasses = getComponentClasses('SectionDivider'); </script> <div {...$$props} - class={cls('SectionDivider', 'flex items-center my-2', theme.root, $$props.class)} + class={cls('SectionDivider', 'flex items-center my-2', settingsClasses.root, $$props.class)} > - <div class="flex-1 border border-black/50 h-px rounded-full mr-2" /> - <div class="font-medium text-black/80 border border-black/50 px-4 rounded-full bg-black/5 shadow"> + <div class="flex-1 border h-px rounded-full mr-2" /> + <div class="font-medium text-surface-content border px-4 rounded-full bg-surface-100 shadow"> <slot /> </div> - <div class="flex-1 border border-black/50 h-px rounded-full ml-2" /> + <div class="flex-1 border h-px rounded-full ml-2" /> </div> diff --git a/packages/svelte-ux/src/lib/components/SelectField.svelte b/packages/svelte-ux/src/lib/components/SelectField.svelte index a7aa8c232..4c0e21fc9 100644 --- a/packages/svelte-ux/src/lib/components/SelectField.svelte +++ b/packages/svelte-ux/src/lib/components/SelectField.svelte @@ -2,7 +2,7 @@ import { createEventDispatcher, type ComponentProps, type ComponentEvents } from 'svelte'; import type { Placement } from '@floating-ui/dom'; - import { mdiChevronDown, mdiClose } from '@mdi/js'; + import { mdiChevronDown, mdiChevronLeft, mdiChevronRight, mdiClose } from '@mdi/js'; import Logger from '../utils/logger'; import { autoFocus, selectOnFocus } from '$lib/actions'; @@ -14,7 +14,7 @@ import MenuItem from './MenuItem.svelte'; import SelectListOptions from './_SelectListOptions.svelte'; import TextField from './TextField.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import type { IconInput } from '$lib/utils/icons'; import type { MenuOption } from '$lib/types/options'; import type { ScrollIntoViewOptions } from '$lib/actions'; @@ -36,7 +36,8 @@ export let disabled: boolean = false; export let readonly: boolean = false; export let icon: IconInput = undefined; - export let toggleIcon: IconInput = mdiChevronDown; + export let inlineOptions = false; + export let toggleIcon: IconInput = !inlineOptions ? mdiChevronDown : null; export let closeIcon: IconInput = mdiClose; export let activeOptionIcon: boolean = false; export let clearable = true; @@ -47,9 +48,15 @@ export let tabindex = 0; export let autofocus: ComponentProps<TextField>['autofocus'] = undefined; export let fieldActions: ComponentProps<TextField>['actions'] = autofocus - ? (node) => [autoFocus(node, typeof autofocus === 'object' ? autofocus : undefined), selectOnFocus(node)] + ? (node) => [ + autoFocus(node, typeof autofocus === 'object' ? autofocus : undefined), + selectOnFocus(node), + ] : undefined; + /** If true, show left/right buttons to step through options */ + export let stepper = false; + let originalIcon = icon; export let scrollIntoView: Partial<ScrollIntoViewOptions> = {}; @@ -63,10 +70,10 @@ group?: string; empty?: string; } = {}; - const theme = getComponentTheme('SelectField'); + const settingsClasses = getComponentClasses('SelectField'); let fieldClasses: ComponentProps<TextField>['classes']; - $: fieldClasses = typeof(classes.field) === "string" ? { root: classes.field } : classes.field; + $: fieldClasses = typeof classes.field === 'string' ? { root: classes.field } : classes.field; // Menu props export let placement: Placement = 'bottom-start'; @@ -75,7 +82,6 @@ export let resize = true; export let disableTransition = false; export let menuProps: ComponentProps<Menu> | undefined = undefined; - export let inlineOptions = false; $: filteredOptions = options ?? []; let searchText = ''; @@ -154,6 +160,7 @@ // Elements let inputEl: HTMLInputElement | null = null; let menuOptionsEl: HTMLDivElement; + let selectFieldEl: HTMLButtonElement; // UI state export let open = false; @@ -207,7 +214,7 @@ show(); } - function onBlur(e: FocusEvent|CustomEvent<any>) { + function onBlur(e: FocusEvent | CustomEvent<any>) { const fe = e as FocusEvent; logger.debug('onBlur', { target: e.target, relatedTarget: fe?.relatedTarget, menuOptionsEl }); @@ -216,7 +223,9 @@ fe.relatedTarget instanceof HTMLElement && !menuOptionsEl?.contains(fe.relatedTarget) && // TODO: Oddly Safari does not set `relatedTarget` to the clicked on menu option (like Chrome and Firefox) but instead appears to take `tabindex` into consideration. Currently resolves to `.options` after setting `tabindex="-1" fe.relatedTarget !== menuOptionsEl?.offsetParent && // click on scroll bar - !fe.relatedTarget.closest('menu > [slot=actions]') // click on action item + !fe.relatedTarget.closest('menu > [slot=actions]') && // click on action item + !selectFieldEl?.contains(fe.relatedTarget) && // click within <SelectField> (ex. toggleIcon) + fe.relatedTarget !== selectFieldEl // click on SelectField itself ) { hide('blur'); } else { @@ -355,6 +364,28 @@ return option; } + $: previous = () => { + const index = options.findIndex((o) => o.value === value); + if (index === 0 || index === -1) { + // If first item, or no selected value yet, return last item + return options[options.length - 1].value; + } else { + // Previous item + return options[index - 1].value; + } + }; + + $: next = () => { + const index = options.findIndex((x) => x.value === value); + if (index === options.length - 1) { + // First value + return options[0].value; + } else { + // Next value + return options[index + 1].value; + } + }; + function clear() { logger.info('clear'); selectOption(null); @@ -364,10 +395,16 @@ <!-- svelte-ignore a11y-click-events-have-key-events --> <button - aria-haspopup={!inlineOptions ? "listbox" : undefined} - class={cls("SelectField block w-full cursor-default text-left", theme.root, classes.root, $$props.class)} - on:click={onClick}> - + aria-haspopup={!inlineOptions ? 'listbox' : undefined} + class={cls( + 'SelectField block w-full cursor-default text-left', + settingsClasses.root, + classes.root, + $$props.class + )} + bind:this={selectFieldEl} + on:click={onClick} +> <TextField {label} {placeholder} @@ -384,40 +421,75 @@ on:keydown={onKeyDown} on:keypress={onKeyPress} actions={fieldActions} - classes={{ container: inlineOptions ? 'border-none shadow-none hover:shadow-none group-focus-within:shadow-none' : undefined }} - class={cls('h-full', theme.field, fieldClasses)} + classes={{ + container: inlineOptions + ? 'border-none shadow-none hover:shadow-none group-focus-within:shadow-none' + : undefined, + }} + class={cls('h-full', settingsClasses.field, fieldClasses)} role="combobox" - aria-expanded={open ? "true" : "false"} - aria-autocomplete={!inlineOptions ? "list" : undefined} + aria-expanded={open ? 'true' : 'false'} + aria-autocomplete={!inlineOptions ? 'list' : undefined} {...$$restProps} > - <slot slot="prepend" name="prepend" /> + <span slot="prepend"> + {#if stepper} + <Button + icon={mdiChevronLeft} + on:click={(e) => { + e.stopPropagation(); + logger.debug('step left clicked'); + selectValue(previous()); + }} + class="mr-2" + size="sm" + /> + {/if} + <slot name="prepend" /> + </span> <span slot="append" class="flex items-center"> <slot name="append" /> {#if loading} <span class="inline-block w-[29px] h-[28px] text-center"> - <ProgressCircle size={16} width={2} class="text-black/50" /> + <ProgressCircle size={16} width={2} class="text-surface-content/50" /> </span> {:else if readonly} <!-- Do not show chevron or clear buttons --> {:else if value && clearable} <Button icon={closeIcon} - class="text-black/50 p-1" + class="text-surface-content/50 p-1" on:click={(e) => { e.stopPropagation(); - logger.debug("closeIcon clicked"); + logger.debug('closeIcon clicked'); clear(); }} /> - {:else if !inlineOptions} + {:else if toggleIcon} <Button icon={toggleIcon} - class="text-black/50 p-1 transform {open ? 'rotate-180' : ''}" + class="text-surface-content/50 p-1 transform {open ? 'rotate-180' : ''}" tabindex="-1" - on:click={() => {logger.debug("toggleIcon clicked")}} + on:click={(e) => { + e.stopPropagation(); + logger.debug('toggleIcon clicked'); + open ? hide() : show(); + }} + /> + {/if} + + {#if stepper} + <Button + icon={mdiChevronRight} + on:click={(e) => { + e.stopPropagation(); + logger.debug('step right clicked'); + selectValue(next()); + }} + class="mr-2" + size="sm" /> {/if} </span> @@ -436,28 +508,44 @@ bind:open on:close={() => hide('menu on:close')} {...menuProps} - > + > <!-- TODO: Rework into hierarchy of snippets in v2.0 --> <SelectListOptions bind:menuOptionsEl - {open} {loading} {highlightIndex} {searchText} {filteredOptions} - classes={{...classes, root: cls(classes.options, inlineOptions ? "border-t mt-1 px-1" : "")}} - {optionText} {optionValue} {selectIndex} {selectOption} {onKeyPress} {onKeyDown}> - + {open} + {loading} + {highlightIndex} + {searchText} + {filteredOptions} + classes={{ + ...classes, + root: cls(classes.options, inlineOptions ? 'border-t mt-1 px-1' : ''), + }} + {optionText} + {optionValue} + {selectIndex} + {selectOption} + {onKeyPress} + {onKeyDown} + > <svelte:fragment slot="option" let:option let:index> <slot name="option" {option} {index} {selected} {value} {highlightIndex}> <MenuItem class={cls( - index === highlightIndex && '[:not(.group:hover)>&]:bg-black/5', + index === highlightIndex && '[:not(.group:hover)>&]:bg-surface-content/5', option === selected && (classes.selected || 'font-semibold'), option.group ? 'px-4' : 'px-2', - theme.option, + settingsClasses.option, classes.option )} - scrollIntoView={{ condition: index === highlightIndex, onlyIfNeeded: inlineOptions, ...scrollIntoView }} + scrollIntoView={{ + condition: index === highlightIndex, + onlyIfNeeded: inlineOptions, + ...scrollIntoView, + }} role="option" - aria-selected={option === selected ? "true" : "false"} - aria-disabled={option?.disabled ? "true" : "false"} + aria-selected={option === selected ? 'true' : 'false'} + aria-disabled={option?.disabled ? 'true' : 'false'} > {optionText(option)} </MenuItem> @@ -465,7 +553,13 @@ </svelte:fragment> <slot name="empty" slot="empty" let:loading> - <div class={cls('p-3 text-black/50 italic text-sm', theme.empty, classes.empty)}> + <div + class={cls( + 'p-3 text-surface-content/5/50 italic text-sm', + settingsClasses.empty, + classes.empty + )} + > {loading ? 'Loading...' : 'No options found'} </div> </slot> @@ -474,40 +568,62 @@ <slot name="actions" {hide} /> </Menu> {:else} - <!-- TODO: Rework into hierarchy of snippets in v2.0. --> - <!-- This code must be identical to the above block --> - <SelectListOptions - bind:menuOptionsEl - {open} {loading} {highlightIndex} {searchText} {filteredOptions} - classes={{...classes, root: cls(classes.options, inlineOptions ? "border-t mt-1 px-1" : "")}} - {optionText} {optionValue} {selectIndex} {selectOption} {onKeyPress} {onKeyDown}> - - <svelte:fragment slot="option" let:option let:index> - <slot name="option" {option} {index} {selected} {value} {highlightIndex}> - <MenuItem - class={cls( - index === highlightIndex && '[:not(.group:hover)>&]:bg-black/5', - option === selected && (classes.selected || 'font-semibold'), - option.group ? 'px-4' : 'px-2', - theme.option, - classes.option - )} - scrollIntoView={{ condition: index === highlightIndex, onlyIfNeeded: inlineOptions, ...scrollIntoView }} - role="option" - aria-selected={option === selected ? "true" : "false"} - aria-disabled={option?.disabled ? "true" : "false"} - > - {optionText(option)} - </MenuItem> - </slot> - </svelte:fragment> - - <slot name="empty" slot="empty" let:loading> - <div class={cls('p-3 text-black/50 italic text-sm', theme.empty, classes.empty)}> - {loading ? 'Loading...' : 'No options found'} - </div> + <!-- TODO: Rework into hierarchy of snippets in v2.0. --> + <!-- This code must be identical to the above block --> + <SelectListOptions + bind:menuOptionsEl + {open} + {loading} + {highlightIndex} + {searchText} + {filteredOptions} + classes={{ + ...classes, + root: cls(classes.options, inlineOptions ? 'border-t mt-1 px-1' : ''), + }} + {optionText} + {optionValue} + {selectIndex} + {selectOption} + {onKeyPress} + {onKeyDown} + > + <svelte:fragment slot="option" let:option let:index> + <slot name="option" {option} {index} {selected} {value} {highlightIndex}> + <MenuItem + class={cls( + index === highlightIndex && '[:not(.group:hover)>&]:bg-surface-content/5', + option === selected && (classes.selected || 'font-semibold'), + option.group ? 'px-4' : 'px-2', + settingsClasses.option, + classes.option + )} + scrollIntoView={{ + condition: index === highlightIndex, + onlyIfNeeded: inlineOptions, + ...scrollIntoView, + }} + role="option" + aria-selected={option === selected ? 'true' : 'false'} + aria-disabled={option?.disabled ? 'true' : 'false'} + > + {optionText(option)} + </MenuItem> </slot> - </SelectListOptions> + </svelte:fragment> + + <slot name="empty" slot="empty" let:loading> + <div + class={cls( + 'p-3 text-surface-content/5/50 italic text-sm', + settingsClasses.empty, + classes.empty + )} + > + {loading ? 'Loading...' : 'No options found'} + </div> + </slot> + </SelectListOptions> {/if} {/if} </button> diff --git a/packages/svelte-ux/src/lib/components/Settings.svelte b/packages/svelte-ux/src/lib/components/Settings.svelte index bae5e3e24..c83be65bf 100644 --- a/packages/svelte-ux/src/lib/components/Settings.svelte +++ b/packages/svelte-ux/src/lib/components/Settings.svelte @@ -1,9 +1,16 @@ <script lang="ts"> - import { settings as setSettings, type Settings } from './settings'; + import ThemeInit from './ThemeInit.svelte'; + import { settings as setSettings, type SettingsInput } from './settings'; - export let settings: Settings; + type $$Props = SettingsInput & { themeInit?: boolean }; - setSettings(settings); + /** Include the ThemeInit component to improve SSR compatibility. */ + export let themeInit = true; + + setSettings($$restProps); </script> +{#if themeInit} + <ThemeInit /> +{/if} <slot /> diff --git a/packages/svelte-ux/src/lib/components/Shine.svelte b/packages/svelte-ux/src/lib/components/Shine.svelte index 08c532b61..1102adf44 100644 --- a/packages/svelte-ux/src/lib/components/Shine.svelte +++ b/packages/svelte-ux/src/lib/components/Shine.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { uniqueId } from '$lib/utils/string'; import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; /** Color of light */ export let lightColor = '#666666'; @@ -26,7 +26,7 @@ root?: string; svg?: string; } = {}; - const theme = getComponentTheme('Shine'); + const settingsClasses = getComponentClasses('Shine'); const filterId = uniqueId('filter-'); @@ -46,7 +46,7 @@ <svelte:window on:pointermove={onPointerMove} on:scroll={onScroll} /> -<svg class={cls('fixed inset-0 pointer-events-none', theme.svg, classes?.svg)}> +<svg class={cls('fixed inset-0 pointer-events-none', settingsClasses.svg, classes?.svg)}> <filter id={filterId} color-interpolation-filters="sRGB"> <feGaussianBlur in="SourceAlpha" stdDeviation={depth} /> @@ -77,7 +77,7 @@ <div style:filter="url(#{filterId})" {...$$restProps} - class={cls('inline-block', theme.root, classes?.root, $$props.class)} + class={cls('inline-block', settingsClasses.root, classes?.root, $$props.class)} bind:this={wrapperEl} > <slot /> diff --git a/packages/svelte-ux/src/lib/components/SpringValue.svelte b/packages/svelte-ux/src/lib/components/SpringValue.svelte index 85b8bcff6..d983f72d9 100644 --- a/packages/svelte-ux/src/lib/components/SpringValue.svelte +++ b/packages/svelte-ux/src/lib/components/SpringValue.svelte @@ -1,15 +1,17 @@ <script lang="ts"> import { spring } from 'svelte/motion'; - import { format as formatUtil, type FormatType } from '../utils/format'; + import type { FormatType } from '../utils/format'; + import { getSettings } from './settings'; type T = $$Generic; type SpringOptions = Parameters<typeof spring<T>>[1]; export let value: T | 0; - export let format: FormatType = undefined; + export let format: FormatType | undefined = undefined; export let options: SpringOptions = undefined; export let disabled = false; + const { format: formatUtil } = getSettings(); const springValue = spring(value, options); $: $springValue = value ?? 0; $: displayValue = disabled || value == null ? value : $springValue; @@ -17,7 +19,7 @@ <slot value={displayValue}> {#if format} - {formatUtil(displayValue, format)} + {$formatUtil(displayValue, format)} {:else} {displayValue} {/if} diff --git a/packages/svelte-ux/src/lib/components/Steps.svelte b/packages/svelte-ux/src/lib/components/Steps.svelte index d07d9c4cf..add45b624 100644 --- a/packages/svelte-ux/src/lib/components/Steps.svelte +++ b/packages/svelte-ux/src/lib/components/Steps.svelte @@ -1,22 +1,17 @@ <script lang="ts"> - import { cssVars } from '../actions/cssVars'; - export let items: any[]; - export let lineGap = 4; // binded let circleSize = 0; - - $: styleVars = { - circleSize, - lineTop: `${circleSize + lineGap}px`, - lineBottom: `${lineGap}px`, - lineOffset: `${circleSize / 2}px`, - }; </script> -<ol use:cssVars={styleVars}> +<ol + style:--circleSize={circleSize} + style:--lineTop="{circleSize + lineGap}px" + style:--lineBottom="{lineGap}px" + style:--lineOffset="{circleSize / 2}px" +> {#each items as item, index} <li class="step relative flex gap-4 pb-10"> <div bind:clientWidth={circleSize}> @@ -25,7 +20,7 @@ {#if index < items.length - 1} <div - class="line absolute top-[var(--lineTop)] bottom-[var(--lineBottom)] left-0 w-[2px] translate-x-[var(--lineOffset)] bg-gray-300" + class="line absolute top-[var(--lineTop)] bottom-[var(--lineBottom)] left-0 w-[2px] translate-x-[var(--lineOffset)] bg-surface-content/20" /> {/if} diff --git a/packages/svelte-ux/src/lib/components/Switch.svelte b/packages/svelte-ux/src/lib/components/Switch.svelte index 3db503246..c631facd3 100644 --- a/packages/svelte-ux/src/lib/components/Switch.svelte +++ b/packages/svelte-ux/src/lib/components/Switch.svelte @@ -1,8 +1,8 @@ <script lang="ts"> - import type { TailwindColors } from '$lib/types'; + import type { ThemeColors } from '$lib/types'; import { uniqueId } from '$lib/utils/string'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let id: string = uniqueId('switch-'); export let value: any = undefined; @@ -10,7 +10,7 @@ export let disabled: boolean = false; export let size: 'sm' | 'md' | 'lg' = 'lg'; - export let color: TailwindColors = 'accent'; + export let color: ThemeColors = 'primary'; export let classes: { root?: string; @@ -18,17 +18,17 @@ switch?: string; toggle?: string; } = {}; - const theme = getComponentTheme('Switch'); + const settingsClasses = getComponentClasses('Switch'); </script> -<div class={cls('Switch', 'inline-block', theme.root, classes.root)}> +<div class={cls('Switch', 'inline-block', settingsClasses.root, classes.root)}> <input {id} type="checkbox" bind:checked on:change {value} - class={cls('peer appearance-none inline', theme.input, classes.input)} + class={cls('peer appearance-none inline', settingsClasses.input, classes.input)} {disabled} /> @@ -45,31 +45,28 @@ }, checked && { - accent: 'bg-accent-500 border-accent-500', - red: 'bg-red-500 border-red-500', - orange: 'bg-orange-500 border-orange-500', - amber: 'bg-amber-500 border-amber-500', - yellow: 'bg-yellow-500 border-yellow-500', - lime: 'bg-lime-500 border-lime-500', - green: 'bg-green-500 border-green-500', - emerald: 'bg-emerald-500 border-emerald-500', - teal: 'bg-teal-500 border-teal-500', - cyan: 'bg-cyan-500 border-cyan-500', - sky: 'bg-sky-500 border-sky-500', - blue: 'bg-blue-500 border-blue-500', - indigo: 'bg-indigo-500 border-indigo-500', - violet: 'bg-violet-500 border-violet-500', - purple: 'bg-purple-500 border-purple-500', - fuchsia: 'bg-fuchsia-500 border-fuchsia-500', - pink: 'bg-pink-500 border-pink-500', - rose: 'bg-rose-500 border-rose-500', + primary: 'bg-primary border-primary', + secondary: 'bg-secondary border-secondary', + accent: 'bg-accent border-accent', + neutral: 'bg-neutral border-neutral', + info: 'bg-info border-info', + success: 'bg-success border-success', + warning: 'bg-warning border-warning', + danger: 'bg-danger border-danger', }[color], - checked === false && 'bg-gray-300 border-gray-300', - checked === null && 'border-gray-300', - disabled - ? 'opacity-50' - : 'cursor-pointer peer-focus-visible:ring-2 ring-accent-400 ring-offset-1', - theme.switch, + { + primary: 'ring-primary/60', + secondary: 'ring-secondary/60', + accent: 'ring-accent/60', + neutral: 'ring-neutral/60', + info: 'ring-info/60', + success: 'ring-success/60', + warning: 'ring-warning/60', + danger: 'ring-danger/60', + }[color], + checked === false && 'bg-surface-content/20', + disabled ? 'opacity-50' : 'cursor-pointer peer-focus-visible:ring-2 ring-offset-1', + settingsClasses.switch, classes.switch, $$props.class )} @@ -77,10 +74,10 @@ <div data-checked={checked} class={cls( - 'toggle w-1/2 aspect-square h-full rounded-full transition-all duration-200 bg-white grid items-center justify-center transform', + 'toggle w-1/2 aspect-square h-full rounded-full transition-all duration-200 bg-surface-100 grid items-center justify-center transform', checked && 'translate-x-full', - checked === null && 'border border-gray-300', - theme.toggle, + checked === null && 'border', + settingsClasses.toggle, classes.toggle )} > diff --git a/packages/svelte-ux/src/lib/components/Tab.svelte b/packages/svelte-ux/src/lib/components/Tab.svelte index 5bb8ecf48..7ff3accf4 100644 --- a/packages/svelte-ux/src/lib/components/Tab.svelte +++ b/packages/svelte-ux/src/lib/components/Tab.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { slide } from 'svelte/transition'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let selected: boolean = false; export let placement: 'top' | 'bottom' | 'left' | 'right' = 'top'; @@ -11,7 +11,7 @@ export let classes: { root?: string; } = {}; - const theme = getComponentTheme('Tab'); + const settingsClasses = getComponentClasses('Tab'); </script> <button @@ -21,15 +21,15 @@ 'inline-flex items-center gap-1 whitespace-nowrap border px-3 py-2 text-xs', `placement-${placement}`, { - top: selected && 'border-b-white', - bottom: selected && 'border-t-white', - left: selected && 'border-r-white', - right: selected && 'border-l-white', + top: selected && 'border-b-surface-100', + bottom: selected && 'border-t-surface-100', + left: selected && 'border-r-surface-100', + right: selected && 'border-l-surface-100', }[placement], selected - ? 'bg-white text-gray-900' - : 'bg-gray-100 text-gray-600 hover:text-gray-900 hover:bg-gray-50', - theme.root, + ? 'bg-surface-100 text-surface-content' + : 'bg-surface-200 text-surface-content/50 hover:text-surface-content hover:bg-surface-100', + settingsClasses.root, classes.root, $$props.class )} diff --git a/packages/svelte-ux/src/lib/components/Table.svelte b/packages/svelte-ux/src/lib/components/Table.svelte index c5fbcafb1..9dfc1432d 100644 --- a/packages/svelte-ux/src/lib/components/Table.svelte +++ b/packages/svelte-ux/src/lib/components/Table.svelte @@ -5,16 +5,11 @@ import type { ColumnDef } from '../types/table'; import { cls } from '../utils/styles'; - import { - getCellValue, - getCellContent, - getCellHeader, - getHeaders, - getRowColumns, - } from '../utils/table'; + import { getCellValue, getCellHeader, getHeaders, getRowColumns } from '../utils/table'; import TableOrderIcon from './TableOrderIcon.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; + import { getSettings } from './settings'; const dispatch = createEventDispatcher(); @@ -34,8 +29,8 @@ td?: string; } = {}; // TODO: Figure out circular reference error - // const theme = getComponentTheme('Table'); - const theme: typeof classes = {}; + // const settingsClasses = getComponentClasses('Table'); + const settingsClasses: typeof classes = {}; export let styles: { container?: string; @@ -55,8 +50,8 @@ return { ...column, classes: { - th: cls(theme.th, classes.th, column.classes?.th), - td: cls(theme.td, classes.td, column.classes?.td), + th: cls(settingsClasses.th, classes.th, column.classes?.th), + td: cls(settingsClasses.td, classes.td, column.classes?.td), }, }; }); @@ -65,24 +60,47 @@ return { ...column, classes: { - th: cls(theme.th, classes.th, column.classes?.th), - td: cls(theme.td, classes.td, column.classes?.td), + th: cls(settingsClasses.th, classes.th, column.classes?.th), + td: cls(settingsClasses.td, classes.td, column.classes?.td), }, }; }); + + const { format } = getSettings(); + $: getCellContent = (column: ColumnDef, rowData: any, rowIndex: number) => { + let value = getCellValue(column, rowData, rowIndex); + if (column.format) { + if (typeof column.format === 'function') { + return column.format(value, rowData, rowIndex); + } else { + return $format(value, column.format); + } + } else { + return value; + } + }; </script> <!-- svelte-ignore a11y-click-events-have-key-events --> <div - class={cls('Table', 'table-container', theme.container, classes.container, $$props.class)} + class={cls( + 'Table', + 'table-container', + settingsClasses.container, + classes.container, + $$props.class + )} style={styles.container} > - <div class={cls('table-wrapper', theme.wrapper, classes.wrapper)} style={styles.wrapper}> - <table class={cls('w-full', theme.table, classes.table)} style={styles.table}> + <div + class={cls('table-wrapper', settingsClasses.wrapper, classes.wrapper)} + style={styles.wrapper} + > + <table class={cls('w-full', settingsClasses.table, classes.table)} style={styles.table}> <slot name="headers" {headers} {getCellHeader}> - <thead class={cls(theme.thead, classes.thead)} style={styles.thead}> + <thead class={cls(settingsClasses.thead, classes.thead)} style={styles.thead}> {#each headers ?? [] as headerRow} - <tr class={cls(theme.tr, classes.tr)} style={styles.tr}> + <tr class={cls(settingsClasses.tr, classes.tr)} style={styles.tr}> {#each headerRow ?? [] as column} <th use:tableCell={{ column }} @@ -103,9 +121,9 @@ <slot /> <slot name="data" {data} columns={rowColumns} {getCellValue} {getCellContent}> - <tbody class={cls(theme.tbody, classes.tbody)} style={styles.tbody}> + <tbody class={cls(settingsClasses.tbody, classes.tbody)} style={styles.tbody}> {#each data ?? [] as rowData, rowIndex} - <tr class={cls(theme.tr, classes.tr)} style={styles.tr}> + <tr class={cls(settingsClasses.tr, classes.tr)} style={styles.tr}> {#each rowColumns ?? [] as column} <td use:tableCell={{ column, rowData, rowIndex, tableData: data }} diff --git a/packages/svelte-ux/src/lib/components/TableOfContents.svelte b/packages/svelte-ux/src/lib/components/TableOfContents.svelte index 6a1acbef4..c20b953f1 100644 --- a/packages/svelte-ux/src/lib/components/TableOfContents.svelte +++ b/packages/svelte-ux/src/lib/components/TableOfContents.svelte @@ -6,16 +6,17 @@ import { cls } from '../utils/styles'; import TreeList from './TreeList.svelte'; import Icon from './Icon.svelte'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let element = 'main'; export let maxDepth = 6; + export let icon = mdiCircleSmall; let activeHeadingId = ''; let headings = []; let nodes = []; - const theme = getComponentTheme('TableOfContents'); + const settingsClasses = getComponentClasses('TableOfContents'); function onScroll(e) { activeHeadingId = headings?.find( @@ -56,20 +57,20 @@ {nodes} classes={{ li: (node) => cls(node.level === 1 ? 'mb-2' : node.level > 2 ? 'ml-3' : '') }} {...$$restProps} - class={cls('TableOfContents', theme.root, $$props.class)} + class={cls('TableOfContents', settingsClasses.root, $$props.class)} let:node > <slot {node} {activeHeadingId}> <a href="#{node.id}" class={cls( - 'flex gap-1 px-2 rounded-lg hover:bg-black/5 ', + 'flex gap-1 px-2 rounded-lg hover:bg-surface-content/5 ', node.level === 1 ? 'font-semibold' : 'text-sm', - node.id && node.id === activeHeadingId && 'bg-black/5' + node.id && node.id === activeHeadingId && 'bg-surface-content/5' )} > {#if node.level > 1} - <Icon path={mdiCircleSmall} class="-mx-1 text-black/30" /> + <Icon path={icon} class="-mx-1 text-surface-content/30" /> {/if} {@html node.name} </a> diff --git a/packages/svelte-ux/src/lib/components/Tabs.svelte b/packages/svelte-ux/src/lib/components/Tabs.svelte index ec00f31a5..cdda96ccd 100644 --- a/packages/svelte-ux/src/lib/components/Tabs.svelte +++ b/packages/svelte-ux/src/lib/components/Tabs.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import type { ComponentProps } from 'svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import Tab from './Tab.svelte'; export let value: any = undefined; @@ -17,7 +17,7 @@ tab?: ComponentProps<Tab>['classes']; content?: string; } = {}; - const theme = getComponentTheme('Tabs'); + const settingsClasses = getComponentClasses('Tabs'); </script> <div @@ -31,7 +31,7 @@ left: 'flex-row', right: 'flex-row-reverse', }[placement], - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -46,7 +46,7 @@ left: '-mr-px', right: '-ml-px', }[placement], - theme.tabs, + settingsClasses.tabs, classes.tabs )} > @@ -56,7 +56,7 @@ {placement} selected={value === tab.value} on:click={() => (value = tab.value)} - classes={{ ...theme.tab, ...classes.tab }} + classes={{ ...settingsClasses.tab, ...classes.tab }} > {tab.label} </Tab> @@ -73,7 +73,7 @@ left: 'border-l', right: 'border-r', }[placement], - theme.content, + settingsClasses.content, classes.content )} > diff --git a/packages/svelte-ux/src/lib/components/TextField.svelte b/packages/svelte-ux/src/lib/components/TextField.svelte index 82e1c968f..43b16b8a6 100644 --- a/packages/svelte-ux/src/lib/components/TextField.svelte +++ b/packages/svelte-ux/src/lib/components/TextField.svelte @@ -9,7 +9,7 @@ import type { Actions } from '../actions/multi'; import { cls } from '../utils/styles'; import { isLiteralObject } from '../utils/object'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import Button from './Button.svelte'; import Icon from './Icon.svelte'; @@ -66,7 +66,7 @@ prepend?: string; append?: string; } = {}; - const theme = getComponentTheme('TextField'); + const settingsClasses = getComponentClasses('TextField'); // Input props export let mask: string | undefined = undefined; @@ -122,7 +122,7 @@ let inputValue: InputValue = ''; $: potentialInputValue = isLiteralObject(value) ? Object.values(value)[0] : value ?? null; - $: if(inputType !== 'number' || inputValue != potentialInputValue) { + $: if (inputType !== 'number' || inputValue != potentialInputValue) { // Update the inputValue, but when the input type is number only do it if the values are actually different. // This avoids the cursor jumping around when backspacing numbers around a decimal point, since // e.g. "123" and "123." are both 123. @@ -200,10 +200,10 @@ 'TextField', 'group flex gap-1', labelPlacement !== 'left' ? 'flex-col' : 'items-center', - error ? '[--color:theme(colors.red.500)]' : '[--color:theme(colors.accent.500)]', + error ? '[--color:theme(colors.danger)]' : '[--color:theme(colors.primary)]', disabled && 'opacity-50 pointer-events-none', !base && (rounded ? 'rounded-full' : 'rounded'), - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -212,10 +212,10 @@ <label class={cls( 'block text-sm font-medium', - 'truncate group-hover:text-gray-700 group-focus-within:text-[var(--color)] group-hover:group-focus-within:text-[var(--color)] cursor-pointer', - error ? 'text-red-500/80' : 'text-black/50', + 'truncate group-hover:text-surface-content/70 group-focus-within:text-[var(--color)] group-hover:group-focus-within:text-[var(--color)] cursor-pointer', + error ? 'text-danger/80' : 'text-surface-content/50', `placement-${labelPlacement}`, - theme.label, + settingsClasses.label, classes.label )} for={id} @@ -230,15 +230,15 @@ class={cls( 'border py-0 transition-shadow', disabled ? '' : 'hover:shadow', - disabled ? '' : error ? 'hover:border-red-700' : 'hover:border-gray-700', + disabled ? '' : error ? 'hover:border-danger' : 'hover:border-surface-content', { 'px-2': !rounded, 'px-6': rounded && !hasPrepend, // TODO: `hasPrepend` always true for SelectField, etc. See: https://github.com/sveltejs/svelte/issues/6059 }, - !base && ['bg-white', rounded ? 'rounded-full' : 'rounded'], - error ? 'border-red-500' : 'border-black/20', + !base && ['bg-surface-100', rounded ? 'rounded-full' : 'rounded'], + error && 'border-danger', 'group-focus-within:shadow-md group-focus-within:border-[var(--color)]', - theme.container, + settingsClasses.container, classes.container )} > @@ -248,14 +248,14 @@ class={cls( 'prepend whitespace-nowrap', rounded && 'pl-3', - theme.prepend, + settingsClasses.prepend, classes.prepend )} > <slot name="prepend" /> {#if icon} <span class="mr-3"> - <Icon data={asIconData(icon)} class="text-black/50" /> + <Icon data={asIconData(icon)} class="text-surface-content/50" /> </span> {/if} </div> @@ -266,11 +266,11 @@ {#if label && ['inset', 'float'].includes(labelPlacement)} <label class={cls( - 'col-span-full row-span-full z-[1] flex items-center h-full truncate origin-top-left transition-all duration-200 group-hover:text-gray-700 group-focus-within:text-[var(--color)] group-hover:group-focus-within:text-[var(--color)] cursor-pointer', - error ? 'text-red-500/80' : 'text-black/50', + 'col-span-full row-span-full z-[1] flex items-center h-full truncate origin-top-left transition-all duration-200 group-hover:text-surface-content/70 group-focus-within:text-[var(--color)] group-hover:group-focus-within:text-[var(--color)] cursor-pointer', + error ? 'text-danger/80' : 'text-surface-content/50', `placement-${labelPlacement}`, (labelPlacement === 'inset' || hasInputValue) && 'shrink', - theme.label, + settingsClasses.label, classes.label )} for={id} @@ -296,7 +296,7 @@ <slot name="prefix" /> {#if type === 'currency'} - <Icon path={mdiCurrencyUsd} size="1.1em" class="text-black/50 -mt-1" /> + <Icon path={mdiCurrencyUsd} size="1.1em" class="text-surface-content/50 -mt-1" /> {/if} {#if multiline} @@ -315,15 +315,15 @@ on:keypress class={cls( 'text-sm border-none w-full bg-transparent outline-none resize-none', - 'placeholder-black placeholder-opacity-0 group-focus-within:placeholder-opacity-30', - error && 'placeholder-red-800', - (labelPlacement !== 'float' || !hasInsetLabel) && 'placeholder-opacity-30', + 'placeholder-surface-content placeholder-opacity-0 group-focus-within:placeholder-opacity-50', + error && 'placeholder-danger', + (labelPlacement !== 'float' || !hasInsetLabel) && 'placeholder-opacity-50', { 'text-left': align === 'left', 'text-center': align === 'center', 'text-right': align === 'right', }, - theme.input, + settingsClasses.input, classes.input )} use:multi={textAreaMultiAction} @@ -351,23 +351,23 @@ on:keypress class={cls( 'text-sm border-none w-full bg-transparent outline-none truncate', - 'selection:bg-gray-500/30', - 'placeholder-black placeholder-opacity-0 group-focus-within:placeholder-opacity-30', - error && 'placeholder-red-800', - (labelPlacement !== 'float' || !hasInsetLabel) && 'placeholder-opacity-30', + 'selection:bg-surface-content/30', + 'placeholder-surface-content placeholder-opacity-0 group-focus-within:placeholder-opacity-50', + error && 'placeholder-danger', + (labelPlacement !== 'float' || !hasInsetLabel) && 'placeholder-opacity-50', { 'text-left': align === 'left', 'text-center': align === 'center', 'text-right': align === 'right', }, - theme.input, + settingsClasses.input, classes.input )} /> {/if} {#if type === 'percent'} - <Icon path={mdiPercent} size="1.1em" class="text-black/50 -mt-1 ml-1" /> + <Icon path={mdiPercent} size="1.1em" class="text-surface-content/50 -mt-1 ml-1" /> {/if} <slot name="suffix" /> @@ -375,12 +375,12 @@ </div> {#if hasAppend} - <div class={cls('append whitespace-nowrap', theme.append, classes.append)}> + <div class={cls('append whitespace-nowrap', settingsClasses.append, classes.append)}> {#if clearable && hasInputValue} <Button icon={mdiClose} {disabled} - class="text-black/50 p-1" + class="text-surface-content/50 p-1" on:click={() => { inputValue = ''; operator = operators?.[0].value; @@ -396,7 +396,7 @@ {disabled} value={operator} on:change={onSelectChange} - class="appearance-none bg-black/5 border border-black/20 rounded-full mr-2 px-2 text-sm outline-none focus:border-opacity-50 focus:shadow-md" + class="appearance-none bg-surface-content/5 border rounded-full mr-2 px-2 text-sm outline-none focus:border-opacity-50 focus:shadow-md" style="text-align-last: center;" > {#each operators ?? [] as { label, value }} @@ -409,7 +409,7 @@ <Button icon={mdiEye} {disabled} - class="text-black/50 p-2" + class="text-surface-content/50 p-2" on:click={() => { if (inputType === 'password') { inputType = 'text'; @@ -423,9 +423,9 @@ <slot name="append" /> {#if error} - <Icon path={mdiInformationOutline} class="text-red-500" /> + <Icon path={mdiInformationOutline} class="text-danger" /> {:else if iconRight} - <Icon data={asIconData(iconRight)} class="text-black/50" /> + <Icon data={asIconData(iconRight)} class="text-surface-content/50" /> {/if} </div> {/if} @@ -436,8 +436,8 @@ class={cls( error ? 'error' : 'hint', 'text-xs ml-2 transition-transform ease-out overflow-hidden origin-top transform group-focus-within:scale-y-100', - error ? 'text-red-500' : 'text-black/50 scale-y-0', - theme.error, + error ? 'text-danger' : 'text-surface-content/50 scale-y-0', + settingsClasses.error, classes.error )} > diff --git a/packages/svelte-ux/src/lib/components/ThemeInit.svelte b/packages/svelte-ux/src/lib/components/ThemeInit.svelte new file mode 100644 index 000000000..6daffa81e --- /dev/null +++ b/packages/svelte-ux/src/lib/components/ThemeInit.svelte @@ -0,0 +1,12 @@ +<script> + import { createHeadSnippet } from '../styles/theme'; + import { getSettings } from './settings'; + + const darkThemes = getSettings().themes?.dark ?? []; + + let headSnippet = createHeadSnippet(darkThemes); +</script> + +<svelte:head> + {@html headSnippet} +</svelte:head> diff --git a/packages/svelte-ux/src/lib/components/ThemeSelect.svelte b/packages/svelte-ux/src/lib/components/ThemeSelect.svelte new file mode 100644 index 000000000..5cad6b4c0 --- /dev/null +++ b/packages/svelte-ux/src/lib/components/ThemeSelect.svelte @@ -0,0 +1,126 @@ +<script lang="ts"> + import { fly } from 'svelte/transition'; + + import { mdiPalette, mdiUndoVariant, mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js'; + + import Button from './Button.svelte'; + import Kbd from './Kbd.svelte'; + import Menu from './Menu.svelte'; + import Switch from './Switch.svelte'; + import Icon from './Icon.svelte'; + import MenuItem from './MenuItem.svelte'; + import Tooltip from './Tooltip.svelte'; + + import { cls } from '../utils/styles'; + import { getSettings } from './settings'; + + const { currentTheme, themes: allThemes } = getSettings(); + + /** The list of dark themes to chose from, if not the list provided to `settings`. */ + export let darkThemes = allThemes?.dark ?? ['dark']; + /** The list of light themes to chose from, if not the list provided to `settings`. */ + export let lightThemes = allThemes?.light ?? ['light']; + + let open = false; + + $: themes = $currentTheme.dark ? darkThemes : lightThemes; + + function onKeyDown(e: KeyboardEvent) { + if (e.ctrlKey && e.code === 'KeyT') { + if (e.shiftKey) { + // Pick next theme + const currentIndex = themes.indexOf($currentTheme.resolvedTheme); + let newTheme = themes[(currentIndex + 1) % themes.length]; + currentTheme.setTheme(newTheme); + } else { + // Toggle light/dark + let newTheme = $currentTheme.dark ? 'light' : 'dark'; + currentTheme.setTheme(newTheme); + } + } + } +</script> + +<Button icon={mdiPalette} iconOnly on:click={() => (open = !open)}> + <Menu + bind:open + on:close={() => (open = false)} + offset={4} + explicitClose + resize="height" + classes={{ root: 'w-[400px] max-w-[95vw]' }} + > + <label + for="switch-color-scheme" + class="grid grid-cols-[1fr,auto,auto] items-center p-2 border-b border-surface-content/10 mb-1 text-sm font-medium" + > + Mode + + {#if $currentTheme.theme} + <span transition:fly={{ x: 8 }}> + <Tooltip title="Reset to System" offset={2}> + <Button + icon={mdiUndoVariant} + color="primary" + size="sm" + class="mr-1" + on:click={() => { + currentTheme.setTheme('system'); + }} + /> + </Tooltip> + </span> + {/if} + + <Switch + id="switch-color-scheme" + checked={!$currentTheme.dark} + on:change={(e) => { + let newTheme = e.target?.checked ? 'light' : 'dark'; + currentTheme.setTheme(newTheme); + }} + class="my-1" + let:checked + > + {#if checked} + <Icon data={mdiWhiteBalanceSunny} size=".8rem" class="text-primary" /> + {:else} + <Icon data={mdiWeatherNight} size=".8rem" class="text-primary" /> + {/if} + </Switch> + </label> + + <div class="grid grid-cols-2 gap-2 p-2 border-b border-surface-content/10"> + {#each themes as themeName} + <MenuItem + on:click={() => currentTheme.setTheme(themeName)} + data-theme={themeName} + class={cls( + 'bg-surface-100 text-surface-content font-semibold border shadow', + $currentTheme.resolvedTheme === themeName && 'ring-2 ring-surface-content' + )} + > + <div class="grid gap-1"> + <div class="w-4 h-4 rounded-full bg-primary" /> + <div class="w-4 h-4 rounded-full bg-secondary" /> + </div> + {themeName} + </MenuItem> + {/each} + </div> + + <div class="p-2 grid grid-cols-[auto,1fr] gap-2 items-center text-xs"> + <span class="font-medium">Toggle scheme:</span> + <span> + <Kbd control /> + <Kbd>T</Kbd> + </span> + + <span class="font-medium">Next theme:</span> + <span> + <Kbd control /> + <Kbd shift /> + <Kbd>T</Kbd> + </span> + </div> + </Menu> +</Button> + +<svelte:window on:keydown={onKeyDown} /> diff --git a/packages/svelte-ux/src/lib/components/ThemeSwitch.svelte b/packages/svelte-ux/src/lib/components/ThemeSwitch.svelte new file mode 100644 index 000000000..7dfe6514f --- /dev/null +++ b/packages/svelte-ux/src/lib/components/ThemeSwitch.svelte @@ -0,0 +1,26 @@ +<script lang="ts"> + import { mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js'; + + import Switch from './Switch.svelte'; + import Icon from './Icon.svelte'; + + import { getSettings } from './settings'; + + const { currentTheme } = getSettings(); +</script> + +<Switch + checked={!$currentTheme.dark} + on:change={(e) => { + const newTheme = e.target?.checked ? 'light' : 'dark'; + currentTheme.setTheme(newTheme); + }} + let:checked + {...$$restProps} +> + {#if checked} + <Icon data={mdiWhiteBalanceSunny} size=".8rem" class="text-primary" /> + {:else} + <Icon data={mdiWeatherNight} size=".8rem" class="text-primary" /> + {/if} +</Switch> diff --git a/packages/svelte-ux/src/lib/components/Tilt.svelte b/packages/svelte-ux/src/lib/components/Tilt.svelte index 62dcf8ceb..66a207aaf 100644 --- a/packages/svelte-ux/src/lib/components/Tilt.svelte +++ b/packages/svelte-ux/src/lib/components/Tilt.svelte @@ -1,12 +1,12 @@ <script lang="ts"> import { cls } from '$lib/utils/styles'; import { scaleLinear } from 'd3-scale'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let maxRotation = 20; export let setBrightness = false; - const theme = getComponentTheme('Tilt'); + const settingsClasses = getComponentClasses('Tilt'); let width = 0; let height = 0; @@ -45,7 +45,7 @@ 'Tilt [perspective:600px]', '[&>*]:[transform:rotateX(var(--rotateX))_rotateY(var(--rotateY))]', '[&>*]:brightness-[var(--brightness)]', - theme.root, + settingsClasses.root, $$props.class )} bind:clientWidth={width} diff --git a/packages/svelte-ux/src/lib/components/ToggleGroup.svelte b/packages/svelte-ux/src/lib/components/ToggleGroup.svelte index 64ff71b03..766e9a2f7 100644 --- a/packages/svelte-ux/src/lib/components/ToggleGroup.svelte +++ b/packages/svelte-ux/src/lib/components/ToggleGroup.svelte @@ -9,7 +9,7 @@ import { cls } from '../utils/styles'; import Logger from '../utils/logger'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value: any = undefined; // index or value export let autoscroll: boolean = false; @@ -19,7 +19,7 @@ | 'outline' | 'fill' | 'fill-light' - | 'fill-white' + | 'fill-surface' | 'underline' | 'none' = 'default'; export let size: 'xs' | 'sm' | 'md' | 'lg' = 'md'; @@ -35,49 +35,49 @@ option?: string; indicator?: string; } = {}; - const theme = getComponentTheme('ToggleGroup'); + const settingsClasses = getComponentClasses('ToggleGroup'); $: variantClasses = { default: { options: '', - label: 'text-gray-500 hover:text-accent-500 [&.selected]:text-accent-500', - indicator: 'h-full bg-accent-50', + label: 'text-surface-content/60 hover:text-primary [&.selected]:text-primary', + indicator: 'h-full bg-primary/10', }, outline: { - options: 'border hover:border-gray-300', - label: 'text-gray-500 hover:text-accent-500 [&.selected]:text-accent-500', - indicator: 'h-full w-full bg-accent-50', + options: 'border', + label: 'text-surface-content/60 hover:text-primary [&.selected]:text-primary', + indicator: 'h-full w-full bg-primary/10', }, fill: { - options: cls(!gap && 'bg-accent-500/10'), + options: cls(!gap && 'bg-primary/10'), label: cls( - 'text-accent-500 hover:text-accent-600 hover:bg-accent-500/10 [&.selected]:text-accent-50', - gap && 'bg-accent-500/10' + 'text-primary hover:text-primary-700 hover:bg-primary/10 [&.selected]:text-primary-content', + gap && 'bg-primary/10' ), - indicator: 'h-full bg-accent-500', + indicator: 'h-full bg-primary', }, 'fill-light': { - options: cls(!gap && 'bg-gray-500/10'), + options: cls(!gap && 'bg-surface-content/10'), label: cls( - 'text-gray-500 hover:text-gray-600 hover:bg-gray-500/10 [&.selected]:text-accent-500', - gap && 'bg-gray-500/10' + 'text-surface-content/60 hover:text-surface-content/80 hover:bg-surface-content/10 [&.selected]:text-primary', + gap && 'bg-surface-content/10' ), - indicator: 'h-full bg-accent-100', + indicator: 'h-full bg-primary/10', }, - 'fill-white': { - options: cls(!gap && 'bg-gray-500/10'), + 'fill-surface': { + options: cls(!gap && 'bg-surface-content/10'), label: cls( - 'text-gray-500 hover:text-gray-600 hover:bg-gray-500/10 [&.selected]:text-accent-500', - gap && 'bg-gray-500/10' + 'text-surface-content/60 hover:text-surface-content/80 hover:bg-surface-content/10 [&.selected]:text-primary', + gap && 'bg-surface-content/10' ), - indicator: 'h-full bg-white border', + indicator: 'h-full bg-surface-100 border', }, underline: { options: vertical ? 'border-r' : 'border-b', label: - 'relative text-black/50 font-bold hover:text-accent-500 hover:bg-accent-500/10 [&.selected]:text-accent-500', + 'relative text-surface-content/50 font-bold hover:text-primary hover:bg-primary/10 [&.selected]:text-primary', indicator: cls( - 'absolute border-accent-500', + 'absolute border-primary', vertical ? 'top-0 right-0 h-full border-l-4 rounded-l' : 'bottom-0 left-0 w-full border-t-2 rounded-t' @@ -98,7 +98,7 @@ gap === true ? 'gap-1' : gap === 'px' ? 'gap-px' : '', inset ? 'p-[2px]' : '', variantClasses[variant].options, - theme.options, + settingsClasses.options, classes.options ), @@ -127,7 +127,7 @@ '[&:not(:last-child)_.indicator]:rounded-r-none', ]), variantClasses[variant].label, - theme.label, + settingsClasses.label, classes.label ), @@ -140,7 +140,7 @@ lg: 'py-1', }[size], variantClasses[variant].option, - theme.option, + settingsClasses.option, classes.option ), @@ -148,7 +148,7 @@ 'z-0', rounded === 'full' ? 'rounded-full' : rounded && 'rounded', variantClasses[variant].indicator, - theme.indicator, + settingsClasses.indicator, classes.indicator ), }; diff --git a/packages/svelte-ux/src/lib/components/ToggleOption.svelte b/packages/svelte-ux/src/lib/components/ToggleOption.svelte index c5eee6999..0fe25b937 100644 --- a/packages/svelte-ux/src/lib/components/ToggleOption.svelte +++ b/packages/svelte-ux/src/lib/components/ToggleOption.svelte @@ -4,7 +4,7 @@ import { groupKey } from './ToggleGroup.svelte'; import { scrollIntoView } from '../utils/dom'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let value: any; @@ -13,7 +13,7 @@ option?: string; indicator?: string; } = {}; - const theme = getComponentTheme('ToggleOption'); + const settingsClasses = getComponentClasses('ToggleOption'); const { registerOption, @@ -54,7 +54,7 @@ 'label', 'grid items-center', $classesContext.label, - theme.root, + settingsClasses.root, classes.root, $$props.class )} @@ -62,13 +62,18 @@ <!-- Stack indicator under option --> {#if selected} <div - class={cls('indicator', $classesContext.indicator, theme.indicator, classes.indicator)} + class={cls( + 'indicator', + $classesContext.indicator, + settingsClasses.indicator, + classes.indicator + )} in:receive={{ key: 'indicator' }} out:send={{ key: 'indicator' }} /> {/if} - <div class={cls('option', $classesContext.option, theme.option, classes.option)}> + <div class={cls('option', $classesContext.option, settingsClasses.option, classes.option)}> <slot {selected} /> </div> diff --git a/packages/svelte-ux/src/lib/components/Tooltip.svelte b/packages/svelte-ux/src/lib/components/Tooltip.svelte index 2fa718bc1..f86894c6c 100644 --- a/packages/svelte-ux/src/lib/components/Tooltip.svelte +++ b/packages/svelte-ux/src/lib/components/Tooltip.svelte @@ -8,7 +8,7 @@ import Popover from './Popover.svelte'; import { cls } from '../utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; export let title = ''; export let open = false; @@ -29,7 +29,7 @@ title?: string; content?: string; } = {}; - const theme = getComponentTheme('Tooltip'); + const settingsClasses = getComponentClasses('Tooltip'); $: hasTitle = title || $$slots.title; @@ -82,14 +82,14 @@ {offset} {matchWidth} {open} - class={cls('Tooltip pointer-events-none', theme.popover, classes.popover)} + class={cls('Tooltip pointer-events-none', settingsClasses.popover, classes.popover)} {...$$restProps} > <slot name="title"> <div class={cls( - 'text-white text-xs bg-gray-900/90 px-2 py-1 rounded whitespace-nowrap', - theme.title, + 'text-xs text-surface-100 bg-surface-content px-2 py-1 rounded whitespace-nowrap', + settingsClasses.title, classes.title )} transition:fly={{ @@ -106,7 +106,7 @@ <!-- svelte-ignore a11y-click-events-have-key-events --> <div - class={cls('contents', theme.content, classes.content)} + class={cls('contents', settingsClasses.content, classes.content)} on:mouseenter={showTooltip} on:mouseleave={hideTooltip} on:focusin={onFocusIn} @@ -119,7 +119,7 @@ class={cls( hasTitle && underline && 'border-b border-dotted', hasTitle && cursor && 'cursor-help', - theme.root, + settingsClasses.root, classes.root, $$props.class )} diff --git a/packages/svelte-ux/src/lib/components/TreeList.svelte b/packages/svelte-ux/src/lib/components/TreeList.svelte index 8f22c9b3e..acff5d017 100644 --- a/packages/svelte-ux/src/lib/components/TreeList.svelte +++ b/packages/svelte-ux/src/lib/components/TreeList.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { cls } from '$lib/utils/styles'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; type Node = { id: number; name: string; level: number; children: Node[] }; @@ -10,13 +10,13 @@ ul?: string | ((nodes: Node[]) => string); li?: string | ((node: Node) => string); } = {}; - const theme = getComponentTheme('TreeList'); + const settingsClasses = getComponentClasses('TreeList'); </script> <ul class={cls( 'TreeList', - typeof theme.ul === 'string' ? theme.ul : theme.ul?.(nodes), + typeof settingsClasses.ul === 'string' ? settingsClasses.ul : settingsClasses.ul?.(nodes), typeof classes.ul === 'string' ? classes.ul : classes.ul?.(nodes), $$props.class )} @@ -24,7 +24,7 @@ {#each nodes ?? [] as node} <li class={cls( - typeof theme.li === 'string' ? theme.li : theme.li?.(node), + typeof settingsClasses.li === 'string' ? settingsClasses.li : settingsClasses.li?.(node), typeof classes.li === 'string' ? classes.li : classes.li?.(node) )} > diff --git a/packages/svelte-ux/src/lib/components/TweenedValue.svelte b/packages/svelte-ux/src/lib/components/TweenedValue.svelte index 5b9a5af64..2cfaa9c05 100644 --- a/packages/svelte-ux/src/lib/components/TweenedValue.svelte +++ b/packages/svelte-ux/src/lib/components/TweenedValue.svelte @@ -1,15 +1,17 @@ <script lang="ts"> import { tweened } from 'svelte/motion'; - import { format as formatUtil, type FormatType } from '../utils/format'; + import type { FormatType } from '../utils/format'; + import { getSettings } from './settings'; type T = $$Generic; type TweenedOptions = Parameters<typeof tweened<T>>[1]; export let value: T | 0; - export let format: FormatType = undefined; + export let format: FormatType | undefined = undefined; export let options: TweenedOptions = undefined; export let disabled = false; + const { format: formatUtil } = getSettings(); const tweenedValue = tweened(value, options); $: $tweenedValue = value ?? 0; $: displayValue = disabled || value == null ? value : $tweenedValue; @@ -17,7 +19,7 @@ <slot value={displayValue}> {#if format} - {formatUtil(displayValue, format)} + {$formatUtil(displayValue, format)} {:else} {displayValue} {/if} diff --git a/packages/svelte-ux/src/lib/components/YearList.svelte b/packages/svelte-ux/src/lib/components/YearList.svelte index 29e6c6d3a..552666ba1 100644 --- a/packages/svelte-ux/src/lib/components/YearList.svelte +++ b/packages/svelte-ux/src/lib/components/YearList.svelte @@ -42,15 +42,15 @@ return disabledYears instanceof Function ? disabledYears(date) : disabledYears instanceof Date - ? isSameYear(date, disabledYears) - : disabledYears instanceof Array - ? disabledYears.some((d) => isSameYear(date, d)) - : disabledYears instanceof Object - ? isWithinInterval(date, { - start: startOfYear(disabledYears.from), - end: endOfYear(disabledYears.to || disabledYears.from), - }) - : false; + ? isSameYear(date, disabledYears) + : disabledYears instanceof Array + ? disabledYears.some((d) => isSameYear(date, d)) + : disabledYears instanceof Object + ? isWithinInterval(date, { + start: startOfYear(disabledYears.from), + end: endOfYear(disabledYears.to || disabledYears.from), + }) + : false; }; </script> diff --git a/packages/svelte-ux/src/lib/components/_SelectListOptions.svelte b/packages/svelte-ux/src/lib/components/_SelectListOptions.svelte index e8106dff3..caeabf749 100644 --- a/packages/svelte-ux/src/lib/components/_SelectListOptions.svelte +++ b/packages/svelte-ux/src/lib/components/_SelectListOptions.svelte @@ -1,20 +1,20 @@ -<script lang='ts'> +<script lang="ts"> import Logger from '../utils/logger'; - import { getComponentTheme } from './theme'; + import { getComponentClasses } from './theme'; import { cls } from '../utils/styles'; const logger = new Logger('SelectListOptions'); export let optionText: (option: any) => string; export let optionValue: (option: any) => any; - export let selectIndex: (index: number) => any; - export let selectOption: (x: any) => any; - export let onKeyDown: (x: KeyboardEvent) => void; - export let onKeyPress: (x: KeyboardEvent) => void; + export let selectIndex: (index: number) => any; + export let selectOption: (x: any) => any; + export let onKeyDown: (x: KeyboardEvent) => void; + export let onKeyPress: (x: KeyboardEvent) => void; - export let open: boolean; + export let open: boolean; export let loading: boolean; - export let filteredOptions: any[]; + export let filteredOptions: any[]; export let value: any = undefined; export let selected: any = undefined; @@ -30,63 +30,67 @@ empty?: string; } = {}; - const theme = getComponentTheme('SelectField'); + const settingsClasses = getComponentClasses('SelectField'); - export let menuOptionsEl: HTMLDivElement; + export let menuOptionsEl: HTMLDivElement; </script> <div - role='listbox' - tabindex='-1' - aria-expanded={open ? 'true' : 'false'} - class={cls('_SelectListOptions options group p-1 focus:outline-none', theme.options, classes.root)} - class:opacity-50={loading} - bind:this={menuOptionsEl} - on:click|stopPropagation={(e) => { - logger.debug('options container clicked'); - - if (e.target instanceof HTMLElement) { - // Find slot parent of click target option, fallback to `e.target` if slot is not overridden - // Use `.options > ` in case slot is nested (ex. GraphQLSelect with slot) - const slotEl = e.target.closest('.options > [slot=option]') ?? e.target; - // Find the index of the clicked on element (ignoring group headers) - const optionIndex = slotEl - ? [...menuOptionsEl.children] - .filter((el) => !el.classList.contains('group-header')) - .indexOf(slotEl) - : -1; - logger.debug({ slotEl, optionIndex }); - // ignore clicks on group options - if (optionIndex !== -1) { - selectIndex(optionIndex); - } - } - }} - on:keydown={e => { - logger.debug('keydown: calling given onKeyDown...'); - onKeyDown(e); - }} - on:keypress={e => { - logger.debug('keypress: calling given onKeyPress...'); - onKeyPress(e); - }} + role="listbox" + tabindex="-1" + aria-expanded={open ? 'true' : 'false'} + class={cls( + '_SelectListOptions options group p-1 focus:outline-none', + settingsClasses.options, + classes.root + )} + class:opacity-50={loading} + bind:this={menuOptionsEl} + on:click|stopPropagation={(e) => { + logger.debug('options container clicked'); + + if (e.target instanceof HTMLElement) { + // Find slot parent of click target option, fallback to `e.target` if slot is not overridden + // Use `.options > ` in case slot is nested (ex. GraphQLSelect with slot) + const slotEl = e.target.closest('.options > [slot=option]') ?? e.target; + // Find the index of the clicked on element (ignoring group headers) + const optionIndex = slotEl + ? [...menuOptionsEl.children] + .filter((el) => !el.classList.contains('group-header')) + .indexOf(slotEl) + : -1; + logger.debug({ slotEl, optionIndex }); + // ignore clicks on group options + if (optionIndex !== -1) { + selectIndex(optionIndex); + } + } + }} + on:keydown={(e) => { + logger.debug('keydown: calling given onKeyDown...'); + onKeyDown(e); + }} + on:keypress={(e) => { + logger.debug('keypress: calling given onKeyPress...'); + onKeyPress(e); + }} > - {#each filteredOptions ?? [] as option, index (optionValue(option))} - {@const previousOption = filteredOptions[index - 1]} - {#if option.group && option.group !== previousOption?.group} - <div - class={cls( - 'group-header text-xs leading-8 tracking-widest text-black/50 px-2', - theme.group, - classes.group - )} - > - {option.group} - </div> - {/if} + {#each filteredOptions ?? [] as option, index (optionValue(option))} + {@const previousOption = filteredOptions[index - 1]} + {#if option.group && option.group !== previousOption?.group} + <div + class={cls( + 'group-header text-xs leading-8 tracking-widest text-surface-content/50 px-2', + settingsClasses.group, + classes.group + )} + > + {option.group} + </div> + {/if} - <slot name="option" {option} {index}></slot> - {:else} - <slot name="empty" {loading} {searchText}></slot> - {/each} -</div> \ No newline at end of file + <slot name="option" {option} {index} /> + {:else} + <slot name="empty" {loading} {searchText} /> + {/each} +</div> diff --git a/packages/svelte-ux/src/lib/components/index.ts b/packages/svelte-ux/src/lib/components/index.ts index 2db586d8c..8d3c7ce2c 100644 --- a/packages/svelte-ux/src/lib/components/index.ts +++ b/packages/svelte-ux/src/lib/components/index.ts @@ -36,6 +36,7 @@ export { default as Icon } from './Icon.svelte'; export { default as InfiniteScroll } from './InfiniteScroll.svelte'; export { default as Input } from './Input.svelte'; export { default as Form } from './Form.svelte'; +export { default as Kbd } from './Kbd.svelte'; export { default as Lazy } from './Lazy.svelte'; export { default as ListItem } from './ListItem.svelte'; export { default as Menu } from './Menu.svelte'; @@ -81,6 +82,9 @@ export { default as TableOrderIcon } from './TableOrderIcon.svelte'; export { default as Tab } from './Tab.svelte'; export { default as Tabs } from './Tabs.svelte'; export { default as TextField } from './TextField.svelte'; +export { default as ThemeSelect } from './ThemeSelect.svelte'; +export { default as ThemeSwitch } from './ThemeSwitch.svelte'; +export { default as ThemeInit } from './ThemeInit.svelte'; export { default as Tilt } from './Tilt.svelte'; export { default as Toggle } from './Toggle.svelte'; export { default as ToggleButton } from './ToggleButton.svelte'; @@ -92,5 +96,5 @@ export { default as TreeList } from './TreeList.svelte'; export { default as TweenedValue } from './TweenedValue.svelte'; export { default as ViewportCenter } from './ViewportCenter.svelte'; export { default as YearList } from './YearList.svelte'; -export { settings, getFormatNumberOptions, getSettings } from './settings'; -export { getTheme, getComponentTheme } from './theme'; +export { settings, getSettings } from './settings'; +export { getClasses, getComponentClasses } from './theme'; diff --git a/packages/svelte-ux/src/lib/components/settings.ts b/packages/svelte-ux/src/lib/components/settings.ts index fd943e754..bf912f321 100644 --- a/packages/svelte-ux/src/lib/components/settings.ts +++ b/packages/svelte-ux/src/lib/components/settings.ts @@ -1,51 +1,116 @@ -import type { FormatNumberOptions, FormatNumberStyle } from '$lib/utils/number'; import { getContext, setContext } from 'svelte'; -import type { Theme } from './theme'; -import type { Prettify } from '$lib/types/typeHelpers'; - -type ExcludeNone<T> = T extends 'none' ? never : T; -export type Settings = { - formats?: { - numbers?: Prettify< - { - defaults?: FormatNumberOptions; - } & { - [key in ExcludeNone<FormatNumberStyle>]?: FormatNumberOptions; - } - >; +import type { ComponentClasses } from './theme'; +import { createThemeStore, type ThemeStore } from '$lib/stores/themeStore'; +import { + getAllKnownLocales, + localeStore, + type LocaleSettings, + type LocaleStore, + type LocaleSettingsInput, +} from '$lib/utils/locale'; +import { buildFormatters, type FormatFunctions } from '$lib/utils/format'; +import { writable, type Readable, type Writable, derived } from 'svelte/store'; + +export type SettingsInput = { + /** Force a specific locale setting. */ + forceLocale?: string; + /** Use this locale in case we don't have locale info for the user's current locale as returned from Intl. + * Defaults to `en` if not specified. */ + fallbackLocale?: string; + /** Format information for additional locales that are not built-in to svelte-ux. */ + localeFormats?: Record<string, LocaleSettingsInput>; + + classes?: ComponentClasses; + /** A list of the available themes */ + themes?: { + light?: string[]; + dark?: string[]; }; - theme?: Theme; + currentTheme?: ThemeStore; + + /** The existing locale store, if calling settings when there is already an existing `Settings` object */ + locale?: LocaleStore; + /** The existing locale store, if calling settings when there is already an existing `Settings` object */ + localeSettings?: Readable<LocaleSettings>; + /** The existing locale store, if calling settings when there is already an existing `Settings` object */ + format?: Readable<FormatFunctions>; }; +export interface Settings extends Omit<SettingsInput, 'formats' | 'dictionary'> { + /** The currently selected locale */ + locale: LocaleStore; + /** The settings for the currently selected locale */ + localeSettings: Readable<LocaleSettings>; + /** Formatting functions and information */ + format: Readable<FormatFunctions>; + currentTheme: ThemeStore; +} + const settingsKey = Symbol(); -export function settings(settings: Settings) { - setContext(settingsKey, settings); +function createLocaleStores(settings: SettingsInput) { + if (settings.locale && settings.localeSettings && settings.format) { + return { + locale: settings.locale, + localeSettings: settings.localeSettings, + format: settings.format, + }; + } + + let allLocales = getAllKnownLocales(settings.localeFormats); + + let locale = localeStore(settings.forceLocale, settings.fallbackLocale); + let localeSettings = derived(locale, ($locale) => { + let settings = allLocales[$locale]; + if (settings) { + return settings; + } + + return { + ...allLocales.en, + locale: $locale, + }; + }); + + return { + locale, + localeSettings, + format: derived(localeSettings, buildFormatters), + }; } -export function getSettings() { +export function settings(settings: SettingsInput): Settings { + let lightThemes = settings.themes?.light ?? ['light']; + let darkThemes = settings.themes?.dark ?? ['dark']; + + let currentTheme = + // In some cases, `settings` is called again from inside a component. Don't create a new theme store in this case. + settings.currentTheme ?? + createThemeStore({ + light: lightThemes, + dark: darkThemes, + }); + + let localeStores = createLocaleStores(settings); + + return setContext<Settings>(settingsKey, { + ...settings, + themes: { + light: lightThemes, + dark: darkThemes, + }, + currentTheme, + ...localeStores, + }); +} + +export function getSettings(): Settings { // in a try/catch to be able to test wo svelte components try { return getContext<Settings>(settingsKey) ?? {}; } catch (error) { - return {}; + return { + currentTheme: createThemeStore({ light: ['light'], dark: ['dark'] }), + }; } } - -export function getFormatNumberOptions(style?: FormatNumberStyle) { - let toRet = { - locales: 'en', - currency: 'USD', - fractionDigits: 2, - currencyDisplay: 'symbol', - }; - - const settings = getSettings(); - toRet = { ...toRet, ...(settings.formats?.numbers?.defaults ?? {}) }; - - if (style && style !== 'none') { - toRet = { ...toRet, ...(settings.formats?.numbers?.[style] ?? {}) }; - } - - return toRet; -} diff --git a/packages/svelte-ux/src/lib/components/theme.ts b/packages/svelte-ux/src/lib/components/theme.ts index aefa8e029..a05737cc7 100644 --- a/packages/svelte-ux/src/lib/components/theme.ts +++ b/packages/svelte-ux/src/lib/components/theme.ts @@ -10,16 +10,16 @@ type ClassesProp<T> = T extends { prototype: infer PR extends SvelteComponent } : never : never; -export type Theme = { +export type ComponentClasses = { [key in ComponentName]?: ClassesProp<(typeof Components)[key]> | string; }; -export function getTheme() { - return getSettings().theme ?? {}; +export function getClasses() { + return getSettings().classes ?? {}; } -export function getComponentTheme(name: ComponentName) { - const theme = getTheme()[name] ?? {}; +export function getComponentClasses(name: ComponentName) { + const theme = getClasses()[name] ?? {}; return typeof theme === 'string' ? { root: theme } : theme; } diff --git a/packages/svelte-ux/src/lib/index.ts b/packages/svelte-ux/src/lib/index.ts index 180dd4045..3e5b71788 100644 --- a/packages/svelte-ux/src/lib/index.ts +++ b/packages/svelte-ux/src/lib/index.ts @@ -2,4 +2,5 @@ export * from './actions'; export * from './components'; export * from './stores'; export * from './types'; +// TODO: Conflic Duration Component & Type export * from './utils'; diff --git a/packages/svelte-ux/src/lib/plugins/tailwind.cjs b/packages/svelte-ux/src/lib/plugins/tailwind.cjs index bcbfaae05..863523ad7 100644 --- a/packages/svelte-ux/src/lib/plugins/tailwind.cjs +++ b/packages/svelte-ux/src/lib/plugins/tailwind.cjs @@ -1,151 +1,85 @@ const plugin = require('tailwindcss/plugin'); -module.exports = plugin(function ({ addUtilities }) { - // Stack grid children - addUtilities({ - '.grid-stack': { - '& > *': { - 'grid-area': '1 / 1', +const { createThemeColors, injectThemes } = require('./tailwind/theme'); +const colorMix = require('./tailwind/colorMix'); +const elevation = require('./tailwind/elevation'); + +// TODO: Type options (convert to Typescript and use generic argument, or use jsdoc?) +module.exports = plugin.withOptions( + (options = {}) => { + const colorSpace = options?.colorSpace ?? 'hsl'; + + return function (api) { + const { addBase, addUtilities, config } = api; + + injectThemes(colorSpace, addBase, config); + + // colorMix(api); // Remove `bg-mix-*` / etc utils until needed (and better browser support) + + elevation(api); + + // Stack grid children + addUtilities({ + '.grid-stack': { + '& > *': { + 'grid-area': '1 / 1', + }, + }, + }); + + // Hide scrollbar + addUtilities({ + '.scrollbar-none': { + '-ms-overflow-style': 'none', + 'scrollbar-width': 'none', + '&::-webkit-scrollbar': { + display: 'none', + }, + }, + }); + }; + }, + (options) => { + const colorSpace = options?.colorSpace ?? 'hsl'; + + return { + darkMode: 'class', + theme: { + extend: { + colors: createThemeColors(colorSpace), + borderColor: (theme) => ({ + DEFAULT: theme('colors.surface-content/20%'), + }), + outlineColor: (theme) => ({ + DEFAULT: theme('colors.surface-content/20%'), + }), + ringOffsetColor: (theme) => ({ + DEFAULT: theme('colors.surface-100/100%'), + }), + typography: ({ theme }) => ({ + DEFAULT: { + css: { + '--tw-prose-body': theme('colors.surface-content'), + '--tw-prose-headings': theme('colors.surface-content'), + '--tw-prose-lead': theme('colors.surface-content'), + '--tw-prose-links': theme('colors.surface-content'), + '--tw-prose-bold': theme('colors.surface-content'), + '--tw-prose-counters': theme('colors.surface-content/30%'), + '--tw-prose-bullets': theme('colors.surface-content/30%'), + '--tw-prose-hr': theme('colors.surface-content/20%'), + '--tw-prose-quotes': theme('colors.surface-content'), + '--tw-prose-quote-borders': theme('colors.surface-content'), + '--tw-prose-captions': theme('colors.surface-content'), + '--tw-prose-code': theme('colors.surface-content'), + '--tw-prose-pre-code': theme('colors.surface-content'), + '--tw-prose-pre-bg': theme('colors.surface-content'), + '--tw-prose-th-borders': theme('colors.surface-300'), + '--tw-prose-td-borders': theme('colors.surface-300'), + }, + }, + }), + }, }, - }, - }); - - // Hide scrollbar - addUtilities({ - '.scrollbar-none': { - '-ms-overflow-style': 'none', - 'scrollbar-width': 'none', - '&::-webkit-scrollbar': { - display: 'none', - }, - }, - }); - - // Add `elevation-#` classes - addUtilities({ - '.elevation-0': { - 'box-shadow': - '0px 0px 0px 0px rgba(0,0,0,0.20), 0px 0px 0px 0px rgba(0,0,0,0.14), 0px 0px 0px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-1': { - 'box-shadow': - '0px 2px 1px -1px rgba(0,0,0,0.20), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-2': { - 'box-shadow': - '0px 3px 1px -2px rgba(0,0,0,0.20), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-3': { - 'box-shadow': - '0px 3px 3px -2px rgba(0,0,0,0.20), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-4': { - 'box-shadow': - '0px 2px 4px -1px rgba(0,0,0,0.20), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-5': { - 'box-shadow': - '0px 3px 5px -1px rgba(0,0,0,0.20), 0px 5px 8px 0px rgba(0,0,0,0.14), 0px 1px 14px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-6': { - 'box-shadow': - '0px 3px 5px -1px rgba(0,0,0,0.20), 0px 6px 10px 0px rgba(0,0,0,0.14), 0px 1px 18px 0px rgba(0,0,0,0.12)', - }, - - '.elevation-7': { - 'box-shadow': - '0px 4px 5px -2px rgba(0,0,0,0.20), 0px 7px 10px 1px rgba(0,0,0,0.14), 0px 2px 16px 1px rgba(0,0,0,0.12)', - }, - - '.elevation-8': { - 'box-shadow': - '0px 5px 5px -3px rgba(0,0,0,0.20), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12)', - }, - - '.elevation-9': { - 'box-shadow': - '0px 5px 6px -3px rgba(0,0,0,0.20), 0px 9px 12px 1px rgba(0,0,0,0.14), 0px 3px 16px 2px rgba(0,0,0,0.12)', - }, - - '.elevation-10': { - 'box-shadow': - '0px 6px 6px -3px rgba(0,0,0,0.20), 0px 10px 14px 1px rgba(0,0,0,0.14), 0px 4px 18px 3px rgba(0,0,0,0.12)', - }, - - '.elevation-11': { - 'box-shadow': - '0px 6px 7px -4px rgba(0,0,0,0.20), 0px 11px 15px 1px rgba(0,0,0,0.14), 0px 4px 20px 3px rgba(0,0,0,0.12)', - }, - - '.elevation-12': { - 'box-shadow': - '0px 7px 8px -4px rgba(0,0,0,0.20), 0px 12px 17px 2px rgba(0,0,0,0.14), 0px 5px 22px 4px rgba(0,0,0,0.12)', - }, - - '.elevation-13': { - 'box-shadow': - '0px 7px 8px -4px rgba(0,0,0,0.20), 0px 13px 19px 2px rgba(0,0,0,0.14), 0px 5px 24px 4px rgba(0,0,0,0.12)', - }, - - '.elevation-14': { - 'box-shadow': - '0px 7px 9px -4px rgba(0,0,0,0.20), 0px 14px 21px 2px rgba(0,0,0,0.14), 0px 5px 26px 4px rgba(0,0,0,0.12)', - }, - - '.elevation-15': { - 'box-shadow': - '0px 8px 9px -5px rgba(0,0,0,0.20), 0px 15px 22px 2px rgba(0,0,0,0.14), 0px 6px 28px 5px rgba(0,0,0,0.12)', - }, - - '.elevation-16': { - 'box-shadow': - '0px 8px 10px -5px rgba(0,0,0,0.20), 0px 16px 24px 2px rgba(0,0,0,0.14), 0px 6px 30px 5px rgba(0,0,0,0.12)', - }, - - '.elevation-17': { - 'box-shadow': - '0px 8px 11px -5px rgba(0,0,0,0.20), 0px 17px 26px 2px rgba(0,0,0,0.14), 0px 6px 32px 5px rgba(0,0,0,0.12)', - }, - - '.elevation-18': { - 'box-shadow': - '0px 9px 11px -5px rgba(0,0,0,0.20), 0px 18px 28px 2px rgba(0,0,0,0.14), 0px 7px 34px 6px rgba(0,0,0,0.12)', - }, - - '.elevation-19': { - 'box-shadow': - '0px 9px 12px -6px rgba(0,0,0,0.20), 0px 19px 29px 2px rgba(0,0,0,0.14), 0px 7px 36px 6px rgba(0,0,0,0.12)', - }, - - '.elevation-20': { - 'box-shadow': - '0px 10px 13px -6px rgba(0,0,0,0.20), 0px 20px 31px 3px rgba(0,0,0,0.14), 0px 8px 38px 7px rgba(0,0,0,0.12)', - }, - - '.elevation-21': { - 'box-shadow': - '0px 10px 13px -6px rgba(0,0,0,0.20), 0px 21px 33px 3px rgba(0,0,0,0.14), 0px 8px 40px 7px rgba(0,0,0,0.12)', - }, - - '.elevation-22': { - 'box-shadow': - '0px 10px 14px -6px rgba(0,0,0,0.20), 0px 22px 35px 3px rgba(0,0,0,0.14), 0px 8px 42px 7px rgba(0,0,0,0.12)', - }, - - '.elevation-23': { - 'box-shadow': - '0px 11px 14px -7px rgba(0,0,0,0.20), 0px 23px 36px 3px rgba(0,0,0,0.14), 0px 9px 44px 8px rgba(0,0,0,0.12)', - }, - - '.elevation-24': { - 'box-shadow': - '0px 11px 15px -7px rgba(0,0,0,0.20), 0px 24px 38px 3px rgba(0,0,0,0.14), 0px 9px 46px 8px rgba(0,0,0,0.12)', - }, - }); -}); + }; + } +); diff --git a/packages/svelte-ux/src/lib/plugins/tailwind/colorMix.cjs b/packages/svelte-ux/src/lib/plugins/tailwind/colorMix.cjs new file mode 100644 index 000000000..244d4d0d8 --- /dev/null +++ b/packages/svelte-ux/src/lib/plugins/tailwind/colorMix.cjs @@ -0,0 +1,38 @@ +module.exports = function ({ matchUtilities }) { + // color-mix (ex. `bg-mix-[indigo/80]`, or `bg-mix-[indigo/-40]`) + // https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix + // https://twitter.com/Saadeghi/status/1727954306140172295 + // https://twitter.com/crswll/status/1724459346489139675 + matchUtilities({ + 'text-mix': (value) => { + const [color, percent] = value.split('/'); + return { + color: `color-mix(in oklab,color-mix(in oklab,${color},${ + percent?.startsWith('-') ? 'black' : percent?.endsWith('%') ? 'transparent' : 'white' + } ${ + percent?.replace('-', '') + '%' + }),transparent calc(100% - 100% * var(--tw-text-opacity,1)))`, + }; + }, + 'bg-mix': (value) => { + const [color, percent] = value.split('/'); + return { + backgroundColor: `color-mix(in oklab,color-mix(in oklab,${color},${ + percent?.startsWith('-') ? 'black' : percent?.endsWith('%') ? 'transparent' : 'white' + } ${ + percent?.replace('-', '') + '%' + }),transparent calc(100% - 100% * var(--tw-bg-opacity,1)))`, + }; + }, + 'border-mix': (value) => { + const [color, percent] = value.split('/'); + return { + borderColor: `color-mix(in oklab,color-mix(in oklab,${color},${ + percent?.startsWith('-') ? 'black' : percent?.endsWith('%') ? 'transparent' : 'white' + } ${ + percent?.replace('-', '') + '%' + }),transparent calc(100% - 100% * var(--tw-border-opacity,1)))`, + }; + }, + }); +}; diff --git a/packages/svelte-ux/src/lib/plugins/tailwind/elevation.cjs b/packages/svelte-ux/src/lib/plugins/tailwind/elevation.cjs new file mode 100644 index 000000000..6e9a40fc3 --- /dev/null +++ b/packages/svelte-ux/src/lib/plugins/tailwind/elevation.cjs @@ -0,0 +1,129 @@ +module.exports = function ({ addUtilities }) { + addUtilities({ + // Add `elevation-#` classes + '.elevation-0': { + 'box-shadow': + '0px 0px 0px 0px rgba(0,0,0,0.20), 0px 0px 0px 0px rgba(0,0,0,0.14), 0px 0px 0px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-1': { + 'box-shadow': + '0px 2px 1px -1px rgba(0,0,0,0.20), 0px 1px 1px 0px rgba(0,0,0,0.14), 0px 1px 3px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-2': { + 'box-shadow': + '0px 3px 1px -2px rgba(0,0,0,0.20), 0px 2px 2px 0px rgba(0,0,0,0.14), 0px 1px 5px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-3': { + 'box-shadow': + '0px 3px 3px -2px rgba(0,0,0,0.20), 0px 3px 4px 0px rgba(0,0,0,0.14), 0px 1px 8px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-4': { + 'box-shadow': + '0px 2px 4px -1px rgba(0,0,0,0.20), 0px 4px 5px 0px rgba(0,0,0,0.14), 0px 1px 10px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-5': { + 'box-shadow': + '0px 3px 5px -1px rgba(0,0,0,0.20), 0px 5px 8px 0px rgba(0,0,0,0.14), 0px 1px 14px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-6': { + 'box-shadow': + '0px 3px 5px -1px rgba(0,0,0,0.20), 0px 6px 10px 0px rgba(0,0,0,0.14), 0px 1px 18px 0px rgba(0,0,0,0.12)', + }, + + '.elevation-7': { + 'box-shadow': + '0px 4px 5px -2px rgba(0,0,0,0.20), 0px 7px 10px 1px rgba(0,0,0,0.14), 0px 2px 16px 1px rgba(0,0,0,0.12)', + }, + + '.elevation-8': { + 'box-shadow': + '0px 5px 5px -3px rgba(0,0,0,0.20), 0px 8px 10px 1px rgba(0,0,0,0.14), 0px 3px 14px 2px rgba(0,0,0,0.12)', + }, + + '.elevation-9': { + 'box-shadow': + '0px 5px 6px -3px rgba(0,0,0,0.20), 0px 9px 12px 1px rgba(0,0,0,0.14), 0px 3px 16px 2px rgba(0,0,0,0.12)', + }, + + '.elevation-10': { + 'box-shadow': + '0px 6px 6px -3px rgba(0,0,0,0.20), 0px 10px 14px 1px rgba(0,0,0,0.14), 0px 4px 18px 3px rgba(0,0,0,0.12)', + }, + + '.elevation-11': { + 'box-shadow': + '0px 6px 7px -4px rgba(0,0,0,0.20), 0px 11px 15px 1px rgba(0,0,0,0.14), 0px 4px 20px 3px rgba(0,0,0,0.12)', + }, + + '.elevation-12': { + 'box-shadow': + '0px 7px 8px -4px rgba(0,0,0,0.20), 0px 12px 17px 2px rgba(0,0,0,0.14), 0px 5px 22px 4px rgba(0,0,0,0.12)', + }, + + '.elevation-13': { + 'box-shadow': + '0px 7px 8px -4px rgba(0,0,0,0.20), 0px 13px 19px 2px rgba(0,0,0,0.14), 0px 5px 24px 4px rgba(0,0,0,0.12)', + }, + + '.elevation-14': { + 'box-shadow': + '0px 7px 9px -4px rgba(0,0,0,0.20), 0px 14px 21px 2px rgba(0,0,0,0.14), 0px 5px 26px 4px rgba(0,0,0,0.12)', + }, + + '.elevation-15': { + 'box-shadow': + '0px 8px 9px -5px rgba(0,0,0,0.20), 0px 15px 22px 2px rgba(0,0,0,0.14), 0px 6px 28px 5px rgba(0,0,0,0.12)', + }, + + '.elevation-16': { + 'box-shadow': + '0px 8px 10px -5px rgba(0,0,0,0.20), 0px 16px 24px 2px rgba(0,0,0,0.14), 0px 6px 30px 5px rgba(0,0,0,0.12)', + }, + + '.elevation-17': { + 'box-shadow': + '0px 8px 11px -5px rgba(0,0,0,0.20), 0px 17px 26px 2px rgba(0,0,0,0.14), 0px 6px 32px 5px rgba(0,0,0,0.12)', + }, + + '.elevation-18': { + 'box-shadow': + '0px 9px 11px -5px rgba(0,0,0,0.20), 0px 18px 28px 2px rgba(0,0,0,0.14), 0px 7px 34px 6px rgba(0,0,0,0.12)', + }, + + '.elevation-19': { + 'box-shadow': + '0px 9px 12px -6px rgba(0,0,0,0.20), 0px 19px 29px 2px rgba(0,0,0,0.14), 0px 7px 36px 6px rgba(0,0,0,0.12)', + }, + + '.elevation-20': { + 'box-shadow': + '0px 10px 13px -6px rgba(0,0,0,0.20), 0px 20px 31px 3px rgba(0,0,0,0.14), 0px 8px 38px 7px rgba(0,0,0,0.12)', + }, + + '.elevation-21': { + 'box-shadow': + '0px 10px 13px -6px rgba(0,0,0,0.20), 0px 21px 33px 3px rgba(0,0,0,0.14), 0px 8px 40px 7px rgba(0,0,0,0.12)', + }, + + '.elevation-22': { + 'box-shadow': + '0px 10px 14px -6px rgba(0,0,0,0.20), 0px 22px 35px 3px rgba(0,0,0,0.14), 0px 8px 42px 7px rgba(0,0,0,0.12)', + }, + + '.elevation-23': { + 'box-shadow': + '0px 11px 14px -7px rgba(0,0,0,0.20), 0px 23px 36px 3px rgba(0,0,0,0.14), 0px 9px 44px 8px rgba(0,0,0,0.12)', + }, + + '.elevation-24': { + 'box-shadow': + '0px 11px 15px -7px rgba(0,0,0,0.20), 0px 24px 38px 3px rgba(0,0,0,0.14), 0px 9px 46px 8px rgba(0,0,0,0.12)', + }, + }); +}; diff --git a/packages/svelte-ux/src/lib/plugins/tailwind/theme.cjs b/packages/svelte-ux/src/lib/plugins/tailwind/theme.cjs new file mode 100644 index 000000000..de9ab225f --- /dev/null +++ b/packages/svelte-ux/src/lib/plugins/tailwind/theme.cjs @@ -0,0 +1,38 @@ +const { createThemeColors, processThemeColors } = require('../../styles/theme'); + +/** + * Inject all Tailwind config themes (`{ ux: { themes: [] }}`) into base CSS + * @param {'rgb' | 'hsl' | 'oklch'} colorSpace + */ +function injectThemes(colorSpace, addBase, config) { + const themes = config('ux.themes'); + const themeRoot = config('ux.themeRoot') ?? ':root'; + + const cssThemes = {}; + let rootThemeName = null; + Object.entries(themes).map(([themeName, themeColors], index) => { + if (index === 0) { + // Root / default theme + cssThemes[themeRoot] = processThemeColors(themeColors, colorSpace); + rootThemeName = themeName; + } else if (index === 1) { + // Dark theme + cssThemes['@media (prefers-color-scheme: dark)'] = { + [themeRoot]: processThemeColors(themeColors, colorSpace), + }; + + // Also register first and second them by name AFTER @media for precedence + cssThemes[`[data-theme=${rootThemeName}]`] = processThemeColors( + themes[rootThemeName], + colorSpace + ); + cssThemes[`[data-theme=${themeName}]`] = processThemeColors(themeColors, colorSpace); + } else { + cssThemes[`[data-theme=${themeName}]`] = processThemeColors(themeColors, colorSpace); + } + }); + + addBase(cssThemes); +} + +module.exports = { createThemeColors, injectThemes }; diff --git a/packages/svelte-ux/src/lib/stores/themeStore.ts b/packages/svelte-ux/src/lib/stores/themeStore.ts new file mode 100644 index 000000000..2c40f94a3 --- /dev/null +++ b/packages/svelte-ux/src/lib/stores/themeStore.ts @@ -0,0 +1,93 @@ +import { writable, type Readable } from 'svelte/store'; +import { browser } from '../utils/env'; + +/** Information about the currently chosen theme. */ +export class CurrentTheme { + /** The currently selected theme. If using the "system" theme this will be null. */ + theme: string | null; + /** Whether the current theme is a light or dark theme */ + dark: boolean; + + constructor(theme: string | null, dark: boolean) { + this.theme = theme; + this.dark = dark; + } + + /** The theme in use, either the selected theme or the theme chosen based on the "system" setting. */ + get resolvedTheme() { + if (this.theme) { + return this.theme; + } else { + return this.dark ? 'dark' : 'light'; + } + } +} + +export interface ThemeStore extends Readable<CurrentTheme> { + setTheme: (themeName: string) => void; +} + +export interface ThemeStoreOptions { + light: string[]; + dark: string[]; +} + +export function createThemeStore(options: ThemeStoreOptions): ThemeStore { + let store = writable<CurrentTheme>(new CurrentTheme(null, false)); + + if (!browser) { + // Stub out most of the store when running SSR. + return { + subscribe: store.subscribe, + setTheme: (themeName: string) => { + store.set(new CurrentTheme(themeName, options.dark.includes(themeName))); + }, + }; + } + + let darkMatcher = window.matchMedia('(prefers-color-scheme: dark)'); + + function resolveSystemTheme({ matches }: { matches: boolean }) { + if (matches) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + + store.set(new CurrentTheme(null, matches)); + } + + function setTheme(themeName: string) { + if (themeName === 'system') { + // Remove setting + localStorage.removeItem('theme'); + delete document.documentElement.dataset.theme; + + resolveSystemTheme(darkMatcher); + darkMatcher.addEventListener('change', resolveSystemTheme); + } else { + darkMatcher.removeEventListener('change', resolveSystemTheme); + + // Save theme to local storage, set `<html data-theme="">`, and set `<html class="dark">` if dark mode + localStorage.theme = themeName; + document.documentElement.dataset.theme = themeName; + + let dark = options.dark.includes(themeName); + if (dark) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + + store.set(new CurrentTheme(themeName, dark)); + } + } + + let savedTheme = localStorage.getItem('theme') || 'system'; + setTheme(savedTheme); + + return { + subscribe: store.subscribe, + setTheme, + }; +} diff --git a/packages/svelte-ux/src/lib/styles/daisy.ts b/packages/svelte-ux/src/lib/styles/daisy.ts new file mode 100644 index 000000000..b27741f80 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/daisy.ts @@ -0,0 +1,71 @@ +import daisyThemes from 'daisyui/src/theming/themes'; +// import { themeOrder } from 'daisyui/src/theming/themeDefaults'; // breaks build +import { sortFunc } from '../utils/sort'; + +const themeNames = [ + 'light', + 'dark', + 'cupcake', + 'bumblebee', + 'emerald', + 'corporate', + 'synthwave', + 'retro', + 'cyberpunk', + 'valentine', + 'halloween', + 'garden', + 'forest', + 'aqua', + 'lofi', + 'pastel', + 'fantasy', + 'wireframe', + 'black', + 'luxury', + 'dracula', + 'cmyk', + 'autumn', + 'business', + 'acid', + 'lemonade', + 'night', + 'coffee', + 'winter', + 'dim', + 'nord', + 'sunset', +]; + +const daisyColorMap = { + 'base-100': 'surface-100', + 'base-200': 'surface-200', + 'base-300': 'surface-300', + 'base-content': 'surface-content', + error: 'danger', + 'error-content': 'danger-content', +}; + +/** + * Map Daisy UI color names to Svelte UX names, and sort themes + */ +function mapColorsName(themes: typeof daisyThemes, colorMap: typeof daisyColorMap) { + return Object.fromEntries( + Object.entries(themes) + .map(([themeName, colors]) => { + return [ + themeName, + Object.fromEntries( + Object.entries(colors).map(([key, value]) => { + return [colorMap[key] ?? key, value]; + }) + ), + ]; + }) + .sort(sortFunc(([themeName]) => themeNames.indexOf(themeName))) + ); +} + +const themes = mapColorsName(daisyThemes, daisyColorMap); + +export { themes }; diff --git a/packages/svelte-ux/src/lib/styles/skeleton.ts b/packages/svelte-ux/src/lib/styles/skeleton.ts new file mode 100644 index 000000000..c7c6da5d8 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton.ts @@ -0,0 +1,110 @@ +/* + * Use local copy of Skeleton themes/getThemeProperties() due to: + * - Skeleton themse only available in `@skeletonlabs/tw-plugin` package, which + * - Does not publish the `src` directly + * - Requires the Node.js runtime (fs, path, tty, url, util) + * - Cloudflare not support Node.js runtime (unless using `require('node:...')) + * - https://developers.cloudflare.com/workers/runtime-apis/nodejs/ + * - Builds work on Vercel (since they support the Node.js runtime) + * - See: https://github.com/techniq/svelte-ux/pull/192 + */ +// +// https://github.com/skeletonlabs/skeleton/blob/dev/packages/plugin/src/tailwind/themes/index.ts#L17-L19 +// import { getThemeProperties } from '@skeletonlabs/tw-plugin'; +import { getThemeProperties } from './skeleton/index'; + +const themeNames = [ + 'skeleton', + 'wintry', + 'modern', + 'rocket', + 'seafoam', + 'vintage', + 'sahara', + 'hamlindigo', + 'gold-nouveau', +] as const; + +// Map Skeleton to Svelte UX theme colors +const skeletonColorMap = { + // Semantic + primary: 'primary', + secondary: 'secondary', + tertiary: 'accent', + // '': 'neutral', + // State + success: 'success', + warning: 'warning', + error: 'danger', + // Surface + surface: 'surface', +}; + +function processTheme(themeName: (typeof themeNames)[number], scheme: 'light' | 'dark') { + const properties = getThemeProperties(themeName); + + let mappedThemeProperties = Object.entries(properties) + .map(([key, value]) => { + if (key.startsWith('--color')) { + // `--color-primary-500` => `primary-500` + // `--color-primary-500` => `primary` + const matches = key.match(/--color-(\w*)-([0-9]{3})/); + const skeletonColorName = matches?.[1]; + const skeletonColorShade = matches?.[2]; + const themeColorName = skeletonColorMap[skeletonColorName]; + if (themeColorName) { + return [`${themeColorName}-${skeletonColorShade}`, `rgb(${value})`]; + } + } else if (key.startsWith('--on-')) { + // `--on-primary` => `primary-content` + const matches = key.match(/--on-(\w*)/); + const skeletonColorName = matches?.[1]; + const themeColorName = skeletonColorMap[skeletonColorName]; + if (themeColorName) { + return [`${themeColorName}-content`, `rgb(${value})`]; + } + } else { + // consider mapping additional properties + // '--theme-font-family-base': 'system-ui', + // '--theme-font-family-heading': 'system-ui', + // '--theme-font-color-base': '0 0 0', + // '--theme-font-color-dark': '255 255 255', + // '--theme-rounded-base': '9999px', + // '--theme-rounded-container': '8px', + // '--theme-border-base': '1px', + } + }) + .filter((d) => d); + + mappedThemeProperties = + scheme === 'light' + ? [ + ...mappedThemeProperties, + ['color-scheme', 'light'], + ['surface-100', `rgb(${properties['--color-surface-50']})`], + ['surface-200', `rgb(${properties['--color-surface-100']})`], + ['surface-300', `rgb(${properties['--color-surface-200']})`], + ['surface-content', `rgb(0 0 0)`], + ] + : [ + ...mappedThemeProperties, + ['color-scheme', 'dark'], + ['surface-100', `rgb(${properties['--color-surface-700']})`], + ['surface-200', `rgb(${properties['--color-surface-800']})`], + ['surface-300', `rgb(${properties['--color-surface-900']})`], + ['surface-content', `rgb(255 255 255)`], + ]; + + return [ + themeName === 'skeleton' ? scheme : scheme === 'dark' ? themeName + '-dark' : themeName, + Object.fromEntries(mappedThemeProperties), + ]; +} + +const themes = Object.fromEntries( + themeNames.flatMap((themeName) => { + return [processTheme(themeName, 'light'), processTheme(themeName, 'dark')]; + }) +); + +export { themes }; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/crimson.ts b/packages/svelte-ux/src/lib/styles/skeleton/crimson.ts new file mode 100644 index 000000000..411459640 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/crimson.ts @@ -0,0 +1,96 @@ +import type { PresetTheme } from './index.js'; + +const crimson = { + name: 'crimson', + properties: { + '--theme-font-family-base': + "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n\t\t'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + '--theme-font-family-heading': 'system-ui', + '--theme-font-color-base': 'var(--color-surface-900)', + '--theme-font-color-dark': 'var(--color-surface-50)', + '--theme-rounded-base': '24px', + '--theme-rounded-container': '24px', + '--theme-border-base': '1px', + '--on-primary': '255 255 255', + '--on-secondary': '255 255 255', + '--on-tertiary': '0 0 0', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '0 0 0', + '--on-surface': '255 255 255', + '--color-primary-50': '249 220 226', + '--color-primary-100': '246 208 216', + '--color-primary-200': '244 197 206', + '--color-primary-300': '238 162 177', + '--color-primary-400': '225 92 119', + '--color-primary-500': '212 22 60', + '--color-primary-600': '191 20 54', + '--color-primary-700': '159 17 45', + '--color-primary-800': '127 13 36', + '--color-primary-900': '104 11 29', + '--color-secondary-50': '227 237 243', + '--color-secondary-100': '218 231 239', + '--color-secondary-200': '209 225 235', + '--color-secondary-300': '181 206 223', + '--color-secondary-400': '126 170 199', + '--color-secondary-500': '70 133 175', + '--color-secondary-600': '63 120 158', + '--color-secondary-700': '53 100 131', + '--color-secondary-800': '42 80 105', + '--color-secondary-900': '34 65 86', + '--color-tertiary-50': '246 244 244', + '--color-tertiary-100': '242 240 240', + '--color-tertiary-200': '239 237 236', + '--color-tertiary-300': '230 226 225', + '--color-tertiary-400': '211 204 203', + '--color-tertiary-500': '192 182 180', + '--color-tertiary-600': '173 164 162', + '--color-tertiary-700': '144 137 135', + '--color-tertiary-800': '115 109 108', + '--color-tertiary-900': '94 89 88', + '--color-success-50': '246 250 239', + '--color-success-100': '243 248 234', + '--color-success-200': '240 247 229', + '--color-success-300': '230 241 213', + '--color-success-400': '212 231 182', + '--color-success-500': '193 221 151', + '--color-success-600': '174 199 136', + '--color-success-700': '145 166 113', + '--color-success-800': '116 133 91', + '--color-success-900': '95 108 74', + '--color-warning-50': '251 246 231', + '--color-warning-100': '250 243 223', + '--color-warning-200': '248 240 215', + '--color-warning-300': '244 231 191', + '--color-warning-400': '236 212 142', + '--color-warning-500': '228 194 94', + '--color-warning-600': '205 175 85', + '--color-warning-700': '171 146 71', + '--color-warning-800': '137 116 56', + '--color-warning-900': '112 95 46', + '--color-error-50': '248 236 236', + '--color-error-100': '246 229 230', + '--color-error-200': '244 223 224', + '--color-error-300': '237 204 205', + '--color-error-400': '224 165 167', + '--color-error-500': '210 127 129', + '--color-error-600': '189 114 116', + '--color-error-700': '158 95 97', + '--color-error-800': '126 76 77', + '--color-error-900': '103 62 63', + '--color-surface-50': '223 224 226', + '--color-surface-100': '213 213 217', + '--color-surface-200': '202 203 207', + '--color-surface-300': '170 171 179', + '--color-surface-400': '107 109 121', + '--color-surface-500': '43 46 64', + '--color-surface-600': '39 41 58', + '--color-surface-700': '32 35 48', + '--color-surface-800': '26 28 38', + '--color-surface-900': '21 23 31', + }, + properties_dark: {}, + enhancements: {}, +} satisfies PresetTheme; + +export default crimson; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/gold-nouveau.ts b/packages/svelte-ux/src/lib/styles/skeleton/gold-nouveau.ts new file mode 100644 index 000000000..42ac99259 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/gold-nouveau.ts @@ -0,0 +1,118 @@ +import type { PresetTheme } from './index.js'; + +const goldNouveau = { + name: 'gold-nouveau', + properties: { + '--theme-font-family-base': 'system-ui, sans-serif', + '--theme-font-family-heading': "'Quicksand', sans-serif", + '--theme-font-color-base': 'var(--color-surface-900)', + '--theme-font-color-dark': 'var(--color-surface-50)', + '--theme-rounded-base': '4px', + '--theme-rounded-container': '4px', + '--theme-border-base': '1px', + '--on-primary': '255 255 255', + '--on-secondary': '255 255 255', + '--on-tertiary': '255 255 255', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '250 248 252', + '--color-primary-100': '242 238 247', + '--color-primary-200': '229 220 239', + '--color-primary-300': '209 192 226', + '--color-primary-400': '162 129 197', + '--color-primary-500': '116 74 161', + '--color-primary-600': '83 53 115', + '--color-primary-700': '60 39 84', + '--color-primary-800': '35 22 49', + '--color-primary-900': '18 11 24', + '--color-secondary-50': '218 234 251', + '--color-secondary-100': '205 227 250', + '--color-secondary-200': '193 220 249', + '--color-secondary-300': '155 199 245', + '--color-secondary-400': '81 156 237', + '--color-secondary-500': '6 114 229', + '--color-secondary-600': '5 103 206', + '--color-secondary-700': '5 86 172', + '--color-secondary-800': '4 68 137', + '--color-secondary-900': '3 56 112', + '--color-tertiary-50': '236 235 250', + '--color-tertiary-100': '229 228 248', + '--color-tertiary-200': '223 221 247', + '--color-tertiary-300': '204 201 241', + '--color-tertiary-400': '165 161 231', + '--color-tertiary-500': '127 120 221', + '--color-tertiary-600': '114 108 199', + '--color-tertiary-700': '95 90 166', + '--color-tertiary-800': '76 72 133', + '--color-tertiary-900': '62 59 108', + '--color-success-50': '234 246 237', + '--color-success-100': '227 243 231', + '--color-success-200': '220 241 225', + '--color-success-300': '199 232 206', + '--color-success-400': '156 214 170', + '--color-success-500': '114 197 133', + '--color-success-600': '103 177 120', + '--color-success-700': '86 148 100', + '--color-success-800': '68 118 80', + '--color-success-900': '56 97 65', + '--color-warning-50': '251 236 218', + '--color-warning-100': '250 229 206', + '--color-warning-200': '249 223 193', + '--color-warning-300': '245 204 156', + '--color-warning-400': '238 165 82', + '--color-warning-500': '231 127 8', + '--color-warning-600': '208 114 7', + '--color-warning-700': '173 95 6', + '--color-warning-800': '139 76 5', + '--color-warning-900': '113 62 4', + '--color-error-50': '238 219 222', + '--color-error-100': '233 207 211', + '--color-error-200': '227 195 200', + '--color-error-300': '210 159 167', + '--color-error-400': '177 87 100', + '--color-error-500': '143 15 34', + '--color-error-600': '129 14 31', + '--color-error-700': '107 11 26', + '--color-error-800': '86 9 20', + '--color-error-900': '70 7 17', + '--color-surface-50': '250 248 252', + '--color-surface-100': '242 238 247', + '--color-surface-200': '229 220 239', + '--color-surface-300': '209 192 226', + '--color-surface-400': '162 129 197', + '--color-surface-500': '116 74 161', + '--color-surface-600': '83 53 115', + '--color-surface-700': '60 39 84', + '--color-surface-800': '35 22 49', + '--color-surface-900': '18 11 24', + }, + properties_dark: { + '--on-primary': '0 0 0', + '--color-primary-50': '251 247 224', + '--color-primary-100': '250 244 214', + '--color-primary-200': '249 241 204', + '--color-primary-300': '245 233 173', + '--color-primary-400': '238 217 112', + '--color-primary-500': '230 200 51', + '--color-primary-600': '207 180 46', + '--color-primary-700': '173 150 38', + '--color-primary-800': '138 120 31', + '--color-primary-900': '113 98 25', + }, + enhancements: { + "[data-theme='gold-nouveau'] h1,\n[data-theme='gold-nouveau'] h2,\n[data-theme='gold-nouveau'] h3,\n[data-theme='gold-nouveau'] h4,\n[data-theme='gold-nouveau'] h5,\n[data-theme='gold-nouveau'] h6": + { fontWeight: 'bold' }, + "[data-theme='gold-nouveau']": { + backgroundImage: + 'radial-gradient(at 0% 100%, rgba(var(--color-secondary-500) / 0.33) 0px, transparent 50%),\n\t\tradial-gradient(at 98% 100%, rgba(var(--color-error-500) / 0.33) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default goldNouveau; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/hamlindigo.ts b/packages/svelte-ux/src/lib/styles/skeleton/hamlindigo.ts new file mode 100644 index 000000000..6272a6cad --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/hamlindigo.ts @@ -0,0 +1,105 @@ +import type { PresetTheme } from './index.js'; + +const hamlindigo = { + name: 'hamlindigo', + properties: { + '--theme-font-family-base': + "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n\t\t'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + '--theme-font-family-heading': 'serif', + '--theme-font-color-base': '0 0 0', + '--theme-font-color-dark': '255 255 255', + '--theme-rounded-base': '2px', + '--theme-rounded-container': '2px', + '--theme-border-base': '2px', + '--on-primary': '0 0 0', + '--on-secondary': '255 255 255', + '--on-tertiary': '255 255 255', + '--on-success': '255 255 255', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '242 245 253', + '--color-primary-100': '238 242 252', + '--color-primary-200': '233 239 252', + '--color-primary-300': '220 229 249', + '--color-primary-400': '194 210 245', + '--color-primary-500': '168 190 241', + '--color-primary-600': '151 171 217', + '--color-primary-700': '126 143 181', + '--color-primary-800': '101 114 145', + '--color-primary-900': '82 93 118', + '--color-secondary-50': '241 238 230', + '--color-secondary-100': '237 232 222', + '--color-secondary-200': '232 227 214', + '--color-secondary-300': '219 210 189', + '--color-secondary-400': '191 176 140', + '--color-secondary-500': '164 142 91', + '--color-secondary-600': '148 128 82', + '--color-secondary-700': '123 107 68', + '--color-secondary-800': '98 85 55', + '--color-secondary-900': '80 70 45', + '--color-tertiary-50': '231 239 241', + '--color-tertiary-100': '223 234 237', + '--color-tertiary-200': '216 229 232', + '--color-tertiary-300': '192 213 218', + '--color-tertiary-400': '144 182 191', + '--color-tertiary-500': '97 151 163', + '--color-tertiary-600': '87 136 147', + '--color-tertiary-700': '73 113 122', + '--color-tertiary-800': '58 91 98', + '--color-tertiary-900': '48 74 80', + '--color-success-50': '227 239 236', + '--color-success-100': '218 234 229', + '--color-success-200': '209 228 223', + '--color-success-300': '181 212 203', + '--color-success-400': '126 180 164', + '--color-success-500': '71 148 125', + '--color-success-600': '64 133 113', + '--color-success-700': '53 111 94', + '--color-success-800': '43 89 75', + '--color-success-900': '35 73 61', + '--color-warning-50': '249 242 226', + '--color-warning-100': '248 238 216', + '--color-warning-200': '246 234 207', + '--color-warning-300': '240 221 178', + '--color-warning-400': '229 195 120', + '--color-warning-500': '218 169 62', + '--color-warning-600': '196 152 56', + '--color-warning-700': '164 127 47', + '--color-warning-800': '131 101 37', + '--color-warning-900': '107 83 30', + '--color-error-50': '241 231 234', + '--color-error-100': '236 223 227', + '--color-error-200': '232 216 221', + '--color-error-300': '218 192 200', + '--color-error-400': '190 144 158', + '--color-error-500': '162 97 117', + '--color-error-600': '146 87 105', + '--color-error-700': '122 73 88', + '--color-error-800': '97 58 70', + '--color-error-900': '79 48 57', + '--color-surface-50': '232 234 241', + '--color-surface-100': '224 228 237', + '--color-surface-200': '216 221 232', + '--color-surface-300': '193 200 218', + '--color-surface-400': '146 159 191', + '--color-surface-500': '99 118 163', + '--color-surface-600': '89 106 147', + '--color-surface-700': '74 89 122', + '--color-surface-800': '59 71 98', + '--color-surface-900': '49 58 80', + }, + properties_dark: {}, + enhancements: { + "[data-theme='hamlindigo']": { + backgroundImage: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cg fill='%23e0e4ed' fill-opacity='0.5'%3E%3Cpath fill-rule='evenodd' d='M0 0h4v4H0V0zm4 4h4v4H4V4z'/%3E%3C/g%3E%3C/svg%3E\")", + }, + ".dark [data-theme='hamlindigo']": { + backgroundImage: + "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cg fill='%233b4762' fill-opacity='0.2'%3E%3Cpath fill-rule='evenodd' d='M0 0h4v4H0V0zm4 4h4v4H4V4z'/%3E%3C/g%3E%3C/svg%3E\")", + }, + }, +} satisfies PresetTheme; + +export default hamlindigo; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/index.ts b/packages/svelte-ux/src/lib/styles/skeleton/index.ts new file mode 100644 index 000000000..81a1f9f4b --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/index.ts @@ -0,0 +1,143 @@ +import crimson from './crimson'; +import goldNouveau from './gold-nouveau'; +import hamlindigo from './hamlindigo'; +import modern from './modern'; +import rocket from './rocket'; +import sahara from './sahara'; +import seafoam from './seafoam'; +import skeleton from './skeleton'; +import vintage from './vintage'; +import wintry from './wintry'; +import type { CSSRuleObject } from 'tailwindcss/types/config.js'; + +export const themes = { + crimson, + 'gold-nouveau': goldNouveau, + hamlindigo, + modern, + rocket, + sahara, + seafoam, + skeleton, + vintage, + wintry, +}; + +export type PresetThemeName = ObjectKeys<typeof themes>; + +export function getThemeProperties(themeName: PresetThemeName) { + return themes[themeName].properties; +} + +export type ObjectValues<T> = T[keyof T]; +export type ObjectKeys<T> = keyof T; + +/* Allows for arbitrary properties to be defined */ +type ArbitraryProps = Record<string, string>; + +export type BaseTheme = { + name: string; + properties: ThemeProperties & ArbitraryProps; + properties_dark: Partial<ThemeProperties & ArbitraryProps>; +}; + +export type PresetTheme = BaseTheme & { + enhancements: CSSRuleObject; +}; + +export type ThemeProperties = { + /* =~= Theme Properties =~= */ + '--theme-font-family-base': string; + '--theme-font-family-heading': string; + '--theme-font-color-base': string; + '--theme-font-color-dark': string; + '--theme-rounded-base': string; + '--theme-rounded-container': string; + '--theme-border-base': string; + /* =~= Theme On-X Colors =~= */ + '--on-primary': string; + '--on-secondary': string; + '--on-tertiary': string; + '--on-success': string; + '--on-warning': string; + '--on-error': string; + '--on-surface': string; + /* =~= Theme Colors =~= */ + /* primary */ + '--color-primary-50': string; + '--color-primary-100': string; + '--color-primary-200': string; + '--color-primary-300': string; + '--color-primary-400': string; + '--color-primary-500': string; + '--color-primary-600': string; + '--color-primary-700': string; + '--color-primary-800': string; + '--color-primary-900': string; + /* secondary */ + '--color-secondary-50': string; + '--color-secondary-100': string; + '--color-secondary-200': string; + '--color-secondary-300': string; + '--color-secondary-400': string; + '--color-secondary-500': string; + '--color-secondary-600': string; + '--color-secondary-700': string; + '--color-secondary-800': string; + '--color-secondary-900': string; + /* tertiary */ + '--color-tertiary-50': string; + '--color-tertiary-100': string; + '--color-tertiary-200': string; + '--color-tertiary-300': string; + '--color-tertiary-400': string; + '--color-tertiary-500': string; + '--color-tertiary-600': string; + '--color-tertiary-700': string; + '--color-tertiary-800': string; + '--color-tertiary-900': string; + /* success */ + '--color-success-50': string; + '--color-success-100': string; + '--color-success-200': string; + '--color-success-300': string; + '--color-success-400': string; + '--color-success-500': string; + '--color-success-600': string; + '--color-success-700': string; + '--color-success-800': string; + '--color-success-900': string; + /* warning */ + '--color-warning-50': string; + '--color-warning-100': string; + '--color-warning-200': string; + '--color-warning-300': string; + '--color-warning-400': string; + '--color-warning-500': string; + '--color-warning-600': string; + '--color-warning-700': string; + '--color-warning-800': string; + '--color-warning-900': string; + /* error */ + '--color-error-50': string; + '--color-error-100': string; + '--color-error-200': string; + '--color-error-300': string; + '--color-error-400': string; + '--color-error-500': string; + '--color-error-600': string; + '--color-error-700': string; + '--color-error-800': string; + '--color-error-900': string; + /* surface */ + '--color-surface-50': string; + '--color-surface-100': string; + '--color-surface-200': string; + '--color-surface-300': string; + '--color-surface-400': string; + '--color-surface-500': string; + '--color-surface-600': string; + '--color-surface-700': string; + '--color-surface-800': string; + '--color-surface-900': string; +}; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/modern.ts b/packages/svelte-ux/src/lib/styles/skeleton/modern.ts new file mode 100644 index 000000000..71a4448a0 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/modern.ts @@ -0,0 +1,114 @@ +import type { PresetTheme } from './index.js'; + +const modern = { + name: 'modern', + properties: { + '--theme-font-family-base': "'Quicksand', sans-serif", + '--theme-font-family-heading': "'Quicksand', sans-serif", + '--theme-font-color-base': 'var(--color-surface-900)', + '--theme-font-color-dark': 'var(--color-tertiary-50)', + '--theme-rounded-base': '9999px', + '--theme-rounded-container': '24px', + '--theme-border-base': '3px', + '--on-primary': '255 255 255', + '--on-secondary': '0 0 0', + '--on-tertiary': '0 0 0', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '252 228 240', + '--color-primary-100': '251 218 235', + '--color-primary-200': '250 209 230', + '--color-primary-300': '247 182 214', + '--color-primary-400': '242 127 184', + '--color-primary-500': '236 72 153', + '--color-primary-600': '212 65 138', + '--color-primary-700': '177 54 115', + '--color-primary-800': '142 43 92', + '--color-primary-900': '116 35 75', + '--color-secondary-50': '218 244 249', + '--color-secondary-100': '205 240 246', + '--color-secondary-200': '193 237 244', + '--color-secondary-300': '155 226 238', + '--color-secondary-400': '81 204 225', + '--color-secondary-500': '6 182 212', + '--color-secondary-600': '5 164 191', + '--color-secondary-700': '5 137 159', + '--color-secondary-800': '4 109 127', + '--color-secondary-900': '3 89 104', + '--color-tertiary-50': '220 244 242', + '--color-tertiary-100': '208 241 237', + '--color-tertiary-200': '196 237 233', + '--color-tertiary-300': '161 227 219', + '--color-tertiary-400': '91 205 193', + '--color-tertiary-500': '20 184 166', + '--color-tertiary-600': '18 166 149', + '--color-tertiary-700': '15 138 125', + '--color-tertiary-800': '12 110 100', + '--color-tertiary-900': '10 90 81', + '--color-success-50': '237 247 220', + '--color-success-100': '230 245 208', + '--color-success-200': '224 242 197', + '--color-success-300': '206 235 162', + '--color-success-400': '169 219 92', + '--color-success-500': '132 204 22', + '--color-success-600': '119 184 20', + '--color-success-700': '99 153 17', + '--color-success-800': '79 122 13', + '--color-success-900': '65 100 11', + '--color-warning-50': '252 244 218', + '--color-warning-100': '251 240 206', + '--color-warning-200': '250 236 193', + '--color-warning-300': '247 225 156', + '--color-warning-400': '240 202 82', + '--color-warning-500': '234 179 8', + '--color-warning-600': '211 161 7', + '--color-warning-700': '176 134 6', + '--color-warning-800': '140 107 5', + '--color-warning-900': '115 88 4', + '--color-error-50': '253 227 227', + '--color-error-100': '252 218 218', + '--color-error-200': '251 208 208', + '--color-error-300': '249 180 180', + '--color-error-400': '244 124 124', + '--color-error-500': '239 68 68', + '--color-error-600': '215 61 61', + '--color-error-700': '179 51 51', + '--color-error-800': '143 41 41', + '--color-error-900': '117 33 33', + '--color-surface-50': '232 232 253', + '--color-surface-100': '224 224 252', + '--color-surface-200': '216 217 252', + '--color-surface-300': '193 194 249', + '--color-surface-400': '146 148 245', + '--color-surface-500': '99 102 241', + '--color-surface-600': '89 92 217', + '--color-surface-700': '74 77 181', + '--color-surface-800': '59 61 145', + '--color-surface-900': '49 50 118', + }, + properties_dark: {}, + enhancements: { + "[data-theme='modern'] h1,\n[data-theme='modern'] h2,\n[data-theme='modern'] h3,\n[data-theme='modern'] h4,\n[data-theme='modern'] h5,\n[data-theme='modern'] h6,\n[data-theme='modern'] a,\n[data-theme='modern'] button": + { fontWeight: 'bold' }, + "[data-theme='modern']": { + backgroundImage: + 'radial-gradient(at 76% 0%, hsla(189,100%,56%,0.36) 0px, transparent 50%),\n\t\tradial-gradient(at 1% 0%, hsla(340,100%,76%,0.26) 0px, transparent 50%),\n\t\tradial-gradient(at 20% 100%, hsla(241,100%,70%,0.47) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + ".dark [data-theme='modern']": { + backgroundImage: + 'radial-gradient(at 76% 0%, hsla(189,100%,56%,0.20) 0px, transparent 50%),\n\t\tradial-gradient(at 1% 0%, hsla(340,100%,76%,0.15) 0px, transparent 50%),\n\t\tradial-gradient(at 20% 100%, hsla(241,100%,70%,0.30) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default modern; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/rocket.ts b/packages/svelte-ux/src/lib/styles/skeleton/rocket.ts new file mode 100644 index 000000000..27fcef659 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/rocket.ts @@ -0,0 +1,106 @@ +import type { PresetTheme } from './index.js'; + +const rocket = { + name: 'rocket', + properties: { + '--theme-font-family-base': 'system-ui', + '--theme-font-family-heading': "'Space Grotesk', sans-serif", + '--theme-font-color-base': 'var(--color-primary-900)', + '--theme-font-color-dark': 'var(--color-primary-100)', + '--theme-rounded-base': '0px', + '--theme-rounded-container': '0px', + '--theme-border-base': '0px', + '--on-primary': '0 0 0', + '--on-secondary': '255 255 255', + '--on-tertiary': '255 255 255', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '218 244 249', + '--color-primary-100': '205 240 246', + '--color-primary-200': '193 237 244', + '--color-primary-300': '155 226 238', + '--color-primary-400': '81 204 225', + '--color-primary-500': '6 182 212', + '--color-primary-600': '5 164 191', + '--color-primary-700': '5 137 159', + '--color-primary-800': '4 109 127', + '--color-primary-900': '3 89 104', + '--color-secondary-50': '226 236 254', + '--color-secondary-100': '216 230 253', + '--color-secondary-200': '206 224 253', + '--color-secondary-300': '177 205 251', + '--color-secondary-400': '118 168 249', + '--color-secondary-500': '59 130 246', + '--color-secondary-600': '53 117 221', + '--color-secondary-700': '44 98 185', + '--color-secondary-800': '35 78 148', + '--color-secondary-900': '29 64 121', + '--color-tertiary-50': '242 230 254', + '--color-tertiary-100': '238 221 253', + '--color-tertiary-200': '233 213 253', + '--color-tertiary-300': '220 187 252', + '--color-tertiary-400': '194 136 249', + '--color-tertiary-500': '168 85 247', + '--color-tertiary-600': '151 77 222', + '--color-tertiary-700': '126 64 185', + '--color-tertiary-800': '101 51 148', + '--color-tertiary-900': '82 42 121', + '--color-success-50': '228 247 220', + '--color-success-100': '219 245 208', + '--color-success-200': '210 242 197', + '--color-success-300': '183 234 161', + '--color-success-400': '130 219 91', + '--color-success-500': '76 203 21', + '--color-success-600': '68 183 19', + '--color-success-700': '57 152 16', + '--color-success-800': '46 122 13', + '--color-success-900': '37 99 10', + '--color-warning-50': '253 246 223', + '--color-warning-100': '253 243 212', + '--color-warning-200': '252 240 202', + '--color-warning-300': '251 230 170', + '--color-warning-400': '247 212 106', + '--color-warning-500': '244 193 42', + '--color-warning-600': '220 174 38', + '--color-warning-700': '183 145 32', + '--color-warning-800': '146 116 25', + '--color-warning-900': '120 95 21', + '--color-error-50': '244 223 230', + '--color-error-100': '240 213 221', + '--color-error-200': '237 202 213', + '--color-error-300': '225 171 187', + '--color-error-400': '203 107 136', + '--color-error-500': '181 44 85', + '--color-error-600': '163 40 77', + '--color-error-700': '136 33 64', + '--color-error-800': '109 26 51', + '--color-error-900': '89 22 42', + '--color-surface-50': '232 234 238', + '--color-surface-100': '224 227 232', + '--color-surface-200': '216 220 226', + '--color-surface-300': '193 199 209', + '--color-surface-400': '147 158 174', + '--color-surface-500': '100 116 139', + '--color-surface-600': '90 104 125', + '--color-surface-700': '75 87 104', + '--color-surface-800': '60 70 83', + '--color-surface-900': '49 57 68', + }, + properties_dark: {}, + enhancements: { + "[data-theme='rocket'] h1,\n[data-theme='rocket'] h2,\n[data-theme='rocket'] h3,\n[data-theme='rocket'] h4,\n[data-theme='rocket'] h5,\n[data-theme='rocket'] h6": + { fontWeight: 'bold' }, + "[data-theme='rocket']": { + backgroundImage: + 'radial-gradient(at 0% 0%, rgba(var(--color-secondary-500) / 0.33) 0px, transparent 50%),\n\t\t\tradial-gradient(at 98% 1%, rgba(var(--color-error-500) / 0.33) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default rocket; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/sahara.ts b/packages/svelte-ux/src/lib/styles/skeleton/sahara.ts new file mode 100644 index 000000000..5599229c0 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/sahara.ts @@ -0,0 +1,117 @@ +import type { PresetTheme } from './index.js'; + +const sahara = { + name: 'sahara', + properties: { + '--theme-font-family-base': + "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n\t\t'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + '--theme-font-family-heading': + "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',\n\t\tArial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + '--theme-font-color-base': 'var(--color-secondary-900)', + '--theme-font-color-dark': 'var(--color-primary-100)', + '--theme-rounded-base': '9999px', + '--theme-rounded-container': '24px', + '--theme-border-base': '1px', + '--on-primary': '0 0 0', + '--on-secondary': '0 0 0', + '--on-tertiary': '0 0 0', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '252 242 225', + '--color-primary-100': '251 238 215', + '--color-primary-200': '250 234 205', + '--color-primary-300': '247 221 175', + '--color-primary-400': '242 196 114', + '--color-primary-500': '236 170 54', + '--color-primary-600': '212 153 49', + '--color-primary-700': '177 128 41', + '--color-primary-800': '142 102 32', + '--color-primary-900': '116 83 26', + '--color-secondary-50': '225 247 245', + '--color-secondary-100': '216 245 241', + '--color-secondary-200': '206 242 238', + '--color-secondary-300': '176 234 227', + '--color-secondary-400': '117 219 207', + '--color-secondary-500': '58 203 186', + '--color-secondary-600': '52 183 167', + '--color-secondary-700': '44 152 140', + '--color-secondary-800': '35 122 112', + '--color-secondary-900': '28 99 91', + '--color-tertiary-50': '245 250 237', + '--color-tertiary-100': '241 249 231', + '--color-tertiary-200': '238 247 225', + '--color-tertiary-300': '228 242 207', + '--color-tertiary-400': '207 233 170', + '--color-tertiary-500': '187 223 134', + '--color-tertiary-600': '168 201 121', + '--color-tertiary-700': '140 167 101', + '--color-tertiary-800': '112 134 80', + '--color-tertiary-900': '92 109 66', + '--color-success-50': '237 247 220', + '--color-success-100': '230 245 208', + '--color-success-200': '224 242 197', + '--color-success-300': '206 235 162', + '--color-success-400': '169 219 92', + '--color-success-500': '132 204 22', + '--color-success-600': '119 184 20', + '--color-success-700': '99 153 17', + '--color-success-800': '79 122 13', + '--color-success-900': '65 100 11', + '--color-warning-50': '251 246 230', + '--color-warning-100': '250 243 221', + '--color-warning-200': '249 240 213', + '--color-warning-300': '245 230 188', + '--color-warning-400': '237 212 137', + '--color-warning-500': '229 193 87', + '--color-warning-600': '206 174 78', + '--color-warning-700': '172 145 65', + '--color-warning-800': '137 116 52', + '--color-warning-900': '112 95 43', + '--color-error-50': '250 231 240', + '--color-error-100': '248 222 235', + '--color-error-200': '246 214 230', + '--color-error-300': '241 190 215', + '--color-error-400': '230 141 186', + '--color-error-500': '219 92 156', + '--color-error-600': '197 83 140', + '--color-error-700': '164 69 117', + '--color-error-800': '131 55 94', + '--color-error-900': '107 45 76', + '--color-surface-50': '249 228 232', + '--color-surface-100': '248 220 224', + '--color-surface-200': '246 211 217', + '--color-surface-300': '240 184 193', + '--color-surface-400': '229 131 147', + '--color-surface-500': '218 78 101', + '--color-surface-600': '196 70 91', + '--color-surface-700': '164 59 76', + '--color-surface-800': '131 47 61', + '--color-surface-900': '107 38 49', + }, + properties_dark: {}, + enhancements: { + "[data-theme='sahara'] h1,\n[data-theme='sahara'] h2,\n[data-theme='sahara'] h3,\n[data-theme='sahara'] h4,\n[data-theme='sahara'] h5,\n[data-theme='sahara'] h6": + { fontWeight: '600' }, + "[data-theme='sahara'] p": { fontWeight: '400' }, + "[data-theme='sahara']": { + backgroundImage: + 'radial-gradient(at 100% 36%, hsla(37,81%,56%,0.15) 0px, transparent 50%),\n\t\tradial-gradient(at 7% 0%, hsla(37,81%,56%,0.20) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + ".dark [data-theme='sahara']": { + backgroundImage: + 'radial-gradient(at 100% 36%, hsla(37,81%,56%,0.15) 0px, transparent 50%),\n\t\tradial-gradient(at 7% 0%, hsla(37,81%,56%,0.20) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default sahara; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/seafoam.ts b/packages/svelte-ux/src/lib/styles/skeleton/seafoam.ts new file mode 100644 index 000000000..1ab017156 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/seafoam.ts @@ -0,0 +1,114 @@ +import type { PresetTheme } from './index.js'; + +const seafoam = { + name: 'seafoam', + properties: { + '--theme-font-family-base': + "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n\t\t'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + '--theme-font-family-heading': "'Playfair Display', serif", + '--theme-font-color-base': 'var(--color-surface-900)', + '--theme-font-color-dark': 'var(--color-secondary-100)', + '--theme-rounded-base': '16px', + '--theme-rounded-container': '16px', + '--theme-border-base': '3px', + '--on-primary': '0 0 0', + '--on-secondary': '255 255 255', + '--on-tertiary': '255 255 255', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '0 0 0', + '--color-primary-50': '237 248 247', + '--color-primary-100': '231 246 245', + '--color-primary-200': '225 243 242', + '--color-primary-300': '207 236 234', + '--color-primary-400': '170 222 219', + '--color-primary-500': '134 208 203', + '--color-primary-600': '121 187 183', + '--color-primary-700': '101 156 152', + '--color-primary-800': '80 125 122', + '--color-primary-900': '66 102 99', + '--color-secondary-50': '222 224 230', + '--color-secondary-100': '211 214 221', + '--color-secondary-200': '200 204 213', + '--color-secondary-300': '166 173 187', + '--color-secondary-400': '100 112 136', + '--color-secondary-500': '33 51 85', + '--color-secondary-600': '30 46 77', + '--color-secondary-700': '25 38 64', + '--color-secondary-800': '20 31 51', + '--color-secondary-900': '16 25 42', + '--color-tertiary-50': '255 226 217', + '--color-tertiary-100': '255 216 204', + '--color-tertiary-200': '255 207 191', + '--color-tertiary-300': '255 177 153', + '--color-tertiary-400': '255 119 77', + '--color-tertiary-500': '255 61 0', + '--color-tertiary-600': '230 55 0', + '--color-tertiary-700': '191 46 0', + '--color-tertiary-800': '153 37 0', + '--color-tertiary-900': '125 30 0', + '--color-success-50': '218 251 241', + '--color-success-100': '205 250 236', + '--color-success-200': '193 249 232', + '--color-success-300': '155 245 218', + '--color-success-400': '81 237 190', + '--color-success-500': '6 229 162', + '--color-success-600': '5 206 146', + '--color-success-700': '5 172 122', + '--color-success-800': '4 137 97', + '--color-success-900': '3 112 79', + '--color-warning-50': '252 251 230', + '--color-warning-100': '251 250 221', + '--color-warning-200': '250 249 213', + '--color-warning-300': '247 245 188', + '--color-warning-400': '240 237 137', + '--color-warning-500': '234 229 87', + '--color-warning-600': '211 206 78', + '--color-warning-700': '176 172 65', + '--color-warning-800': '140 137 52', + '--color-warning-900': '115 112 43', + '--color-error-50': '248 227 227', + '--color-error-100': '246 218 218', + '--color-error-200': '244 209 209', + '--color-error-300': '237 181 181', + '--color-error-400': '224 126 126', + '--color-error-500': '210 70 70', + '--color-error-600': '189 63 63', + '--color-error-700': '158 53 53', + '--color-error-800': '126 42 42', + '--color-error-900': '103 34 34', + '--color-surface-50': '222 248 249', + '--color-surface-100': '211 246 246', + '--color-surface-200': '201 244 244', + '--color-surface-300': '168 237 238', + '--color-surface-400': '102 223 225', + '--color-surface-500': '37 209 212', + '--color-surface-600': '33 188 191', + '--color-surface-700': '28 157 159', + '--color-surface-800': '22 125 127', + '--color-surface-900': '18 102 104', + }, + properties_dark: {}, + enhancements: { + "[data-theme='seafoam'] h1,\n[data-theme='seafoam'] h2,\n[data-theme='seafoam'] h3,\n[data-theme='seafoam'] h4,\n[data-theme='seafoam'] h5,\n[data-theme='seafoam'] h6": + { fontWeight: 'bold', fontStyle: 'italic', letterSpacing: '1px' }, + "[data-theme='seafoam']": { + background: + 'linear-gradient(0deg, rgba(203, 221, 254, 0.75) 0%, rgba(163, 209, 206, 0.75) 100%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + ".dark [data-theme='seafoam']": { + background: 'linear-gradient(0deg, rgba(33, 50, 83, 1) 0%, rgba(8, 132, 124, 1) 100%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default seafoam; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/skeleton.ts b/packages/svelte-ux/src/lib/styles/skeleton/skeleton.ts new file mode 100644 index 000000000..039111528 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/skeleton.ts @@ -0,0 +1,106 @@ +import type { PresetTheme } from './index.js'; + +const skeleton = { + name: 'skeleton', + properties: { + '--theme-font-family-base': 'system-ui', + '--theme-font-family-heading': 'system-ui', + '--theme-font-color-base': '0 0 0', + '--theme-font-color-dark': '255 255 255', + '--theme-rounded-base': '9999px', + '--theme-rounded-container': '8px', + '--theme-border-base': '1px', + '--on-primary': '0 0 0', + '--on-secondary': '255 255 255', + '--on-tertiary': '0 0 0', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '219 245 236', + '--color-primary-100': '207 241 230', + '--color-primary-200': '195 238 224', + '--color-primary-300': '159 227 205', + '--color-primary-400': '87 207 167', + '--color-primary-500': '15 186 129', + '--color-primary-600': '14 167 116', + '--color-primary-700': '11 140 97', + '--color-primary-800': '9 112 77', + '--color-primary-900': '7 91 63', + '--color-secondary-50': '229 227 251', + '--color-secondary-100': '220 218 250', + '--color-secondary-200': '211 209 249', + '--color-secondary-300': '185 181 245', + '--color-secondary-400': '132 126 237', + '--color-secondary-500': '79 70 229', + '--color-secondary-600': '71 63 206', + '--color-secondary-700': '59 53 172', + '--color-secondary-800': '47 42 137', + '--color-secondary-900': '39 34 112', + '--color-tertiary-50': '219 242 252', + '--color-tertiary-100': '207 237 251', + '--color-tertiary-200': '195 233 250', + '--color-tertiary-300': '159 219 246', + '--color-tertiary-400': '86 192 240', + '--color-tertiary-500': '14 165 233', + '--color-tertiary-600': '13 149 210', + '--color-tertiary-700': '11 124 175', + '--color-tertiary-800': '8 99 140', + '--color-tertiary-900': '7 81 114', + '--color-success-50': '237 247 220', + '--color-success-100': '230 245 208', + '--color-success-200': '224 242 197', + '--color-success-300': '206 235 162', + '--color-success-400': '169 219 92', + '--color-success-500': '132 204 22', + '--color-success-600': '119 184 20', + '--color-success-700': '99 153 17', + '--color-success-800': '79 122 13', + '--color-success-900': '65 100 11', + '--color-warning-50': '252 244 218', + '--color-warning-100': '251 240 206', + '--color-warning-200': '250 236 193', + '--color-warning-300': '247 225 156', + '--color-warning-400': '240 202 82', + '--color-warning-500': '234 179 8', + '--color-warning-600': '211 161 7', + '--color-warning-700': '176 134 6', + '--color-warning-800': '140 107 5', + '--color-warning-900': '115 88 4', + '--color-error-50': '249 221 234', + '--color-error-100': '246 209 228', + '--color-error-200': '244 198 221', + '--color-error-300': '238 163 200', + '--color-error-400': '225 94 159', + '--color-error-500': '212 25 118', + '--color-error-600': '191 23 106', + '--color-error-700': '159 19 89', + '--color-error-800': '127 15 71', + '--color-error-900': '104 12 58', + '--color-surface-50': '228 230 238', + '--color-surface-100': '219 222 233', + '--color-surface-200': '210 214 227', + '--color-surface-300': '182 189 210', + '--color-surface-400': '128 140 177', + '--color-surface-500': '73 90 143', + '--color-surface-600': '66 81 129', + '--color-surface-700': '55 68 107', + '--color-surface-800': '44 54 86', + '--color-surface-900': '36 44 70', + }, + properties_dark: {}, + enhancements: { + "[data-theme='skeleton'] h1,\n[data-theme='skeleton'] h2,\n[data-theme='skeleton'] h3,\n[data-theme='skeleton'] h4,\n[data-theme='skeleton'] h5,\n[data-theme='skeleton'] h6": + { fontWeight: 'bold' }, + "[data-theme='skeleton']": { + backgroundImage: + 'radial-gradient(at 0% 0%, rgba(var(--color-secondary-500) / 0.33) 0px, transparent 50%),\n\t\t\tradial-gradient(at 98% 1%, rgba(var(--color-error-500) / 0.33) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default skeleton; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/vintage.ts b/packages/svelte-ux/src/lib/styles/skeleton/vintage.ts new file mode 100644 index 000000000..36d8dd53b --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/vintage.ts @@ -0,0 +1,115 @@ +import type { PresetTheme } from './index.js'; + +const vintage = { + name: 'vintage', + properties: { + '--theme-font-family-base': + "Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,\n\t\t'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + '--theme-font-family-heading': "'Abril Fatface', cursive", + '--theme-font-color-base': 'var(--color-primary-900)', + '--theme-font-color-dark': 'var(--color-primary-100)', + '--theme-rounded-base': '2px', + '--theme-rounded-container': '4px', + '--theme-border-base': '1px', + '--on-primary': '0 0 0', + '--on-secondary': '0 0 0', + '--on-tertiary': '0 0 0', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '0 0 0', + '--on-surface': '255 255 255', + '--color-primary-50': '252 237 221', + '--color-primary-100': '251 231 209', + '--color-primary-200': '250 225 198', + '--color-primary-300': '247 207 163', + '--color-primary-400': '240 170 95', + '--color-primary-500': '234 134 26', + '--color-primary-600': '211 121 23', + '--color-primary-700': '176 101 20', + '--color-primary-800': '140 80 16', + '--color-primary-900': '115 66 13', + '--color-secondary-50': '239 248 242', + '--color-secondary-100': '234 245 237', + '--color-secondary-200': '229 243 233', + '--color-secondary-300': '213 235 219', + '--color-secondary-400': '182 221 192', + '--color-secondary-500': '151 206 165', + '--color-secondary-600': '136 185 149', + '--color-secondary-700': '113 155 124', + '--color-secondary-800': '91 124 99', + '--color-secondary-900': '74 101 81', + '--color-tertiary-50': '218 244 249', + '--color-tertiary-100': '205 240 246', + '--color-tertiary-200': '193 237 244', + '--color-tertiary-300': '155 226 238', + '--color-tertiary-400': '81 204 225', + '--color-tertiary-500': '6 182 212', + '--color-tertiary-600': '5 164 191', + '--color-tertiary-700': '5 137 159', + '--color-tertiary-800': '4 109 127', + '--color-tertiary-900': '3 89 104', + '--color-success-50': '237 247 231', + '--color-success-100': '230 245 223', + '--color-success-200': '224 242 215', + '--color-success-300': '206 234 190', + '--color-success-400': '169 219 142', + '--color-success-500': '132 203 93', + '--color-success-600': '119 183 84', + '--color-success-700': '99 152 70', + '--color-success-800': '79 122 56', + '--color-success-900': '65 99 46', + '--color-warning-50': '253 243 222', + '--color-warning-100': '252 238 211', + '--color-warning-200': '252 234 200', + '--color-warning-300': '250 222 167', + '--color-warning-400': '246 197 101', + '--color-warning-500': '242 172 35', + '--color-warning-600': '218 155 32', + '--color-warning-700': '182 129 26', + '--color-warning-800': '145 103 21', + '--color-warning-900': '119 84 17', + '--color-error-50': '249 236 235', + '--color-error-100': '247 229 228', + '--color-error-200': '245 223 221', + '--color-error-300': '238 203 201', + '--color-error-400': '226 165 161', + '--color-error-500': '213 126 120', + '--color-error-600': '192 113 108', + '--color-error-700': '160 95 90', + '--color-error-800': '128 76 72', + '--color-error-900': '104 62 59', + '--color-surface-50': '226 225 224', + '--color-surface-100': '217 215 214', + '--color-surface-200': '207 205 204', + '--color-surface-300': '178 175 173', + '--color-surface-400': '121 115 111', + '--color-surface-500': '63 55 49', + '--color-surface-600': '57 50 44', + '--color-surface-700': '47 41 37', + '--color-surface-800': '38 33 29', + '--color-surface-900': '31 27 24', + }, + properties_dark: {}, + enhancements: { + "[data-theme='vintage'] h1,\n[data-theme='vintage'] h2,\n[data-theme='vintage'] h3,\n[data-theme='vintage'] h4,\n[data-theme='vintage'] h5,\n[data-theme='vintage'] h6": + { letterSpacing: '1px' }, + "[data-theme='vintage']": { + backgroundImage: + 'radial-gradient(at 100% 0%, hsla(135,34%,70%,0.20) 0px, transparent 50%),\n\t\tradial-gradient(at 85% 100%, hsla(31,83%,50%,0.20) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + ".dark [data-theme='vintage']": { + backgroundImage: + 'radial-gradient(at 100% 0%, hsla(135,34%,70%,0.14) 0px, transparent 50%),\n\t\tradial-gradient(at 85% 100%, hsla(31,83%,50%,0.14) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + }, +} satisfies PresetTheme; + +export default vintage; diff --git a/packages/svelte-ux/src/lib/styles/skeleton/wintry.ts b/packages/svelte-ux/src/lib/styles/skeleton/wintry.ts new file mode 100644 index 000000000..23b993805 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/skeleton/wintry.ts @@ -0,0 +1,110 @@ +import type { PresetTheme } from './index.js'; + +const wintry = { + name: 'wintry', + properties: { + '--theme-font-family-heading': 'Inter, system-ui, sans-serif', + '--theme-font-family-base': 'system-ui', + '--theme-font-color-base': '23 37 84', + '--theme-font-color-dark': '255 255 255', + '--theme-rounded-base': '9999px', + '--theme-rounded-container': '6px', + '--theme-border-base': '1px', + '--on-primary': '0 0 0', + '--on-secondary': '0 0 0', + '--on-tertiary': '255 255 255', + '--on-success': '0 0 0', + '--on-warning': '0 0 0', + '--on-error': '255 255 255', + '--on-surface': '255 255 255', + '--color-primary-50': '239 246 255', + '--color-primary-100': '219 234 254', + '--color-primary-200': '191 219 254', + '--color-primary-300': '147 197 253', + '--color-primary-400': '96 165 250', + '--color-primary-500': '59 130 246', + '--color-primary-600': '37 99 235', + '--color-primary-700': '29 78 216', + '--color-primary-800': '30 64 175', + '--color-primary-900': '30 58 138', + '--color-secondary-50': '240 249 255', + '--color-secondary-100': '224 242 254', + '--color-secondary-200': '186 230 253', + '--color-secondary-300': '125 211 252', + '--color-secondary-400': '56 189 248', + '--color-secondary-500': '14 165 233', + '--color-secondary-600': '2 132 199', + '--color-secondary-700': '3 105 161', + '--color-secondary-800': '7 89 133', + '--color-secondary-900': '12 74 110', + '--color-tertiary-50': '238 242 255', + '--color-tertiary-100': '224 231 255', + '--color-tertiary-200': '199 210 254', + '--color-tertiary-300': '165 180 252', + '--color-tertiary-400': '129 140 248', + '--color-tertiary-500': '99 102 241', + '--color-tertiary-600': '79 70 229', + '--color-tertiary-700': '67 56 202', + '--color-tertiary-800': '55 48 163', + '--color-tertiary-900': '49 46 129', + '--color-success-50': '237 247 220', + '--color-success-100': '230 245 208', + '--color-success-200': '224 242 197', + '--color-success-300': '206 235 162', + '--color-success-400': '169 219 92', + '--color-success-500': '132 204 22', + '--color-success-600': '119 184 20', + '--color-success-700': '99 153 17', + '--color-success-800': '79 122 13', + '--color-success-900': '65 100 11', + '--color-warning-50': '252 244 218', + '--color-warning-100': '251 240 206', + '--color-warning-200': '250 236 193', + '--color-warning-300': '247 225 156', + '--color-warning-400': '240 202 82', + '--color-warning-500': '234 179 8', + '--color-warning-600': '211 161 7', + '--color-warning-700': '176 134 6', + '--color-warning-800': '140 107 5', + '--color-warning-900': '115 88 4', + '--color-error-50': '249 221 234', + '--color-error-100': '246 209 228', + '--color-error-200': '244 198 221', + '--color-error-300': '238 163 200', + '--color-error-400': '225 94 159', + '--color-error-500': '212 25 118', + '--color-error-600': '191 23 106', + '--color-error-700': '159 19 89', + '--color-error-800': '127 15 71', + '--color-error-900': '104 12 58', + '--color-surface-50': '249 250 251', + '--color-surface-100': '243 244 246', + '--color-surface-200': '229 231 235', + '--color-surface-300': '209 213 219', + '--color-surface-400': '156 163 175', + '--color-surface-500': '107 114 128', + '--color-surface-600': '75 85 99', + '--color-surface-700': '55 65 81', + '--color-surface-800': '31 41 55', + '--color-surface-900': '17 24 39', + }, + properties_dark: {}, + enhancements: { + "[data-theme='wintry'] h1,\n[data-theme='wintry'] h2,\n[data-theme='wintry'] h3,\n[data-theme='wintry'] h4,\n[data-theme='wintry'] h5,\n[data-theme='wintry'] h6": + { fontWeight: 'bold' }, + "[data-theme='wintry']": { + backgroundImage: + 'radial-gradient(at 50% 0%, rgba(var(--color-secondary-500) / 0.50) 0px, transparent 75%), radial-gradient(at 100% 0%, rgba(var(--color-tertiary-500) / 0.40) 0px, transparent 50%)', + backgroundAttachment: 'fixed', + backgroundPosition: 'center', + backgroundRepeat: 'no-repeat', + backgroundSize: 'cover', + }, + ".dark [data-theme='wintry']": { + backgroundImage: + 'radial-gradient(at 50% 0%, rgba(var(--color-secondary-500) / 0.18) 0px, transparent 75%), radial-gradient(at 100% 0%, rgba(var(--color-tertiary-500) / 0.18) 0px, transparent 50%)', + }, + }, +} satisfies PresetTheme; + +export default wintry; diff --git a/packages/svelte-ux/src/lib/styles/theme.ts b/packages/svelte-ux/src/lib/styles/theme.ts new file mode 100644 index 000000000..541671e86 --- /dev/null +++ b/packages/svelte-ux/src/lib/styles/theme.ts @@ -0,0 +1,266 @@ +import { range } from 'd3-array'; + +import { + rgb, + hsl, + oklch, + clampRgb, + interpolate, + wcagContrast, + formatCss, + type Color, +} from 'culori'; + +export type SupportedColorSpace = 'rgb' | 'hsl' | 'oklch'; + +export const semanticColors = ['primary', 'secondary', 'accent', 'neutral'] as const; +export const stateColors = ['info', 'success', 'warning', 'danger'] as const; +export const colors = [...semanticColors, ...stateColors]; + +export const shades = [50, ...range(100, 1000, 100)]; + +export const colorNames = [ + // Semantic & State colors (ex. `priamry`, 'primary-content`, 'primary-100`, ...) + ...colors.flatMap((color) => [ + color, // default + `${color}-content`, // text/content + ...shades.map((shade) => `${color}-${shade}`), + ]), + + // Surfaces + 'surface-100', + 'surface-200', + 'surface-300', + 'surface-content', +]; + +/** + * Generate theme colors (ex. { primary: hsl(var(--color-primary) / <alpha-value>), ... }) + */ +export function createThemeColors(colorSpace: SupportedColorSpace) { + return Object.fromEntries( + colorNames.map((color) => [color, `${colorSpace}(var(--color-${color}) / <alpha-value>)`]) + ); +} + +/** + * Get themes names split into light and dark collections determined by `color-scheme` property + */ +export function getThemeNames(themes: Record<string, any>) { + const light: string[] = []; + const dark: string[] = []; + + Object.entries(themes).map(([themeName, props]) => { + if (props['color-scheme'] === 'dark') { + dark.push(themeName); + } else { + light.push(themeName); + } + }); + + return { light, dark }; +} + +/** + * Convert names to CSS variables and color values common color space (hsl, oklch, etc) and space separated + */ +export function processThemeColors( + themeColors: Record<string, string>, + colorSpace: SupportedColorSpace +) { + const colors = { ...themeColors }; + + // Generate optional semanatic colors + if (!('neutral' in colors) && !('neutral-500' in colors)) { + colors['neutral'] = 'oklch(.355192 .032071 262.988584)'; + } + + // Generate optional state colors + if (!('info' in colors) && !('info-500' in colors)) { + colors['info'] = 'oklch(0.7206 0.191 231.6)'; + } + if (!('success' in colors) && !('success-500' in colors)) { + colors['success'] = 'oklch(64.8% 0.150 160)'; + } + if (!('warning' in colors) && !('warning-500' in colors)) { + colors['warning'] = 'oklch(0.8471 0.199 83.87)'; + } + if (!('danger' in colors) && !('danger-500' in colors)) { + colors['danger'] = 'oklch(0.7176 0.221 22.18)'; + } + + // Generate optional content colors + for (const color of [...semanticColors, ...stateColors]) { + // Add `primary` from `primary-500` if not defined in theme (ex. Skeleton) + if (!(color in colors) && `${color}-500` in themeColors) { + colors[color] = themeColors[`${color}-500`]; + } + + if (!(`${color}-content` in colors)) { + colors[`${color}-content`] = foregroundColor(colors[color]); + } + + // Generate color shades (ex. `primary-500`) if not defined. Useful for Daisy but not Skeleton themes, for example + for (const shade of shades) { + const shadeColorName = `${color}-${shade}`; + if (!(shadeColorName in colors)) { + // Find the next shade above (shade < 500) or below (shade > 500) and use as reference, if available + const referenceShade = + Object.keys(colors) + .map((str) => { + const [c, s] = str.split('-'); + return [c, Number(s)]; + }) + .find(([c, s]) => c === color && (s < 500 ? s > shade : s < shade))?.[1] ?? 500; + const referenceColor = colors[`${color}-${referenceShade}`] ?? colors[color]; + + if (shade < 500) { + colors[shadeColorName] = lightenColor(referenceColor, (referenceShade - shade) / 1000); // 100 == 0.1 + } else if (shade > 500) { + colors[shadeColorName] = darkenColor(colors[color], (shade - referenceShade) / 1000); // 100 == 0.1 + } else { + colors[shadeColorName] = colors[color]; + } + } + } + } + + // Generate optional surface colors + if (!('surface-100' in colors)) { + colors['surface-100'] = 'oklch(100 0 0)'; + } + + if (!('surface-200' in colors)) { + colors['surface-200'] = darkenColor(colors['surface-100'], 0.07); + } + + if (!('surface-300' in colors)) { + if ('surface-200' in themeColors) { + colors['surface-300'] = darkenColor(colors['surface-200'], 0.07); + } else { + colors['surface-300'] = darkenColor(colors['surface-100'], 0.14); + } + } + + if (!('surface-content' in colors)) { + colors['surface-content'] = foregroundColor(colors['surface-100']); + } + + const result = Object.fromEntries( + Object.entries(colors).map(([name, value]) => { + if (colorNames.includes(name)) { + // Add space separated color variables for each color + return [`--color-${name}`, colorVariableValue(value, colorSpace)]; + } else { + // Additional properties such as `color-scheme` or CSS variable + return [name, value]; + } + }) + ); + + return result; +} + +function round(value: number, decimals: number) { + if (value) { + return Number(value.toFixed(decimals)); + } else { + return 0; + } +} + +function isDark(color: Color | string) { + try { + if (wcagContrast(color, 'black') < wcagContrast(color, 'white')) { + return true; + } + return false; + } catch (e) { + return false; + } +} + +/** Lighten or darken color based on contrast of input */ +function foregroundColor(color: Color | string, percentage = 0.8) { + try { + return isDark(color) ? lightenColor(color, percentage) : darkenColor(color, percentage); + } catch (e) { + // console.error('Unable to generate foreground color', color); + } +} + +function lightenColor(color: Color | string, percentage: number) { + try { + return formatCss(interpolate([color, 'white'], 'oklch')(percentage)); + } catch (e) { + // console.error('Unable to generate lighten color', color); + } +} + +function darkenColor(color: Color | string, percentage: number) { + try { + return formatCss(interpolate([color, 'black'], 'oklch')(percentage)); + } catch (e) { + // console.error('Unable to generate darken color', color); + } +} + +/** + * Convert color to space separated components string + */ +export function colorVariableValue( + color: Color | string, + colorSpace: SupportedColorSpace, + decimals = 4 +) { + try { + if (colorSpace === 'rgb') { + const { r, g, b } = rgb(color); + return `${round(r * 255, decimals)} ${round(g * 255, decimals)} ${round(b * 255, decimals)}`; + } else if (colorSpace === 'hsl') { + const { h, s, l } = hsl(clampRgb(color)); + return `${round(h, decimals)} ${round(s * 100, decimals)}% ${round(l * 100, decimals)}%`; + } else if (colorSpace === 'oklch') { + const { l, c, h } = oklch(color); + return `${round(l, decimals)} ${round(c, decimals)} ${round(h, decimals)}`; + } + } catch (e) { + // console.error('Unable to convert color object to string', color); + } +} + +/** + * Process theme to style variables + */ +export function themeStylesString(theme: any, colorSpace: SupportedColorSpace) { + const styleProperties = processThemeColors(theme, colorSpace); + return Object.entries(styleProperties) + .map(([key, value]) => { + return `${key}: ${value};`; + }) + .join('\n'); +} + +/** Return a script tag that will set the initial theme from localStorage. This allows setting + * the theme before anything starts rendering, even when SSR is in use. + * + * This feels a bit weird compared to just placing the function directly in svelte:head, + * but it's the only way to inject the `darkThemes` array into the function. + **/ +export function createHeadSnippet(darkThemes: string[]) { + function _applyInitialStyle(darkThemes) { + let theme = localStorage.getItem('theme'); + if (theme) { + document.documentElement.dataset.theme = theme; + if (darkThemes.includes(theme)) { + document.documentElement.classList.add('dark'); + } + } else if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + document.documentElement.classList.add('dark'); + } + } + + let darkThemeList = darkThemes.map((theme) => `'${theme}'`).join(', '); + + return `<script>(${_applyInitialStyle.toString()})([${darkThemeList}])</script>`; +} diff --git a/packages/svelte-ux/src/lib/types/table.ts b/packages/svelte-ux/src/lib/types/table.ts index c4e034e54..695e3439c 100644 --- a/packages/svelte-ux/src/lib/types/table.ts +++ b/packages/svelte-ux/src/lib/types/table.ts @@ -18,7 +18,7 @@ export type ColumnDef<TData = any> = { name: string; header?: string; value?: string | ((rowData: TData, rowIndex?: number) => any); - format?: FormatType; + format?: FormatType | ((value: any, rowData: any, rowIndex: number) => string); /** Render as HTML. Only enable if value from trusted source (else exposing to XSS vulnerability) */ html?: boolean; orderBy?: string | boolean | ((a: any, b: any) => number); diff --git a/packages/svelte-ux/src/lib/types/typeHelpers.ts b/packages/svelte-ux/src/lib/types/typeHelpers.ts index c928b6836..018003b54 100644 --- a/packages/svelte-ux/src/lib/types/typeHelpers.ts +++ b/packages/svelte-ux/src/lib/types/typeHelpers.ts @@ -1,6 +1,7 @@ // https://basarat.gitbooks.io/typescript/docs/types/never.html#use-case-exhaustive-checks -import type { SvelteComponentTyped } from 'svelte'; +import type { colors } from '$lib/styles/theme'; +import type { SvelteComponent } from 'svelte'; import type { derived, Readable } from 'svelte/store'; import type { FlyParams, @@ -79,9 +80,9 @@ export type FilterPropKeys<T, Match> = { }[keyof T]; // https://stackoverflow.com/a/72297256/191902 -export type ComponentProps<T> = T extends SvelteComponentTyped<infer P, any, any> ? P : never; -export type ComponentEvents<T> = T extends SvelteComponentTyped<any, infer E, any> ? E : never; -export type ComponentSlots<T> = T extends SvelteComponentTyped<any, any, infer S> ? S : never; +export type ComponentProps<T> = T extends SvelteComponent<infer P, any, any> ? P : never; +export type ComponentEvents<T> = T extends SvelteComponent<any, infer E, any> ? E : never; +export type ComponentSlots<T> = T extends SvelteComponent<any, any, infer S> ? S : never; // Export until `Stores` and `StoresValues` are exported from svelte - https://github.com/sveltejs/svelte/blob/master/src/runtime/store/index.ts#L111-L112 export type Stores = Parameters<typeof derived>[0]; @@ -94,7 +95,6 @@ export type StoresValues<T> = T extends Readable<infer U> export type TransitionParams = BlurParams | FadeParams | FlyParams | SlideParams | ScaleParams; export type TailwindColors = - | 'accent' | 'red' | 'orange' | 'amber' @@ -114,9 +114,29 @@ export type TailwindColors = | 'rose' | 'gray'; +export type ThemeColors = (typeof colors)[number]; + export type EventWithTarget = Partial<Pick<Event, 'currentTarget' | 'target'>>; // Matt Pocock tips //https://www.youtube.com/watch?v=2lCCKiWGlC0 export type Prettify<T> = { [K in keyof T]: T[K]; } & {}; + +/** + * util to make sure we have handled all enum cases in a switch statement + * Just add at the end of the switch statement a `default` like this: + * + * ```ts + * switch (periodType) { + * case xxx: + * ... + * + * default: + * assertNever(periodType); // This will now report unhandled cases + * } + * ``` + */ +export function assertNever(x: never): never { + throw new Error(`Unhandled enum case: ${x}`); +} diff --git a/packages/svelte-ux/src/lib/utils/date.test.ts b/packages/svelte-ux/src/lib/utils/date.test.ts new file mode 100644 index 000000000..f4e6f4dcc --- /dev/null +++ b/packages/svelte-ux/src/lib/utils/date.test.ts @@ -0,0 +1,536 @@ +import { describe, it, expect } from 'vitest'; +import { + formatDate, + getMonthDaysByWeek, + localToUtcDate, + utcToLocalDate, + formatIntl, + formatDateWithLocale, + getPeriodTypeByCode, + getPeriodTypeCode, +} from './date'; +import { formatWithLocale } from '.'; +import { createLocaleSettings, defaultLocale } from './locale'; +import { + PeriodType, + type FormatDateOptions, + DayOfWeek, + type CustomIntlDateTimeFormatOptions, + DateToken, +} from './date_types'; +import { getWeekStartsOnFromIntl } from './dateInternal'; + +const DATE = '2023-11-21'; // "good" default date as the day (21) is bigger than 12 (number of months). And november is a good month1 (because why not?) +const dt_2M_2d = new Date(2023, 10, 21); +const dt_2M_1d = new Date(2023, 10, 7); +const dt_1M_1d = new Date(2023, 2, 7); +const dt_first = new Date(2024, 1, 1); + +const dt_1M_1d_time_pm = new Date(2023, 2, 7, 14, 2, 3, 4); +const dt_1M_1d_time_am = new Date(2023, 2, 7, 1, 2, 3, 4); + +const fr = createLocaleSettings({ + locale: 'fr', + formats: { + dates: { + ordinalSuffixes: { + one: 'er', + }, + }, + }, +}); + +describe('formatDate()', () => { + it('should return empty string for null or undefined date', () => { + // @ts-expect-error + expect(formatDate(null)).equal(''); + // @ts-expect-error + expect(formatDate(undefined)).equal(''); + }); + + it('should return empty string for invalid date', () => { + // @ts-expect-error + expect(formatDate('invalid date')).equal(''); + }); + + describe('should format date for PeriodType.Day', () => { + const localDate = new Date(2023, 10, 21); + const combi = [ + ['short', defaultLocale, '11/21'], + ['short', fr, '21/11'], + ['long', defaultLocale, 'Nov 21, 2023'], + ['long', fr, '21 nov. 2023'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, localDate, PeriodType.Day, { variant })).equal( + expected + ); + }); + } + }); + + describe('should format date string for PeriodType.Day', () => { + const combi = [ + ['short', defaultLocale, '11/21'], + ['short', fr, '21/11'], + ['long', defaultLocale, 'Nov 21, 2023'], + ['long', fr, '21 nov. 2023'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, PeriodType.Day, { variant })).equal(expected); + }); + } + }); + + describe('should format date string for DayTime, TimeOnly', () => { + const combi: [Date, PeriodType, FormatDateOptions, string[]][] = [ + [ + dt_1M_1d_time_pm, + PeriodType.DayTime, + { variant: 'short' }, + ['3/7/2023, 2:02 PM', '07/03/2023 14:02'], + ], + [ + dt_1M_1d_time_pm, + PeriodType.DayTime, + { variant: 'default' }, + ['3/7/2023, 02:02 PM', '07/03/2023 14:02'], + ], + [ + dt_1M_1d_time_pm, + PeriodType.DayTime, + { variant: 'long' }, + ['3/7/2023, 02:02:03 PM', '07/03/2023 14:02:03'], + ], + [dt_1M_1d_time_pm, PeriodType.TimeOnly, { variant: 'short' }, ['2:02 PM', '14:02']], + [dt_1M_1d_time_pm, PeriodType.TimeOnly, { variant: 'default' }, ['02:02:03 PM', '14:02:03']], + [ + dt_1M_1d_time_pm, + PeriodType.TimeOnly, + { variant: 'long' }, + ['02:02:03.004 PM', '14:02:03,004'], + ], + ]; + + for (const c of combi) { + const [date, periodType, options, [expected_default, expected_fr]] = c; + it(c.toString(), () => { + expect(formatWithLocale(defaultLocale, date, periodType, options)).equal(expected_default); + }); + + it(c.toString() + 'fr', () => { + expect(formatWithLocale(fr, date, periodType, options)).equal(expected_fr); + }); + } + }); + + describe('should format date for PeriodType.WeekSun / Mon no mather the locale', () => { + const combi = [ + [PeriodType.WeekSun, 'short', defaultLocale, '11/19 - 11/25'], + [PeriodType.WeekSun, 'short', fr, '19/11 - 25/11'], + [PeriodType.WeekSun, 'long', defaultLocale, '11/19/2023 - 11/25/2023'], + [PeriodType.WeekSun, 'long', fr, '19/11/2023 - 25/11/2023'], + [PeriodType.WeekMon, 'long', defaultLocale, '11/20/2023 - 11/26/2023'], + [PeriodType.WeekMon, 'long', fr, '20/11/2023 - 26/11/2023'], + ] as const; + + for (const c of combi) { + const [periodType, variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, periodType, { variant })).equal(expected); + }); + } + }); + + describe('should format date for PeriodType.Week with the good weekstarton locale', () => { + const combi = [ + [PeriodType.Week, 'short', defaultLocale, '11/19 - 11/25'], + [PeriodType.Week, 'short', fr, '20/11 - 26/11'], + [PeriodType.Week, 'long', defaultLocale, '11/19/2023 - 11/25/2023'], + [PeriodType.Week, 'long', fr, '20/11/2023 - 26/11/2023'], + + [PeriodType.Week, 'short', defaultLocale, '11/19 - 11/25'], + [PeriodType.Week, 'short', fr, '20/11 - 26/11'], + [PeriodType.Week, 'long', defaultLocale, '11/19/2023 - 11/25/2023'], + [PeriodType.Week, 'long', fr, '20/11/2023 - 26/11/2023'], + ] as const; + + for (const c of combi) { + const [periodType, variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, periodType, { variant })).equal(expected); + }); + } + }); + + describe('should format date for PeriodType.Month', () => { + const combi = [ + ['short', defaultLocale, 'Nov'], + ['short', fr, 'nov.'], + ['long', defaultLocale, 'November'], + ['long', fr, 'novembre'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, PeriodType.Month, { variant })).equal(expected); + }); + } + }); + + describe('should format date for PeriodType.MonthYear', () => { + const combi = [ + ['short', defaultLocale, 'Nov 23'], + ['short', fr, 'nov. 23'], + ['long', defaultLocale, 'November 2023'], + ['long', fr, 'novembre 2023'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, PeriodType.MonthYear, { variant })).equal( + expected + ); + }); + } + }); + + describe('should format date for PeriodType.Quarter', () => { + const combi = [ + ['short', defaultLocale, 'Oct - Dec 23'], + ['short', fr, 'oct. - déc. 23'], + ['long', defaultLocale, 'October - December 2023'], + ['long', fr, 'octobre - décembre 2023'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, PeriodType.Quarter, { variant })).equal( + expected + ); + }); + } + }); + + describe('should format date for PeriodType.CalendarYear', () => { + const combi = [ + ['short', defaultLocale, '23'], + ['short', fr, '23'], + ['long', defaultLocale, '2023'], + ['long', fr, '2023'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, PeriodType.CalendarYear, { variant })).equal( + expected + ); + }); + } + }); + + describe('should format date for PeriodType.FiscalYearOctober', () => { + const combi = [ + ['short', defaultLocale, '24'], + ['short', fr, '24'], + ['long', defaultLocale, '2024'], + ['long', fr, '2024'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect( + formatDateWithLocale(locales, DATE, PeriodType.FiscalYearOctober, { variant }) + ).equal(expected); + }); + } + }); + + describe('should format date for PeriodType.BiWeek1Sun', () => { + const combi = [ + ['short', defaultLocale, '11/12 - 11/25'], + ['short', fr, '12/11 - 25/11'], + ['long', defaultLocale, '11/12/2023 - 11/25/2023'], + ['long', fr, '12/11/2023 - 25/11/2023'], + ] as const; + + for (const c of combi) { + const [variant, locales, expected] = c; + it(c.toString(), () => { + expect(formatDateWithLocale(locales, DATE, PeriodType.BiWeek1Sun, { variant })).equal( + expected + ); + }); + } + }); + + describe('should format date for PeriodType.undefined', () => { + const expected = '2023-11-21T00:00:00-04:00'; + const combi = [ + ['short', defaultLocale], + ['short', fr], + ['long', defaultLocale], + ['long', fr], + ] as const; + + for (const c of combi) { + const [variant, locales] = c; + it(c.toString(), () => { + // @ts-expect-error + expect(formatDateWithLocale(locales, DATE, undefined, { variant })).equal(expected); + }); + } + }); +}); + +describe('formatIntl() tokens', () => { + const combi: [Date, CustomIntlDateTimeFormatOptions, string[]][] = [ + [dt_1M_1d, 'MM/dd/yyyy', ['03/07/2023', '07/03/2023']], + [dt_2M_2d, 'M/d/yyyy', ['11/21/2023', '21/11/2023']], + [dt_2M_1d, 'M/d/yyyy', ['11/7/2023', '07/11/2023']], + [dt_2M_1d, 'M/dd/yyyy', ['11/07/2023', '07/11/2023']], + [dt_1M_1d, 'M/d/yyyy', ['3/7/2023', '07/03/2023']], + [dt_1M_1d, 'MM/d/yyyy', ['03/7/2023', '7/03/2023']], + [dt_2M_2d, 'M/d', ['11/21', '21/11']], + [dt_2M_2d, 'MMM d, yyyy', ['Nov 21, 2023', '21 nov. 2023']], + [dt_2M_1d, 'MMM d, yyyy', ['Nov 7, 2023', '7 nov. 2023']], + [dt_2M_1d, 'MMM do, yyyy', ['Nov 7th, 2023', '7 nov. 2023']], + [dt_2M_2d, 'MMM', ['Nov', 'nov.']], + [dt_2M_2d, 'MMMM', ['November', 'novembre']], + [dt_2M_2d, 'MMM yy', ['Nov 23', 'nov. 23']], + [dt_2M_2d, 'MMMM yyyy', ['November 2023', 'novembre 2023']], + [dt_2M_2d, 'yy', ['23', '23']], + [dt_2M_2d, 'yyyy', ['2023', '2023']], + [dt_2M_2d, { dateStyle: 'full' }, ['Tuesday, November 21, 2023', 'mardi 21 novembre 2023']], + [dt_2M_2d, { dateStyle: 'long' }, ['November 21, 2023', '21 novembre 2023']], + [dt_2M_2d, { dateStyle: 'medium' }, ['Nov 21, 2023', '21 nov. 2023']], + [dt_2M_2d, { dateStyle: 'medium', withOrdinal: true }, ['Nov 21st, 2023', '21 nov. 2023']], + [dt_2M_2d, { dateStyle: 'short' }, ['11/21/23', '21/11/2023']], + [dt_1M_1d, { dateStyle: 'short' }, ['3/7/23', '07/03/2023']], + [dt_first, DateToken.DayOfMonth_withOrdinal, ['1st', '1er']], + + // time + [dt_1M_1d_time_pm, [DateToken.Hour_numeric, DateToken.Minute_numeric], ['2:02 PM', '14:02']], + [dt_1M_1d_time_am, [DateToken.Hour_numeric, DateToken.Minute_numeric], ['1:02 AM', '01:02']], + [ + dt_1M_1d_time_am, + [DateToken.Hour_numeric, DateToken.Minute_numeric, DateToken.Hour_wAMPM], + ['1:02 AM', '1:02 AM'], + ], + [ + dt_1M_1d_time_am, + [DateToken.Hour_2Digit, DateToken.Minute_2Digit, DateToken.Hour_woAMPM], + ['01:02', '01:02'], + ], + [ + dt_1M_1d_time_am, + [DateToken.Hour_numeric, DateToken.Minute_numeric, DateToken.Second_numeric], + ['1:02:03 AM', '01:02:03'], + ], + [ + dt_1M_1d_time_am, + [ + DateToken.Hour_numeric, + DateToken.Minute_numeric, + DateToken.Second_numeric, + DateToken.MiliSecond_3, + ], + ['1:02:03.004 AM', '01:02:03,004'], + ], + ]; + + for (const c of combi) { + const [date, tokens, [expected_default, expected_fr]] = c; + it(c.toString(), () => { + expect(formatIntl(defaultLocale, date, tokens)).equal(expected_default); + }); + + it(c.toString() + 'fr', () => { + expect(formatIntl(fr, date, tokens)).equal(expected_fr); + }); + } +}); + +describe('utcToLocalDate()', () => { + it('in with offset -00 => local', () => { + const utcDate = '2023-11-21T00:00:00-00:00'; + const localDate = utcToLocalDate(utcDate); + expect(localDate.toISOString()).equal('2023-11-21T04:00:00.000Z'); + }); + + it('in without offset, the utc is already +4, to local: another +4', () => { + const utcDate = '2023-11-21T00:00:00'; + const localDate = utcToLocalDate(utcDate); + expect(localDate.toISOString()).equal('2023-11-21T08:00:00.000Z'); + }); +}); + +describe('localToUtcDate()', () => { + it('in with offset -04 => UTC', () => { + const localDate = '2023-11-21T00:00:00-04:00'; + const utcDate = localToUtcDate(localDate); + expect(utcDate.toISOString()).equal('2023-11-21T00:00:00.000Z'); + }); + + it('in with offset -00 => UTC', () => { + const localDate = '2023-11-21T04:00:00-00:00'; + const utcDate = localToUtcDate(localDate); + expect(utcDate.toISOString()).equal('2023-11-21T00:00:00.000Z'); + }); + + it('in without offset == UTC', () => { + const localDate = '2023-11-21T04:00:00'; + const utcDate = localToUtcDate(localDate); + expect(utcDate.toISOString()).equal('2023-11-21T04:00:00.000Z'); + }); +}); + +describe('getMonthDaysByWeek()', () => { + it('default starting Week: Sunday', () => { + const dates = getMonthDaysByWeek(new Date(DATE)); + expect(dates).toMatchInlineSnapshot(` + [ + [ + 2023-10-29T04:00:00.000Z, + 2023-10-30T04:00:00.000Z, + 2023-10-31T04:00:00.000Z, + 2023-11-01T04:00:00.000Z, + 2023-11-02T04:00:00.000Z, + 2023-11-03T04:00:00.000Z, + 2023-11-04T04:00:00.000Z, + ], + [ + 2023-11-05T04:00:00.000Z, + 2023-11-06T04:00:00.000Z, + 2023-11-07T04:00:00.000Z, + 2023-11-08T04:00:00.000Z, + 2023-11-09T04:00:00.000Z, + 2023-11-10T04:00:00.000Z, + 2023-11-11T04:00:00.000Z, + ], + [ + 2023-11-12T04:00:00.000Z, + 2023-11-13T04:00:00.000Z, + 2023-11-14T04:00:00.000Z, + 2023-11-15T04:00:00.000Z, + 2023-11-16T04:00:00.000Z, + 2023-11-17T04:00:00.000Z, + 2023-11-18T04:00:00.000Z, + ], + [ + 2023-11-19T04:00:00.000Z, + 2023-11-20T04:00:00.000Z, + 2023-11-21T04:00:00.000Z, + 2023-11-22T04:00:00.000Z, + 2023-11-23T04:00:00.000Z, + 2023-11-24T04:00:00.000Z, + 2023-11-25T04:00:00.000Z, + ], + [ + 2023-11-26T04:00:00.000Z, + 2023-11-27T04:00:00.000Z, + 2023-11-28T04:00:00.000Z, + 2023-11-29T04:00:00.000Z, + 2023-11-30T04:00:00.000Z, + 2023-12-01T04:00:00.000Z, + 2023-12-02T04:00:00.000Z, + ], + ] + `); + }); + + it('Starting Week: Monday', () => { + const dates = getMonthDaysByWeek(new Date(DATE), 1); + expect(dates).toMatchInlineSnapshot(` + [ + [ + 2023-10-30T04:00:00.000Z, + 2023-10-31T04:00:00.000Z, + 2023-11-01T04:00:00.000Z, + 2023-11-02T04:00:00.000Z, + 2023-11-03T04:00:00.000Z, + 2023-11-04T04:00:00.000Z, + 2023-11-05T04:00:00.000Z, + ], + [ + 2023-11-06T04:00:00.000Z, + 2023-11-07T04:00:00.000Z, + 2023-11-08T04:00:00.000Z, + 2023-11-09T04:00:00.000Z, + 2023-11-10T04:00:00.000Z, + 2023-11-11T04:00:00.000Z, + 2023-11-12T04:00:00.000Z, + ], + [ + 2023-11-13T04:00:00.000Z, + 2023-11-14T04:00:00.000Z, + 2023-11-15T04:00:00.000Z, + 2023-11-16T04:00:00.000Z, + 2023-11-17T04:00:00.000Z, + 2023-11-18T04:00:00.000Z, + 2023-11-19T04:00:00.000Z, + ], + [ + 2023-11-20T04:00:00.000Z, + 2023-11-21T04:00:00.000Z, + 2023-11-22T04:00:00.000Z, + 2023-11-23T04:00:00.000Z, + 2023-11-24T04:00:00.000Z, + 2023-11-25T04:00:00.000Z, + 2023-11-26T04:00:00.000Z, + ], + [ + 2023-11-27T04:00:00.000Z, + 2023-11-28T04:00:00.000Z, + 2023-11-29T04:00:00.000Z, + 2023-11-30T04:00:00.000Z, + 2023-12-01T04:00:00.000Z, + 2023-12-02T04:00:00.000Z, + 2023-12-03T04:00:00.000Z, + ], + ] + `); + }); +}); + +describe('getWeekStartsOnFromIntl() tokens', () => { + it('by default, sunday', () => { + const val = getWeekStartsOnFromIntl(); + expect(val).toBe(DayOfWeek.Sunday); + }); + + it('For en it should be synday', () => { + const val = getWeekStartsOnFromIntl('en'); + expect(val).toBe(DayOfWeek.Sunday); + }); + + it('For fr it should be monday', () => { + const val = getWeekStartsOnFromIntl('fr'); + expect(val).toBe(DayOfWeek.Monday); + }); +}); + +describe('getPeriodTypeByCode()', () => { + it('week', () => { + const val = getPeriodTypeByCode('WEEK'); + expect(val).toBe(PeriodType.Week); + }); +}); + +describe('getPeriodTypeCode()', () => { + it('BiWeek1Sat', () => { + const val = getPeriodTypeCode(PeriodType.BiWeek1Sat); + expect(val).toBe('BIWEEK1-SAT'); + }); +}); diff --git a/packages/svelte-ux/src/lib/utils/date.ts b/packages/svelte-ux/src/lib/utils/date.ts index 581354e18..03b69342c 100644 --- a/packages/svelte-ux/src/lib/utils/date.ts +++ b/packages/svelte-ux/src/lib/utils/date.ts @@ -1,5 +1,4 @@ import { - format, startOfDay, endOfDay, startOfWeek, @@ -31,238 +30,166 @@ import { formatISO, } from 'date-fns'; -import { timeDays } from 'd3-time'; - import { hasKeyOf } from '../types/typeGuards'; import { chunk } from './array'; -import type { DateRange } from './dateRange'; - -export type SelectedDate = Date | Date[] | DateRange | null; - -export type Period = { - start: Date; - end: Date; - periodTypeId: PeriodType; -}; - -export enum PeriodType { - Day = 10, - - WeekSun = 20, - WeekMon = 21, - WeekTue = 22, - WeekWed = 23, - WeekThu = 24, - WeekFri = 25, - WeekSat = 26, - - Month = 30, - Quarter = 40, - CalendarYear = 50, - FiscalYearOctober = 60, - - BiWeek1Sun = 70, - BiWeek1Mon = 71, - BiWeek1Tue = 72, - BiWeek1Wed = 73, - BiWeek1Thu = 74, - BiWeek1Fri = 75, - BiWeek1Sat = 76, - - BiWeek2Sun = 80, - BiWeek2Mon = 81, - BiWeek2Tue = 82, - BiWeek2Wed = 83, - BiWeek2Thu = 84, - BiWeek2Fri = 85, - BiWeek2Sat = 86, +import { + PeriodType, + DayOfWeek, + DateToken, + type SelectedDate, + type CustomIntlDateTimeFormatOptions, + type FormatDateOptions, + type DateFormatVariantPreset, +} from './date_types'; +import { defaultLocale, type LocaleSettings } from './locale'; +import { assertNever } from '$lib/types'; + +export * from './date_types'; + +export function getDayOfWeekName(weekStartsOn: DayOfWeek, locales: string) { + // Create a date object for a specific day (0 = Sunday, 1 = Monday, etc.) + // And "7 of Jan 2024" is a Sunday + const date = new Date(2024, 0, 7 + weekStartsOn); + const formatter = new Intl.DateTimeFormat(locales, { weekday: 'short' }); + return formatter.format(date); } -export enum DayOfWeek { - SUN, - MON, - TUE, - WED, - THU, - FRI, - SAT, +export function getPeriodTypeName(periodType: PeriodType) { + return getPeriodTypeNameWithLocale(defaultLocale, periodType); } -export function getPeriodTypeName(periodType: PeriodType) { +export function getPeriodTypeNameWithLocale(settings: LocaleSettings, periodType: PeriodType) { + const { + locale: locale, + dictionary: { Date: dico }, + } = settings; + switch (periodType) { + case PeriodType.Custom: + return 'Custom'; + case PeriodType.Day: - return 'Day'; + return dico.Day; + case PeriodType.DayTime: + return dico.DayTime; + case PeriodType.TimeOnly: + return dico.Time; case PeriodType.WeekSun: - return 'Week (Sun)'; + return `${dico.Week} (${getDayOfWeekName(DayOfWeek.Sunday, locale)})`; case PeriodType.WeekMon: - return 'Week (Mon)'; + return `${dico.Week} (${getDayOfWeekName(1, locale)})`; case PeriodType.WeekTue: - return 'Week (Tue)'; + return `${dico.Week} (${getDayOfWeekName(2, locale)})`; case PeriodType.WeekWed: - return 'Week (Wed)'; + return `${dico.Week} (${getDayOfWeekName(3, locale)})`; case PeriodType.WeekThu: - return 'Week (Thu)'; + return `${dico.Week} (${getDayOfWeekName(4, locale)})`; case PeriodType.WeekFri: - return 'Week (Fri)'; + return `${dico.Week} (${getDayOfWeekName(5, locale)})`; case PeriodType.WeekSat: - return 'Week (Sat)'; + return `${dico.Week} (${getDayOfWeekName(6, locale)})`; + case PeriodType.Week: + return dico.Week; case PeriodType.Month: - return 'Month'; + return dico.Month; + case PeriodType.MonthYear: + return dico.Month; case PeriodType.Quarter: - return 'Quarter'; + return dico.Quarter; case PeriodType.CalendarYear: - return 'Calendar Year'; + return dico.CalendarYear; case PeriodType.FiscalYearOctober: - return 'Fiscal Year (Oct)'; + return dico.FiscalYearOct; case PeriodType.BiWeek1Sun: - return 'Bi-Week (Sun)'; + return `${dico.BiWeek} (${getDayOfWeekName(0, locale)})`; case PeriodType.BiWeek1Mon: - return 'Bi-Week (Mon)'; + return `${dico.BiWeek} (${getDayOfWeekName(1, locale)})`; case PeriodType.BiWeek1Tue: - return 'Bi-Week (Tue)'; + return `${dico.BiWeek} (${getDayOfWeekName(2, locale)})`; case PeriodType.BiWeek1Wed: - return 'Bi-Week (Wed)'; + return `${dico.BiWeek} (${getDayOfWeekName(3, locale)})`; case PeriodType.BiWeek1Thu: - return 'Bi-Week (Thu)'; + return `${dico.BiWeek} (${getDayOfWeekName(4, locale)})`; case PeriodType.BiWeek1Fri: - return 'Bi-Week (Fri)'; + return `${dico.BiWeek} (${getDayOfWeekName(5, locale)})`; case PeriodType.BiWeek1Sat: - return 'Bi-Week (Sat)'; + return `${dico.BiWeek} (${getDayOfWeekName(6, locale)})`; + case PeriodType.BiWeek1: + return dico.BiWeek; case PeriodType.BiWeek2Sun: - return 'Bi-Week 2 (Sun)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(0, locale)})`; case PeriodType.BiWeek2Mon: - return 'Bi-Week 2 (Mon)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(1, locale)})`; case PeriodType.BiWeek2Tue: - return 'Bi-Week 2 (Tue)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(2, locale)})`; case PeriodType.BiWeek2Wed: - return 'Bi-Week 2 (Wed)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(3, locale)})`; case PeriodType.BiWeek2Thu: - return 'Bi-Week 2 (Thu)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(4, locale)})`; case PeriodType.BiWeek2Fri: - return 'Bi-Week 2 (Fri)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(5, locale)})`; case PeriodType.BiWeek2Sat: - return 'Bi-Week 2 (Sat)'; + return `${dico.BiWeek} 2 (${getDayOfWeekName(6, locale)})`; + case PeriodType.BiWeek2: + return `${dico.BiWeek} 2`; default: - return 'Unknown'; + assertNever(periodType); // This will now report unhandled cases } } -export function getPeriodTypeCode(periodType: PeriodType) { - switch (periodType) { - case PeriodType.Day: - return 'DAY'; - - case PeriodType.WeekSun: - return 'WEEK-SUN'; - case PeriodType.WeekMon: - return 'WEEK-MON'; - case PeriodType.WeekTue: - return 'WEEK-TUE'; - case PeriodType.WeekWed: - return 'WEEK-WED'; - case PeriodType.WeekThu: - return 'WEEK-THU'; - case PeriodType.WeekFri: - return 'WEEK-FRI'; - case PeriodType.WeekSat: - return 'WEEK-SAT'; - - case PeriodType.Month: - return 'MTH'; - case PeriodType.Quarter: - return 'QTR'; - case PeriodType.CalendarYear: - return 'CY'; - case PeriodType.FiscalYearOctober: - return 'FY-OCT'; - - case PeriodType.BiWeek1Sun: - return 'BIWEEK1-SUN'; - case PeriodType.BiWeek1Mon: - return 'BIWEEK1-MON'; - case PeriodType.BiWeek1Tue: - return 'BIWEEK1-TUE'; - case PeriodType.BiWeek1Wed: - return 'BIWEEK1-WED'; - case PeriodType.BiWeek1Thu: - return 'BIWEEK1-THU'; - case PeriodType.BiWeek1Fri: - return 'BIWEEK1-FRI'; - case PeriodType.BiWeek1Sat: - return 'BIWEEK1-SAT'; - - case PeriodType.BiWeek2Sun: - return 'BIWEEK2-SUN'; - case PeriodType.BiWeek2Mon: - return 'BIWEEK2-MON'; - case PeriodType.BiWeek2Tue: - return 'BIWEEK2-TUE'; - case PeriodType.BiWeek2Wed: - return 'BIWEEK2-WED'; - case PeriodType.BiWeek2Thu: - return 'BIWEEK2-THU'; - case PeriodType.BiWeek2Fri: - return 'BIWEEK2-FRI'; - case PeriodType.BiWeek2Sat: - return 'BIWEEK2-SAT'; +const periodTypeMappings: Record<PeriodType, string> = { + [PeriodType.Custom]: 'CUSTOM', + + [PeriodType.Day]: 'DAY', + [PeriodType.DayTime]: 'DAY-TIME', + [PeriodType.TimeOnly]: 'TIME', + + [PeriodType.WeekSun]: 'WEEK-SUN', + [PeriodType.WeekMon]: 'WEEK-MON', + [PeriodType.WeekTue]: 'WEEK-TUE', + [PeriodType.WeekWed]: 'WEEK-WED', + [PeriodType.WeekThu]: 'WEEK-THU', + [PeriodType.WeekFri]: 'WEEK-FRI', + [PeriodType.WeekSat]: 'WEEK-SAT', + [PeriodType.Week]: 'WEEK', + + [PeriodType.Month]: 'MTH', + [PeriodType.MonthYear]: 'MTH-CY', + [PeriodType.Quarter]: 'QTR', + [PeriodType.CalendarYear]: 'CY', + [PeriodType.FiscalYearOctober]: 'FY-OCT', + + [PeriodType.BiWeek1Sun]: 'BIWEEK1-SUN', + [PeriodType.BiWeek1Mon]: 'BIWEEK1-MON', + [PeriodType.BiWeek1Tue]: 'BIWEEK1-TUE', + [PeriodType.BiWeek1Wed]: 'BIWEEK1-WED', + [PeriodType.BiWeek1Thu]: 'BIWEEK1-THU', + [PeriodType.BiWeek1Fri]: 'BIWEEK1-FRI', + [PeriodType.BiWeek1Sat]: 'BIWEEK1-SAT', + [PeriodType.BiWeek1]: 'BIWEEK1', + + [PeriodType.BiWeek2Sun]: 'BIWEEK2-SUN', + [PeriodType.BiWeek2Mon]: 'BIWEEK2-MON', + [PeriodType.BiWeek2Tue]: 'BIWEEK2-TUE', + [PeriodType.BiWeek2Wed]: 'BIWEEK2-WED', + [PeriodType.BiWeek2Thu]: 'BIWEEK2-THU', + [PeriodType.BiWeek2Fri]: 'BIWEEK2-FRI', + [PeriodType.BiWeek2Sat]: 'BIWEEK2-SAT', + [PeriodType.BiWeek2]: 'BIWEEK2', +}; - default: - return 'UNK'; - } +export function getPeriodTypeCode(periodType: PeriodType): string { + return periodTypeMappings[periodType]; } -export function getPeriodTypeByCode(code: string) { - switch (code) { - case 'DAY': - return PeriodType.Day; - - case 'WEEK-SUN': - return PeriodType.WeekSun; - case 'WEEK-MON': - return PeriodType.WeekMon; - case 'WEEK-TUE': - return PeriodType.WeekTue; - case 'WEEK-WED': - return PeriodType.WeekWed; - case 'WEEK-THU': - return PeriodType.WeekThu; - case 'WEEK-FRI': - return PeriodType.WeekFri; - case 'WEEK-SAT': - return PeriodType.WeekSat; - - case 'MTH': - return PeriodType.Month; - case 'QTR': - return PeriodType.Quarter; - case 'CY': - return PeriodType.CalendarYear; - case 'FY-OCT': - return PeriodType.FiscalYearOctober; - - case 'BIWEEK1-SUN': - return PeriodType.BiWeek1Sun; - case 'BIWEEK1-MON': - return PeriodType.BiWeek1Mon; - case 'BIWEEK1-TUE': - return PeriodType.BiWeek1Tue; - case 'BIWEEK1-WED': - return PeriodType.BiWeek1Wed; - case 'BIWEEK1-THU': - return PeriodType.BiWeek1Thu; - case 'BIWEEK1-FRI': - return PeriodType.BiWeek1Fri; - case 'BIWEEK1-SAT': - return PeriodType.BiWeek1Sat; - - default: - return null; - } +export function getPeriodTypeByCode(code: string): PeriodType { + const element = Object.entries(periodTypeMappings).find((c) => c[1] === code); + return parseInt(element?.[0] ?? '1'); } export function getDayOfWeek(periodType: PeriodType) { @@ -284,20 +211,43 @@ export function replaceDayOfWeek(periodType: PeriodType, dayOfWeek: DayOfWeek) { } export function hasDayOfWeek(periodType: PeriodType) { - const periodTypeCode = getPeriodTypeCode(periodType); - return /\-(SUN|MON|TUE|WED|THU|FRI|SAT)/.test(periodTypeCode); + // It's more: is it week related and .Week, .BiWeek1 or .BiWeek2 don't contain a day... + // const periodTypeCode = getPeriodTypeCode(periodType); + // return /\-(SUN|MON|TUE|WED|THU|FRI|SAT)/.test(periodTypeCode); + + if (periodType >= PeriodType.WeekSun && periodType <= PeriodType.Week) { + return true; + } + if (periodType >= PeriodType.BiWeek1Sun && periodType <= PeriodType.BiWeek1) { + return true; + } + if (periodType >= PeriodType.BiWeek2Sun && periodType <= PeriodType.BiWeek2) { + return true; + } + + return false; } export function getMonths(year = new Date().getFullYear()) { return Array.from({ length: 12 }, (_, i) => new Date(year, i, 1)); } -export function getMonthDaysByWeek(startOfMonth: Date): Date[][] { - const startOfFirstWeek = startOfWeek(startOfMonth); - const endOfLastWeek = endOfWeek(endOfMonth(startOfMonth)); - const monthDaysByWeek = chunk(timeDays(startOfFirstWeek, endOfLastWeek), 7); +export function getMonthDaysByWeek( + dateInTheMonth: Date, + weekStartsOn: DayOfWeek = DayOfWeek.Sunday +): Date[][] { + const startOfFirstWeek = startOfWeek(startOfMonth(dateInTheMonth), { weekStartsOn }); + const endOfLastWeek = endOfWeek(endOfMonth(dateInTheMonth), { weekStartsOn }); + + const list = []; - return monthDaysByWeek; + let valueToAdd = startOfFirstWeek; + while (valueToAdd <= endOfLastWeek) { + list.push(valueToAdd); + valueToAdd = addDays(valueToAdd, 1); + } + + return chunk(list, 7) as Date[][]; } export function getMinSelectedDate(date: SelectedDate | null | undefined) { @@ -381,7 +331,14 @@ export function endOfBiWeek(date: Date, week: number, startOfWeek: DayOfWeek) { return addDays(startOfBiWeek(date, week, startOfWeek), 13); } -export function getDateFuncsByPeriodType(periodType: PeriodType | null | undefined) { +export function getDateFuncsByPeriodType( + settings: LocaleSettings, + periodType: PeriodType | null | undefined +) { + if (settings) { + periodType = updatePeriodTypeWithWeekStartsOn(settings.formats.dates.weekStartsOn, periodType); + } + switch (periodType) { case PeriodType.Day: return { @@ -392,6 +349,7 @@ export function getDateFuncsByPeriodType(periodType: PeriodType | null | undefin isSame: isSameDay, }; + case PeriodType.Week: case PeriodType.WeekSun: return { start: startOfWeek, @@ -489,6 +447,7 @@ export function getDateFuncsByPeriodType(periodType: PeriodType | null | undefin }; // BiWeek 1 + case PeriodType.BiWeek1: case PeriodType.BiWeek1Sun: case PeriodType.BiWeek1Mon: case PeriodType.BiWeek1Tue: @@ -497,6 +456,7 @@ export function getDateFuncsByPeriodType(periodType: PeriodType | null | undefin case PeriodType.BiWeek1Fri: case PeriodType.BiWeek1Sat: // BiWeek 2 + case PeriodType.BiWeek2: case PeriodType.BiWeek2Sun: case PeriodType.BiWeek2Mon: case PeriodType.BiWeek2Tue: @@ -522,7 +482,14 @@ export function getDateFuncsByPeriodType(periodType: PeriodType | null | undefin }; } - default: + // All cases not handled above + case PeriodType.Custom: + case PeriodType.DayTime: + case PeriodType.TimeOnly: + + case PeriodType.MonthYear: + case null: + case undefined: // Default to end of day if periodType == null, etc return { start: startOfDay, @@ -531,6 +498,9 @@ export function getDateFuncsByPeriodType(periodType: PeriodType | null | undefin difference: differenceInDays, isSame: isSameDay, }; + + default: + assertNever(periodType); // This will now report unhandled cases } } @@ -549,11 +519,182 @@ export function formatISODate( return formatISO(date, { representation }); } +export function formatIntl( + settings: LocaleSettings, + dt: Date, + tokens_or_intlOptions: CustomIntlDateTimeFormatOptions +) { + const { + locale, + formats: { + dates: { ordinalSuffixes: suffixes }, + }, + } = settings; + + function formatIntlOrdinal(formatter: Intl.DateTimeFormat, with_ordinal = false) { + if (with_ordinal) { + const rules = new Intl.PluralRules(locale, { type: 'ordinal' }); + + const splited = formatter.formatToParts(dt); + return splited + .map((c) => { + if (c.type === 'day') { + const ordinal = rules.select(parseInt(c.value, 10)); + const suffix = suffixes[ordinal]; + return `${c.value}${suffix}`; + } + return c.value; + }) + .join(''); + } + + return formatter.format(dt); + } + + if (typeof tokens_or_intlOptions !== 'string' && !Array.isArray(tokens_or_intlOptions)) { + return formatIntlOrdinal( + new Intl.DateTimeFormat(locale, tokens_or_intlOptions), + tokens_or_intlOptions.withOrdinal + ); + } + + const tokens = Array.isArray(tokens_or_intlOptions) + ? tokens_or_intlOptions.join('') + : tokens_or_intlOptions; + + // Order of includes check is important! (longest first) + const formatter = new Intl.DateTimeFormat(locale, { + year: tokens.includes(DateToken.Year_numeric) + ? 'numeric' + : tokens.includes(DateToken.Year_2Digit) + ? '2-digit' + : undefined, + + month: tokens.includes(DateToken.Month_long) + ? 'long' + : tokens.includes(DateToken.Month_short) + ? 'short' + : tokens.includes(DateToken.Month_2Digit) + ? '2-digit' + : tokens.includes(DateToken.Month_numeric) + ? 'numeric' + : undefined, + + day: tokens.includes(DateToken.DayOfMonth_2Digit) + ? '2-digit' + : tokens.includes(DateToken.DayOfMonth_numeric) + ? 'numeric' + : undefined, + + hour: tokens.includes(DateToken.Hour_2Digit) + ? '2-digit' + : tokens.includes(DateToken.Hour_numeric) + ? 'numeric' + : undefined, + hour12: tokens.includes(DateToken.Hour_woAMPM) + ? false + : tokens.includes(DateToken.Hour_wAMPM) + ? true + : undefined, + + minute: tokens.includes(DateToken.Minute_2Digit) + ? '2-digit' + : tokens.includes(DateToken.Minute_numeric) + ? 'numeric' + : undefined, + + second: tokens.includes(DateToken.Second_2Digit) + ? '2-digit' + : tokens.includes(DateToken.Second_numeric) + ? 'numeric' + : undefined, + + fractionalSecondDigits: tokens.includes(DateToken.MiliSecond_3) ? 3 : undefined, + + weekday: tokens.includes(DateToken.DayOfWeek_narrow) + ? 'narrow' + : tokens.includes(DateToken.DayOfWeek_long) + ? 'long' + : tokens.includes(DateToken.DayOfWeek_short) + ? 'short' + : undefined, + }); + + return formatIntlOrdinal(formatter, tokens.includes(DateToken.DayOfMonth_withOrdinal)); +} + +function range( + settings: LocaleSettings, + date: Date, + weekStartsOn: DayOfWeek, + formatToUse: CustomIntlDateTimeFormatOptions, + biWeek: undefined | 1 | 2 = undefined // undefined means that it's not a bi-week +) { + const start = + biWeek === undefined + ? startOfWeek(date, { weekStartsOn }) + : startOfBiWeek(date, biWeek, weekStartsOn); + const end = + biWeek === undefined + ? endOfWeek(date, { weekStartsOn }) + : endOfBiWeek(date, biWeek, weekStartsOn); + + return formatIntl(settings, start, formatToUse) + ' - ' + formatIntl(settings, end, formatToUse); +} + export function formatDate( date: Date | string | null | undefined, - periodType?: PeriodType | null | undefined, - variant?: 'short' | 'long' // TODO: Support x-long, etc (maybe call it sm, md, lg, xl, etc) + periodType: PeriodType, + options: FormatDateOptions = {} +): string { + return formatDateWithLocale(defaultLocale, date, periodType, options); +} + +export function updatePeriodTypeWithWeekStartsOn( + weekStartsOn: DayOfWeek, + periodType: PeriodType | null | undefined ) { + if (periodType === PeriodType.Week) { + periodType = [ + PeriodType.WeekSun, + PeriodType.WeekMon, + PeriodType.WeekTue, + PeriodType.WeekWed, + PeriodType.WeekThu, + PeriodType.WeekFri, + PeriodType.WeekSat, + ][weekStartsOn]; + } else if (periodType === PeriodType.BiWeek1) { + periodType = [ + PeriodType.BiWeek1Sun, + PeriodType.BiWeek1Mon, + PeriodType.BiWeek1Tue, + PeriodType.BiWeek1Wed, + PeriodType.BiWeek1Thu, + PeriodType.BiWeek1Fri, + PeriodType.BiWeek1Sat, + ][weekStartsOn]; + } else if (periodType === PeriodType.BiWeek2) { + periodType = [ + PeriodType.BiWeek2Sun, + PeriodType.BiWeek2Mon, + PeriodType.BiWeek2Tue, + PeriodType.BiWeek2Wed, + PeriodType.BiWeek2Thu, + PeriodType.BiWeek2Fri, + PeriodType.BiWeek2Sat, + ][weekStartsOn]; + } + + return periodType; +} + +export function formatDateWithLocale( + settings: LocaleSettings, + date: Date | string | null | undefined, + periodType: PeriodType, + options: FormatDateOptions = {} +): string { if (typeof date === 'string') { date = parseISO(date); } @@ -564,51 +705,107 @@ export function formatDate( return ''; } + const weekStartsOn = options.weekStartsOn ?? settings.formats.dates.weekStartsOn; + + const { day, dayTime, timeOnly, week, month, monthsYear, year } = settings.formats.dates.presets; + + periodType = updatePeriodTypeWithWeekStartsOn(weekStartsOn, periodType) ?? periodType; + + /** Resolve a preset given the chosen variant */ + function rv(preset: DateFormatVariantPreset) { + if (options.variant === 'custom') { + return options.custom ?? preset.default; + } else if (options.custom && !options.variant) { + return options.custom; + } + + return preset[options.variant ?? 'default']; + } + switch (periodType) { + case PeriodType.Custom: + return formatIntl(settings, date, options.custom!); + case PeriodType.Day: - return variant === 'short' ? format(date, 'M/d') : format(date, 'MMM d, yyyy'); + return formatIntl(settings, date, rv(day!)!); + case PeriodType.DayTime: + return formatIntl(settings, date, rv(dayTime!)!); + + case PeriodType.TimeOnly: + return formatIntl(settings, date, rv(timeOnly!)!); + + case PeriodType.Week: //Should never happen, but to make types happy case PeriodType.WeekSun: + return range(settings, date, 0, rv(week!)!); case PeriodType.WeekMon: + return range(settings, date, 1, rv(week!)!); case PeriodType.WeekTue: + return range(settings, date, 2, rv(week!)!); case PeriodType.WeekWed: + return range(settings, date, 3, rv(week!)!); case PeriodType.WeekThu: + return range(settings, date, 4, rv(week!)!); case PeriodType.WeekFri: + return range(settings, date, 5, rv(week!)!); case PeriodType.WeekSat: - return variant === 'short' - ? format(date, 'M/d') + ' - ' + format(addDays(date, 6), 'M/d') - : format(date, 'M/d/yyyy') + ' - ' + format(addDays(date, 6), 'M/d/yyyy'); + return range(settings, date, 6, rv(week!)!); case PeriodType.Month: - return variant === 'short' ? format(date, 'MMM yyyy') : format(date, 'MMMM yyyy'); + return formatIntl(settings, date, rv(month!)!); + + case PeriodType.MonthYear: + return formatIntl(settings, date, rv(monthsYear!)!); + case PeriodType.Quarter: - return variant === 'short' - ? format(date, 'MMM') + ' - ' + format(addMonths(date, 2), 'MMM yyyy') - : format(date, 'MMMM') + ' - ' + format(addMonths(date, 2), 'MMMM yyyy'); + return [ + formatIntl(settings, startOfQuarter(date), rv(month!)!), + formatIntl(settings, endOfQuarter(date), rv(monthsYear!)!), + ].join(' - '); + case PeriodType.CalendarYear: - return variant === 'short' ? format(date, 'yy') : format(date, 'yyyy'); + return formatIntl(settings, date, rv(year!)!); + case PeriodType.FiscalYearOctober: - return variant === 'short' ? `${getFiscalYear(date)}`.substring(2) : `${getFiscalYear(date)}`; + const fDate = new Date(getFiscalYear(date), 0, 1); + return formatIntl(settings, fDate, rv(year!)!); + case PeriodType.BiWeek1: //Should never happen, but to make types happy case PeriodType.BiWeek1Sun: + return range(settings, date, 0, rv(week!)!, 1); case PeriodType.BiWeek1Mon: + return range(settings, date, 1, rv(week!)!, 1); case PeriodType.BiWeek1Tue: + return range(settings, date, 2, rv(week!)!, 1); case PeriodType.BiWeek1Wed: + return range(settings, date, 3, rv(week!)!, 1); case PeriodType.BiWeek1Thu: + return range(settings, date, 4, rv(week!)!, 1); case PeriodType.BiWeek1Fri: + return range(settings, date, 5, rv(week!)!, 1); case PeriodType.BiWeek1Sat: + return range(settings, date, 6, rv(week!)!, 1); + + case PeriodType.BiWeek2: //Should never happen, but to make types happy case PeriodType.BiWeek2Sun: + return range(settings, date, 0, rv(week!)!, 2); case PeriodType.BiWeek2Mon: + return range(settings, date, 1, rv(week!)!, 2); case PeriodType.BiWeek2Tue: + return range(settings, date, 2, rv(week!)!, 2); case PeriodType.BiWeek2Wed: + return range(settings, date, 3, rv(week!)!, 2); case PeriodType.BiWeek2Thu: + return range(settings, date, 4, rv(week!)!, 2); case PeriodType.BiWeek2Fri: + return range(settings, date, 5, rv(week!)!, 2); case PeriodType.BiWeek2Sat: - return variant === 'short' - ? format(date, 'M/d') + ' - ' + format(addDays(date, 13), 'M/d') - : format(date, 'M/d/yyyy') + ' - ' + format(addDays(date, 13), 'M/d/yyyy'); + return range(settings, date, 6, rv(week!)!, 2); + default: return formatISO(date); + // default: + // assertNever(periodType); // This will now report unhandled cases } } @@ -620,9 +817,6 @@ export function utcToLocalDate(date: Date | string | null | undefined) { // https://github.com/date-fns/date-fns/issues/376#issuecomment-454163253 // return new Date(date.getTime() + date.getTimezoneOffset() * 60 * 1000); - - // This approach seems to work more reliably with dates before 11/18/1883 @ 12:00 - // https://github.com/d3/d3-time/issues/29#issuecomment-396415951 const d = new Date( date.getUTCFullYear(), date.getUTCMonth(), diff --git a/packages/svelte-ux/src/lib/utils/dateDisplay.ts b/packages/svelte-ux/src/lib/utils/dateDisplay.ts deleted file mode 100644 index 6ca714f8b..000000000 --- a/packages/svelte-ux/src/lib/utils/dateDisplay.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { format as dateFormat } from 'date-fns'; -import { formatDate, utcToLocalDate, PeriodType } from './date'; - -export type DateDisplayOptions = { - periodType?: PeriodType | null; - variant?: Parameters<typeof formatDate>[2]; - format?: string; - utc?: boolean; -}; - -export function dateDisplay( - value: Date | string | number | null | undefined, - options?: DateDisplayOptions -) { - let date = value != null ? (value instanceof Date ? value : new Date(value)) : null; - - // Offset for UTC - if (options?.utc) { - date = utcToLocalDate(date); - } - - let formattedDate = ''; - if (date) { - if (options?.format) { - formattedDate = dateFormat(date, options?.format); - } else if (options?.periodType) { - formattedDate = formatDate(date, options?.periodType, options?.variant); - } else { - formattedDate = date.toLocaleString(); - } - } - - return formattedDate; -} diff --git a/packages/svelte-ux/src/lib/utils/dateInternal.ts b/packages/svelte-ux/src/lib/utils/dateInternal.ts new file mode 100644 index 000000000..4dafad8b1 --- /dev/null +++ b/packages/svelte-ux/src/lib/utils/dateInternal.ts @@ -0,0 +1,11 @@ +import { DayOfWeek } from './date_types'; + +export function getWeekStartsOnFromIntl(locales?: string): DayOfWeek { + if (!locales) { + return DayOfWeek.Sunday; + } + + const info = new Intl.Locale(locales); + // @ts-ignore + return (info.weekInfo.firstDay ?? 0) % 7; // (in Intl, sunday is 7 not 0, so we need to mod 7) +} diff --git a/packages/svelte-ux/src/lib/utils/dateRange.ts b/packages/svelte-ux/src/lib/utils/dateRange.ts index 624e537bb..cde3271af 100644 --- a/packages/svelte-ux/src/lib/utils/dateRange.ts +++ b/packages/svelte-ux/src/lib/utils/dateRange.ts @@ -1,6 +1,8 @@ import { startOfDay, isLeapYear, isAfter, isBefore, subYears } from 'date-fns'; -import { getDateFuncsByPeriodType, PeriodType } from './date'; +import { getDateFuncsByPeriodType, updatePeriodTypeWithWeekStartsOn } from './date'; +import { PeriodType } from './date_types'; +import type { LocaleSettings } from '.'; export type DateRange = { from: Date | null; @@ -8,90 +10,54 @@ export type DateRange = { periodType?: PeriodType | null; }; -export const dayPresets = getDateRangePresets(PeriodType.Day); -export const biWeekSun1Presets = getDateRangePresets(PeriodType.BiWeek1Sun); -export const biWeekMon1Presets = getDateRangePresets(PeriodType.BiWeek1Mon); -export const monthPresets = getDateRangePresets(PeriodType.Month); -export const quarterPresets = getDateRangePresets(PeriodType.Quarter); -export const fiscalYearPresets = getDateRangePresets(PeriodType.FiscalYearOctober); - -const now = new Date(); +function formatMsg( + settings: LocaleSettings, + type: + | 'PeriodDay' + | 'PeriodWeek' + | 'PeriodBiWeek' + | 'PeriodMonth' + | 'PeriodQuarter' + | 'PeriodYear' + | 'PeriodFiscalYear', + lastX: number +) { + return lastX === 0 + ? settings.dictionary.Date[type].Current + : lastX === 1 + ? settings.dictionary.Date[type].Last + : settings.dictionary.Date[type].LastX.replace('{0}', lastX.toString()); +} -export function getDateRangePresets(periodType: PeriodType): { label: string; value: DateRange }[] { +export function getDateRangePresets( + settings: LocaleSettings, + periodType: PeriodType +): { label: string; value: DateRange }[] { let now = new Date(); const today = startOfDay(now); - const { start, end, add } = getDateFuncsByPeriodType(periodType); + + if (settings) { + periodType = + updatePeriodTypeWithWeekStartsOn(settings.formats.dates.weekStartsOn, periodType) ?? + periodType; + } + + const { start, end, add } = getDateFuncsByPeriodType(settings, periodType); switch (periodType) { case PeriodType.Day: { - const yesterday = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Today', // Current Day - value: { - from: today, - to: end(today), - periodType, - }, - }, - { - label: 'Yesterday', // Last Day - value: { - from: yesterday, - to: end(yesterday), - periodType, - }, - }, - { - label: 'Last 3 days', + return [0, 1, 3, 7, 14, 30].map((lastX) => { + return { + label: formatMsg(settings, 'PeriodDay', lastX), value: { - from: add(yesterday, -2), - to: end(yesterday), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - { - label: 'Last 7 days', - value: { - from: add(yesterday, -6), - to: end(yesterday), - periodType, - }, - }, - { - label: 'Last 14 days', - value: { - from: add(yesterday, -13), - to: end(yesterday), - periodType, - }, - }, - { - label: 'Last 30 days', - value: { - from: add(yesterday, -29), - to: end(yesterday), - periodType, - }, - }, - // { - // label: 'Last 60 days', - // value: { - // from: add(yesterday, -59), - // to: end(yesterday), - // periodType, - // }, - // }, - // { - // label: 'Last 90 days', - // value: { - // from: add(yesterday, -89), - // to: end(yesterday), - // periodType, - // }, - // }, - ]; + }; + }); } case PeriodType.WeekSun: @@ -101,50 +67,18 @@ export function getDateRangePresets(periodType: PeriodType): { label: string; va case PeriodType.WeekThu: case PeriodType.WeekFri: case PeriodType.WeekSat: { - const lastWeek = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Current week', // Week to Date - value: { - from: start(today), - to: end(today), - periodType, - }, - }, - { - label: 'Last week', // Week to Date - value: { - from: lastWeek, - to: end(lastWeek), - periodType, - }, - }, - { - label: 'Last 2 weeks', - value: { - from: start(add(lastWeek, -1)), - to: end(lastWeek), - periodType, - }, - }, - { - label: 'Last 4 weeks', - value: { - from: start(add(lastWeek, -3)), - to: end(lastWeek), - periodType, - }, - }, - { - label: 'Last 6 weeks', + return [0, 1, 2, 4, 6].map((lastX) => { + return { + label: formatMsg(settings, 'PeriodWeek', lastX), value: { - from: start(add(lastWeek, -5)), - to: end(lastWeek), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - ]; + }; + }); } case PeriodType.BiWeek1Sun: @@ -161,222 +95,90 @@ export function getDateRangePresets(periodType: PeriodType): { label: string; va case PeriodType.BiWeek2Thu: case PeriodType.BiWeek2Fri: case PeriodType.BiWeek2Sat: { - const lastBiWeek = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Current bi-week', - value: { - from: start(today), - to: end(today), - periodType, - }, - }, - { - label: 'Last bi-week', - value: { - from: lastBiWeek, - to: end(lastBiWeek), - periodType, - }, - }, - { - label: 'Last 2 bi-weeks', - value: { - from: start(add(lastBiWeek, -1)), - to: end(lastBiWeek), - periodType, - }, - }, - { - label: 'Last 4 bi-weeks', - value: { - from: start(add(lastBiWeek, -3)), - to: end(lastBiWeek), - periodType, - }, - }, - { - label: 'Last 6 bi-weeks', + return [0, 1, 2, 4, 6].map((lastX) => { + return { + label: formatMsg(settings, 'PeriodBiWeek', lastX), value: { - from: start(add(lastBiWeek, -5)), - to: end(lastBiWeek), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - ]; + }; + }); } case PeriodType.Month: { - const lastMonth = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Current month', // Month to Date + return [0, 1, 2, 3, 6, 12].map((lastX) => { + return { + label: formatMsg(settings, 'PeriodMonth', lastX), value: { - from: start(today), - to: end(today), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - { - label: 'Last month', - value: { - from: lastMonth, - to: end(lastMonth), - periodType, - }, - }, - { - label: 'Last 3 months', - value: { - from: start(add(lastMonth, -2)), - to: end(lastMonth), - periodType, - }, - }, - { - label: 'Last 6 months', - value: { - from: start(add(lastMonth, -5)), - to: end(lastMonth), - periodType, - }, - }, - { - label: 'Last 12 months', - value: { - from: start(add(lastMonth, -11)), - to: end(lastMonth), - periodType, - }, - }, - ]; + }; + }); } case PeriodType.Quarter: { - const lastQuarter = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Current quarter', // Quarter to Date - value: { - from: start(today), - to: end(today), - periodType, - }, - }, - { - label: 'Last quarter', - value: { - from: lastQuarter, - to: end(lastQuarter), - periodType, - }, - }, - { - label: 'Same quarter, last year', - value: { - from: start(add(today, -4)), - to: end(add(today, -4)), - periodType, - }, - }, - { - label: 'Last 4 quarters', - value: { - from: start(add(lastQuarter, -3)), - to: end(lastQuarter), - periodType, - }, - }, - { - label: 'Last 3 years', + return [0, 1, -1, 4, 12].map((lastX) => { + // Special thing + if (lastX === -1) { + return { + label: settings.dictionary.Date.PeriodQuarterSameLastyear, + value: { + from: start(add(today, -4)), + to: end(add(today, -4)), + periodType, + }, + }; + } + + return { + label: formatMsg(settings, 'PeriodQuarter', lastX), value: { - from: start(add(lastQuarter, -11)), - to: end(lastQuarter), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - ]; + }; + }); } case PeriodType.CalendarYear: { - const lastYear = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Current year', // Year to Date - value: { - from: start(today), - to: end(today), - periodType, - }, - }, - { - label: 'Last year', - value: { - from: lastYear, - to: end(lastYear), - periodType, - }, - }, - { - label: 'Last 3 years', - value: { - from: start(add(lastYear, -2)), - to: end(lastYear), - periodType, - }, - }, - { - label: 'Last 5 years', + return [0, 1, 3, 5].map((lastX) => { + return { + label: formatMsg(settings, 'PeriodYear', lastX), value: { - from: start(add(lastYear, -4)), - to: end(lastYear), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - ]; + }; + }); } case PeriodType.FiscalYearOctober: { - const lastFiscalYear = start(add(today, -1)); + const last = start(add(today, -1)); - return [ - { - label: 'Current fiscal year', // Fiscal Year to Date - value: { - from: start(today), - to: end(today), - periodType, - }, - }, - { - label: 'Last fiscal year', - value: { - from: lastFiscalYear, - to: end(lastFiscalYear), - periodType, - }, - }, - { - label: 'Last 3 years', - value: { - from: start(add(lastFiscalYear, -2)), - to: end(lastFiscalYear), - periodType, - }, - }, - { - label: 'Last 5 years', + return [0, 1, 3, 5].map((lastX) => { + return { + label: formatMsg(settings, 'PeriodFiscalYear', lastX), value: { - from: start(add(lastFiscalYear, -4)), - to: end(lastFiscalYear), + from: add(last, -lastX + 1), + to: lastX === 0 ? end(today) : end(last), periodType, }, - }, - ]; + }; + }); } default: { @@ -455,14 +257,18 @@ export function getPreviousYearPeriodOffset( export type PeriodComparison = 'prevPeriod' | 'prevYear' | 'fiftyTwoWeeksAgo'; -export function getPeriodComparisonOffset(view: PeriodComparison, period: DateRange | undefined) { +export function getPeriodComparisonOffset( + settings: LocaleSettings, + view: PeriodComparison, + period: DateRange | undefined +) { if (period == null || period.from == null || period.to == null || period.periodType == null) { throw new Error('Period must be defined to calculate offset'); } switch (view) { case 'prevPeriod': - const dateFuncs = getDateFuncsByPeriodType(period.periodType); + const dateFuncs = getDateFuncsByPeriodType(settings, period.periodType); return dateFuncs.difference(period.from, period.to) - 1; // Difference counts full days, need additoinal offset case 'prevYear': diff --git a/packages/svelte-ux/src/lib/utils/date_types.ts b/packages/svelte-ux/src/lib/utils/date_types.ts new file mode 100644 index 000000000..b0c6d1be5 --- /dev/null +++ b/packages/svelte-ux/src/lib/utils/date_types.ts @@ -0,0 +1,154 @@ +import type { DateRange } from './dateRange'; + +export type SelectedDate = Date | Date[] | DateRange | null; + +export type Period = { + start: Date; + end: Date; + periodTypeId: PeriodType; +}; + +export enum PeriodType { + Custom = 1, + + Day = 10, + DayTime = 11, + TimeOnly = 15, + + WeekSun = 20, + WeekMon = 21, + WeekTue = 22, + WeekWed = 23, + WeekThu = 24, + WeekFri = 25, + WeekSat = 26, + Week = 27, // will be replaced by WeekSun, WeekMon, etc depending on weekStartsOn + + Month = 30, + MonthYear = 31, + Quarter = 40, + CalendarYear = 50, + FiscalYearOctober = 60, + + BiWeek1Sun = 70, + BiWeek1Mon = 71, + BiWeek1Tue = 72, + BiWeek1Wed = 73, + BiWeek1Thu = 74, + BiWeek1Fri = 75, + BiWeek1Sat = 76, + BiWeek1 = 77, // will be replaced by BiWeek1Sun, BiWeek1Mon, etc depending on weekStartsOn + + BiWeek2Sun = 80, + BiWeek2Mon = 81, + BiWeek2Tue = 82, + BiWeek2Wed = 83, + BiWeek2Thu = 84, + BiWeek2Fri = 85, + BiWeek2Sat = 86, + BiWeek2 = 87, // will be replaced by BiWeek2Sun, BiWeek2Mon, etc depending on weekStartsOn +} + +export enum DayOfWeek { + Sunday = 0, + Monday = 1, + Tuesday = 2, + Wednesday = 3, + Thursday = 4, + Friday = 5, + Saturday = 6, +} + +export enum DateToken { + /** `1982, 1986, 2024` */ + Year_numeric = 'yyy', + /** `82, 86, 24` */ + Year_2Digit = 'yy', + + /** `January, February, ..., December` */ + Month_long = 'MMMM', + /** `Jan, Feb, ..., Dec` */ + Month_short = 'MMM', + /** `01, 02, ..., 12` */ + Month_2Digit = 'MM', + /** `1, 2, ..., 12` */ + Month_numeric = 'M', + + /** `1, 2, ..., 11, 12` */ + Hour_numeric = 'h', + /** `01, 02, ..., 11, 12` */ + Hour_2Digit = 'hh', + /** You should probably not use this. Force with AM/PM (and the good locale), not specifying this will automatically take the good local */ + Hour_wAMPM = 'a', + /** You should probably not use this. Force without AM/PM (and the good locale), not specifying this will automatically take the good local */ + Hour_woAMPM = 'aaaaaa', + + /** `0, 1, ..., 59` */ + Minute_numeric = 'm', + /** `00, 01, ..., 59` */ + Minute_2Digit = 'mm', + + /** `0, 1, ..., 59` */ + Second_numeric = 's', + /** `00, 01, ..., 59` */ + Second_2Digit = 'ss', + + /** `000, 001, ..., 999` */ + MiliSecond_3 = 'SSS', + + /** Minimize digit: `1, 2, 11, ...` */ + DayOfMonth_numeric = 'd', + /** `01, 02, 11, ...` */ + DayOfMonth_2Digit = 'dd', + /** `1st, 2nd, 11th, ...` You can have your local ordinal by passing `ordinalSuffixes` in options / settings */ + DayOfMonth_withOrdinal = 'do', + + /** `M, T, W, T, F, S, S` */ + DayOfWeek_narrow = 'eeeee', + /** `Monday, Tuesday, ..., Sunday` */ + DayOfWeek_long = 'eeee', + /** `Mon, Tue, Wed, ..., Sun` */ + DayOfWeek_short = 'eee', +} + +export type OrdinalSuffixes = { + one?: string; + two?: string; + few?: string; + other?: string; + zero?: string; + many?: string; +}; +export type DateFormatVariant = 'short' | 'default' | 'long'; +export type DateFormatVariantPreset = { + short?: CustomIntlDateTimeFormatOptions; + default?: CustomIntlDateTimeFormatOptions; + long?: CustomIntlDateTimeFormatOptions; +}; +export type CustomIntlDateTimeFormatOptions = + | string + | string[] + | (Intl.DateTimeFormatOptions & { withOrdinal?: boolean }); + +export type FormatDateOptions = { + weekStartsOn?: DayOfWeek; + variant?: DateFormatVariant | 'custom'; + custom?: CustomIntlDateTimeFormatOptions; +}; + +export interface FormatDateLocaleOptions { + weekStartsOn?: DayOfWeek; + baseParsing?: string; + presets?: { + day?: DateFormatVariantPreset; + dayTime?: DateFormatVariantPreset; + timeOnly?: DateFormatVariantPreset; + week?: DateFormatVariantPreset; + month?: DateFormatVariantPreset; + monthsYear?: DateFormatVariantPreset; + year?: DateFormatVariantPreset; + }; + ordinalSuffixes?: OrdinalSuffixes; +} + +export type FormatDateLocalePresets = Required<FormatDateLocaleOptions>; diff --git a/packages/svelte-ux/src/lib/utils/dictionary.ts b/packages/svelte-ux/src/lib/utils/dictionary.ts new file mode 100644 index 000000000..614d024f4 --- /dev/null +++ b/packages/svelte-ux/src/lib/utils/dictionary.ts @@ -0,0 +1,41 @@ +export type DictionaryMessagesOptions = { + Ok?: string; + Cancel?: string; + + Date?: { + Start?: string; + End?: string; + Empty?: string; + + Day?: string; + DayTime?: string; + Time?: string; + Week?: string; + BiWeek?: string; + Month?: string; + Quarter?: string; + CalendarYear?: string; + FiscalYearOct?: string; + + PeriodDay?: PeriodDayMsg; + PeriodWeek?: PeriodDayMsg; + PeriodBiWeek?: PeriodDayMsg; + PeriodMonth?: PeriodDayMsg; + PeriodQuarter?: PeriodDayMsg; + PeriodQuarterSameLastyear?: string; + PeriodYear?: PeriodDayMsg; + PeriodFiscalYear?: PeriodDayMsg; + }; +}; + +export type PeriodDayMsg = { + Current?: string; + Last?: string; + LastX?: string; +}; + +type DeepRequired<T> = Required<{ + [K in keyof T]: T[K] extends Required<T[K]> ? Required<T[K]> : DeepRequired<T[K]>; +}>; + +export type DictionaryMessages = DeepRequired<DictionaryMessagesOptions>; diff --git a/packages/svelte-ux/src/lib/utils/format.ts b/packages/svelte-ux/src/lib/utils/format.ts index e066c986c..97246eaa1 100644 --- a/packages/svelte-ux/src/lib/utils/format.ts +++ b/packages/svelte-ux/src/lib/utils/format.ts @@ -1,43 +1,93 @@ -import { isFunction } from 'lodash-es'; - -import { formatDate, PeriodType } from './date'; -import { formatNumber } from './number'; +import { formatDateWithLocale, getPeriodTypeNameWithLocale, getDayOfWeekName } from './date'; +import { formatNumberWithLocale } from './number'; import type { FormatNumberOptions, FormatNumberStyle } from './number'; +import { defaultLocale, type LocaleSettings } from './locale'; +import { PeriodType, type FormatDateOptions, DayOfWeek } from './date_types'; -export type FormatType = - | FormatNumberStyle - | PeriodType - | ((value: any, ...extraArgs: any[]) => any); +export type FormatType = FormatNumberStyle | PeriodType; /** * Generic format which can handle Dates, Numbers, or custom format function */ +export function format(value: null | undefined, format?: FormatNumberStyle | PeriodType): string; export function format( - value: null | undefined, + value: number, format?: FormatNumberStyle, - extraFuncArgs?: FormatNumberOptions + options?: FormatNumberOptions ): string; export function format( - value: number, - format?: FormatNumberStyle, - extraFuncArgs?: FormatNumberOptions + value: string | Date, + format?: PeriodType, + options?: FormatDateOptions ): string; -export function format(value: string | Date, format?: PeriodType, ...extraFuncArgs: any[]): string; -export function format(value: any, format?: FormatType, ...extraFuncArgs: any[]): any { - let formattedValue = value ?? ''; // Do not render `null` +export function format( + value: any, + format?: FormatType, + options?: FormatNumberOptions | FormatDateOptions +): any { + return formatWithLocale(defaultLocale, value, format, options); +} + +export function formatWithLocale( + settings: LocaleSettings, + value: any, + format?: FormatType, + options?: FormatNumberOptions | FormatDateOptions +) { + let formattedValue: string | undefined; if (format) { - if (isFunction(format)) { - formattedValue = format(value, ...extraFuncArgs); - } else if (format in PeriodType) { - formattedValue = formatDate(value, format as PeriodType, ...extraFuncArgs); + if (format in PeriodType) { + formattedValue = formatDateWithLocale( + settings, + value, + format as PeriodType, + options as FormatDateOptions + ); } else if (typeof value === 'number') { - formattedValue = formatNumber(value, { - style: format, - ...extraFuncArgs[0], - }); + formattedValue = formatNumberWithLocale( + settings, + value, + format as FormatNumberStyle, + options as FormatNumberOptions + ); } } return formattedValue ?? ''; // return empty string so Svelte doesn't render `null` string; } + +export type FormatFunction = (( + value: number | null | undefined, + style: FormatNumberStyle, + options?: FormatNumberOptions +) => string) & + (( + value: Date | string | null | undefined, + period: PeriodType, + options?: FormatDateOptions + ) => string); + +export interface FormatFunctionProperties { + getPeriodTypeName: (period: PeriodType) => string; + getDayOfWeekName: (day: DayOfWeek) => string; + settings: LocaleSettings; +} + +export type FormatFunctions = FormatFunction & FormatFunctionProperties; + +export function buildFormatters(settings: LocaleSettings): FormatFunctions { + const mainFormat = ( + value: any, + style: FormatNumberStyle | PeriodType, + options?: FormatNumberOptions | FormatDateOptions + ) => formatWithLocale(settings, value, style, options); + + mainFormat.settings = settings; + + mainFormat.getDayOfWeekName = (day: DayOfWeek) => getDayOfWeekName(day, settings.locale); + mainFormat.getPeriodTypeName = (period: PeriodType) => + getPeriodTypeNameWithLocale(settings, period); + + return mainFormat; +} diff --git a/packages/svelte-ux/src/lib/utils/index.ts b/packages/svelte-ux/src/lib/utils/index.ts index 991bf1d6a..ca6a767f1 100644 --- a/packages/svelte-ux/src/lib/utils/index.ts +++ b/packages/svelte-ux/src/lib/utils/index.ts @@ -1,9 +1,15 @@ // top-level exports -export { formatDate, PeriodType } from './date'; -export * from './dateDisplay'; +export { formatDate } from './date'; +export { PeriodType, DayOfWeek, DateToken } from './date_types'; export * from './duration'; export * from './file'; -export * from './format'; +export { + format, + formatWithLocale, + type FormatFunction, + type FormatFunctionProperties, + type FormatFunctions, +} from './format'; export * from './json'; export * from './logger'; export { round, clamp } from './number'; @@ -18,6 +24,15 @@ export * as date from './date'; export * as dateRange from './dateRange'; export * as dom from './dom'; export * as env from './env'; +export { + defaultLocale, + createLocaleSettings, + type LocaleStore, + type LocaleSettings, + type LocaleSettingsInput, + type NumberPresets, + type NumberPresetsOptions, +} from './locale'; // export * as excel from './excel'; // Remove until `await import('exceljs')` works externally export * as map from './map'; export * as number from './number'; diff --git a/packages/svelte-ux/src/lib/utils/locale.ts b/packages/svelte-ux/src/lib/utils/locale.ts new file mode 100644 index 000000000..450a6440c --- /dev/null +++ b/packages/svelte-ux/src/lib/utils/locale.ts @@ -0,0 +1,262 @@ +import type { Prettify } from '$lib/types/typeHelpers'; +import { defaultsDeep } from 'lodash-es'; +import { derived, writable, type Readable, type Writable } from 'svelte/store'; +import { + DateToken, + DayOfWeek, + type FormatDateLocaleOptions, + type FormatDateLocalePresets, +} from './date_types'; +import type { DictionaryMessages, DictionaryMessagesOptions } from './dictionary'; +import type { FormatNumberOptions, FormatNumberStyle } from './number'; +import { getWeekStartsOnFromIntl } from './dateInternal'; + +function resolvedLocaleStore( + forceLocales: Writable<string | string[] | null>, + fallbackLocale?: string +) { + return derived(forceLocales, ($forceLocales) => { + let result: string | undefined; + if ($forceLocales?.length) { + if (Array.isArray($forceLocales)) { + result = $forceLocales[0]; + } else { + result = $forceLocales; + } + } + + return result ?? fallbackLocale ?? 'en'; + }); +} + +export interface LocaleStore extends Readable<string> { + set(value: string | null): void; +} + +export function localeStore(forceLocale: string | undefined, fallbackLocale?: string): LocaleStore { + let currentLocale = writable(forceLocale ?? null); + let resolvedLocale = resolvedLocaleStore(currentLocale, fallbackLocale); + return { + ...resolvedLocale, + set(value: string | null) { + currentLocale.set(value); + }, + }; +} + +type ExcludeNone<T> = T extends 'none' ? never : T; + +export type NumberPresetsOptions = Prettify< + { + defaults?: FormatNumberOptions; + } & { + [key in ExcludeNone<FormatNumberStyle>]?: FormatNumberOptions; + } +>; +export type NumberPresets = Prettify< + { + defaults: FormatNumberOptions; + } & { + [key in ExcludeNone<FormatNumberStyle>]?: FormatNumberOptions; + } +>; + +export interface LocaleSettingsInput { + locale: string; + formats?: { + numbers?: NumberPresetsOptions; + dates?: FormatDateLocaleOptions; + }; + dictionary?: DictionaryMessagesOptions; +} + +export interface LocaleSettings { + locale: string; + formats: { + numbers: NumberPresets; + dates: FormatDateLocalePresets; + }; + dictionary: DictionaryMessages; +} + +const defaultLocaleSettings: LocaleSettings = { + locale: 'en', + dictionary: { + Ok: 'Ok', + Cancel: 'Cancel', + Date: { + Start: 'Start', + End: 'End', + Empty: 'Empty', + + Day: 'Day', + DayTime: 'Day Time', + Time: 'Time', + Week: 'Week', + BiWeek: 'Bi-Week', + Month: 'Month', + Quarter: 'Quarter', + CalendarYear: 'Calendar Year', + FiscalYearOct: 'Fiscal Year (Oct)', + + PeriodDay: { + Current: 'Today', + Last: 'Yesterday', + LastX: 'Last {0} days', + }, + PeriodWeek: { + Current: 'This week', + Last: 'Last week', + LastX: 'Last {0} weeks', + }, + PeriodBiWeek: { + Current: 'This bi-week', + Last: 'Last bi-week', + LastX: 'Last {0} bi-weeks', + }, + PeriodMonth: { + Current: 'This month', + Last: 'Last month', + LastX: 'Last {0} months', + }, + PeriodQuarter: { + Current: 'This quarter', + Last: 'Last quarter', + LastX: 'Last {0} quarters', + }, + PeriodQuarterSameLastyear: 'Same quarter last year', + PeriodYear: { + Current: 'This year', + Last: 'Last year', + LastX: 'Last {0} years', + }, + PeriodFiscalYear: { + Current: 'This fiscal year', + Last: 'Last fiscal year', + LastX: 'Last {0} fiscal years', + }, + }, + }, + formats: { + numbers: { + defaults: { + currency: 'USD', + fractionDigits: 2, + currencyDisplay: 'symbol', + }, + }, + dates: { + baseParsing: 'MM/dd/yyyy', + weekStartsOn: DayOfWeek.Sunday, + ordinalSuffixes: { + one: 'st', + two: 'nd', + few: 'rd', + other: 'th', + }, + presets: { + day: { + short: [DateToken.DayOfMonth_numeric, DateToken.Month_numeric], + default: [DateToken.DayOfMonth_numeric, DateToken.Month_numeric, DateToken.Year_numeric], + long: [DateToken.DayOfMonth_numeric, DateToken.Month_short, DateToken.Year_numeric], + }, + dayTime: { + short: [ + DateToken.DayOfMonth_numeric, + DateToken.Month_numeric, + DateToken.Year_numeric, + DateToken.Hour_numeric, + DateToken.Minute_numeric, + ], + default: [ + DateToken.DayOfMonth_numeric, + DateToken.Month_numeric, + DateToken.Year_numeric, + DateToken.Hour_2Digit, + DateToken.Minute_2Digit, + ], + long: [ + DateToken.DayOfMonth_numeric, + DateToken.Month_numeric, + DateToken.Year_numeric, + DateToken.Hour_2Digit, + DateToken.Minute_2Digit, + DateToken.Second_2Digit, + ], + }, + + timeOnly: { + short: [DateToken.Hour_numeric, DateToken.Minute_numeric], + default: [DateToken.Hour_2Digit, DateToken.Minute_2Digit, DateToken.Second_2Digit], + long: [ + DateToken.Hour_2Digit, + DateToken.Minute_2Digit, + DateToken.Second_2Digit, + DateToken.MiliSecond_3, + ], + }, + + week: { + short: [DateToken.DayOfMonth_numeric, DateToken.Month_numeric], + default: [DateToken.DayOfMonth_numeric, DateToken.Month_numeric, DateToken.Year_numeric], + long: [DateToken.DayOfMonth_numeric, DateToken.Month_numeric, DateToken.Year_numeric], + }, + month: { + short: DateToken.Month_short, + default: DateToken.Month_short, + long: DateToken.Month_long, + }, + monthsYear: { + short: [DateToken.Month_short, DateToken.Year_2Digit], + default: [DateToken.Month_long, DateToken.Year_numeric], + long: [DateToken.Month_long, DateToken.Year_numeric], + }, + year: { + short: DateToken.Year_2Digit, + default: DateToken.Year_numeric, + long: DateToken.Year_numeric, + }, + }, + }, + }, +}; + +/** Creates a locale settings object, using the `base` locale settings as defaults. + * If omitted, the `en` locale is used as the base. */ +export function createLocaleSettings( + localeSettings: LocaleSettingsInput, + base = defaultLocaleSettings +): LocaleSettings { + // if ordinalSuffixes is specified, we want to make sure that all are empty first + if (localeSettings.formats?.dates?.ordinalSuffixes) { + localeSettings.formats.dates.ordinalSuffixes = { + one: '', + two: '', + few: '', + other: '', + zero: '', + many: '', + ...localeSettings.formats.dates.ordinalSuffixes, + }; + } + + // if weekStartsOn is not specified, let's default to the local one + if (localeSettings.formats?.dates?.weekStartsOn === undefined) { + localeSettings = defaultsDeep(localeSettings, { + formats: { dates: { weekStartsOn: getWeekStartsOnFromIntl(localeSettings.locale) } }, + }); + } + + return defaultsDeep(localeSettings, base); +} + +export const defaultLocale = createLocaleSettings({ locale: 'en' }); + +export function getAllKnownLocales( + additionalLocales?: Record<string, LocaleSettingsInput> +): Record<string, LocaleSettings> { + const additional = additionalLocales + ? Object.entries(additionalLocales).map(([key, value]) => [key, createLocaleSettings(value)]) + : []; + return { en: defaultLocale, ...Object.fromEntries(additional) }; +} diff --git a/packages/svelte-ux/src/lib/utils/number.test.ts b/packages/svelte-ux/src/lib/utils/number.test.ts index 171bbbcc5..0cc29872c 100644 --- a/packages/svelte-ux/src/lib/utils/number.test.ts +++ b/packages/svelte-ux/src/lib/utils/number.test.ts @@ -1,6 +1,7 @@ import { describe, it, expect } from 'vitest'; -import { clamp, formatNumber, round } from './number'; +import { clamp, formatNumber, formatNumberWithLocale, round } from './number'; +import { defaultLocale, createLocaleSettings } from './locale'; describe('clamp()', () => { it('no change', () => { @@ -60,17 +61,21 @@ describe('formatNumber()', () => { }); it('returns value as string for style "none"', () => { - const actual = formatNumber(1234.5678, { style: 'none' }); + const actual = formatNumber(1234.5678, 'none'); expect(actual).equal('1234.5678'); }); it('formats number with integer default', () => { - const actual = formatNumber(1234.5678, { style: 'integer' }); + const actual = formatNumber(1234.5678, 'integer'); expect(actual).equal('1,235'); }); it('formats number with integer fr', () => { - const actual = formatNumber(1234.5678, { style: 'integer', locales: 'fr' }); + const actual = formatNumberWithLocale( + createLocaleSettings({ locale: 'fr' }), + 1234.5678, + 'integer' + ); expect(actual).equal('1 235'); }); @@ -80,12 +85,12 @@ describe('formatNumber()', () => { }); it('formats number with specified fraction digits', () => { - const actual = formatNumber(1234.5678, { fractionDigits: 3 }); + const actual = formatNumber(1234.5678, 'decimal', { fractionDigits: 3 }); expect(actual).equal('1,234.568'); }); it('returns value with significant digits', () => { - const actual = formatNumber(1234.5678, { + const actual = formatNumber(1234.5678, 'default', { notation: 'compact', maximumSignificantDigits: 2, }); @@ -93,7 +98,7 @@ describe('formatNumber()', () => { }); it('returns value with significant digits', () => { - const actual = formatNumber(1000, { + const actual = formatNumber(1000, 'default', { notation: 'compact', minimumSignificantDigits: 2, }); @@ -101,44 +106,49 @@ describe('formatNumber()', () => { }); it('formats number with currency USD by style', () => { - const actual = formatNumber(1234.5678, { style: 'currency' }); + const actual = formatNumber(1234.5678, 'currency'); expect(actual).equal('$1,234.57'); }); it('formats number with currency USD by currency', () => { - const actual = formatNumber(1234.5678, { currency: 'USD' }); + const actual = formatNumber(1234.5678, 'currency', { currency: 'USD' }); expect(actual).equal('$1,234.57'); }); it('formats number with currency GBP', () => { - const actual = formatNumber(1234.5678, { currency: 'GBP' }); + const actual = formatNumber(1234.5678, 'currency', { currency: 'GBP' }); expect(actual).equal('£1,234.57'); }); it('formats number with currency EUR only currency', () => { - const actual = formatNumber(1234.5678, { currency: 'EUR' }); + const actual = formatNumber(1234.5678, 'currency', { currency: 'EUR' }); expect(actual).equal('€1,234.57'); }); it('formats number with currency EUR with right local', () => { - const actual = formatNumber(1234.5678, { locales: 'fr', currency: 'EUR' }); + const actual = formatNumberWithLocale( + createLocaleSettings({ locale: 'fr' }), + 1234.5678, + 'currency', + { + currency: 'EUR', + } + ); expect(actual).equal('1 234,57 €'); }); it('returns value with percent symbol for style "percent"', () => { - const actual = formatNumber(0.1234, { style: 'percent' }); + const actual = formatNumber(0.1234, 'percent'); expect(actual).equal('12.34%'); }); it('returns value with percent symbol and no decimal for style "percentRound"', () => { - const actual2 = formatNumber(0.1234, { style: 'percentRound' }); + const actual2 = formatNumber(0.1234, 'percentRound'); expect(actual2).equal('12%'); }); it('returns value with metric suffix for style "unit" & meters', () => { - const actual = formatNumber(1000, { - style: 'unit', - + const actual = formatNumber(1000, 'unit', { unit: 'meter', unitDisplay: 'narrow', @@ -149,8 +159,7 @@ describe('formatNumber()', () => { }); it('byte 10B', () => { - const actual = formatNumber(10, { - style: 'unit', + const actual = formatNumber(10, 'unit', { unit: 'byte', unitDisplay: 'narrow', notation: 'compact', @@ -160,8 +169,7 @@ describe('formatNumber()', () => { }); it('byte 200KB', () => { - const actual = formatNumber(200000, { - style: 'unit', + const actual = formatNumber(200000, 'unit', { unit: 'byte', unitDisplay: 'narrow', notation: 'compact', @@ -171,8 +179,7 @@ describe('formatNumber()', () => { }); it('byte 50MB', () => { - const actual = formatNumber(50000000, { - style: 'unit', + const actual = formatNumber(50000000, 'unit', { unit: 'byte', unitDisplay: 'narrow', notation: 'compact', @@ -182,7 +189,7 @@ describe('formatNumber()', () => { }); it('dollar 0', () => { - const actual = formatNumber(0, { + const actual = formatNumber(0, 'metric', { style: 'metric', suffix: ' dollar', }); @@ -190,39 +197,33 @@ describe('formatNumber()', () => { }); it('dollars 10', () => { - const actual = formatNumber(10, { - style: 'metric', + const actual = formatNumber(10, 'metric', { suffix: ' dollar', }); expect(actual).equal('10 dollars'); }); it('dollars 200K', () => { - const actual = formatNumber(200000, { - style: 'metric', + const actual = formatNumber(200000, 'metric', { suffix: ' dollar', }); expect(actual).equal('200K dollars'); }); it('dollars 50M', () => { - const actual = formatNumber(50000000, { - style: 'metric', + const actual = formatNumber(50000000, 'metric', { suffix: ' dollar', }); expect(actual).equal('50M dollars'); }); it('50M wo suffix', () => { - const actual = formatNumber(50000000, { - style: 'metric', - }); + const actual = formatNumber(50000000, 'metric'); expect(actual).equal('50M'); }); it('200 m²', () => { - const actual = formatNumber(200, { - style: 'metric', + const actual = formatNumber(200, 'metric', { suffix: ' m²', suffixExtraIfMany: '', }); diff --git a/packages/svelte-ux/src/lib/utils/number.ts b/packages/svelte-ux/src/lib/utils/number.ts index e2be0ec1d..45b51e3a1 100644 --- a/packages/svelte-ux/src/lib/utils/number.ts +++ b/packages/svelte-ux/src/lib/utils/number.ts @@ -1,4 +1,5 @@ -import { getFormatNumberOptions } from '$lib/components/settings'; +import type { Settings } from '../components/settings'; +import { defaultLocale, createLocaleSettings, type LocaleSettings } from './locale'; export type FormatNumberStyle = | 'decimal' // from Intl.NumberFormat options.style NumberFormatOptions @@ -8,11 +9,10 @@ export type FormatNumberStyle = | 'none' | 'integer' | 'percentRound' - | 'metric'; + | 'metric' + | 'default'; export type FormatNumberOptions = Intl.NumberFormatOptions & { - style?: FormatNumberStyle; - locales?: string | undefined; fractionDigits?: number; suffix?: string; /** @@ -22,22 +22,48 @@ export type FormatNumberOptions = Intl.NumberFormatOptions & { suffixExtraIfMany?: string; }; +function getFormatNumber(settings: LocaleSettings, style: FormatNumberStyle | undefined) { + const { numbers } = settings.formats; + const styleSettings = style ? numbers[style] : {}; + return { + ...numbers.defaults, + ...styleSettings, + }; +} + +export function formatNumber( + number: number | null | undefined, + style?: FormatNumberStyle, + options?: FormatNumberOptions +) { + return formatNumberWithLocale(defaultLocale, number, style, options); +} + // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat -export function formatNumber(number: number | null | undefined, options: FormatNumberOptions = {}) { +export function formatNumberWithLocale( + settings: LocaleSettings, + number: number | null | undefined, + style?: FormatNumberStyle, + options: FormatNumberOptions = {} +) { if (number == null) { return ''; } - if (options.style === 'none') { + if (style === 'none') { return `${number}`; } - const defaults = getFormatNumberOptions(options.style); + const defaults = getFormatNumber(settings, style); - const formatter = Intl.NumberFormat(options.locales ?? defaults.locales ?? undefined, { + const formatter = Intl.NumberFormat(settings.locale, { // Let's always starts with all defaults ...defaults, + ...(style !== 'default' && { + style, + }), + // If currency is specified, then style must be currency ...(options.currency != null && { style: 'currency', @@ -45,32 +71,30 @@ export function formatNumber(number: number | null | undefined, options: FormatN // Let's shorten min / max with fractionDigits ...{ - minimumFractionDigits: - options.fractionDigits != null ? options.fractionDigits : defaults.fractionDigits, - maximumFractionDigits: - options.fractionDigits != null ? options.fractionDigits : defaults.fractionDigits, + minimumFractionDigits: options.fractionDigits ?? defaults.fractionDigits, + maximumFractionDigits: options.fractionDigits ?? defaults.fractionDigits, }, // now we bring in user specified options ...options, // Let's overwrite for style=percentRound - ...(options.style === 'percentRound' && { + ...(style === 'percentRound' && { style: 'percent', minimumFractionDigits: 0, maximumFractionDigits: 0, }), // Let's overwrite for style=metric - ...(options.style === 'metric' && { + ...(style === 'metric' && { style: 'decimal', notation: 'compact', minimumFractionDigits: 0, maximumFractionDigits: 0, }), - // Let's overwrite for style=metric - ...(options.style === 'integer' && { + // Let's overwrite for style=integer + ...(style === 'integer' && { style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0, diff --git a/packages/svelte-ux/src/lib/utils/table.ts b/packages/svelte-ux/src/lib/utils/table.ts index 7d7e70092..2e3817015 100644 --- a/packages/svelte-ux/src/lib/utils/table.ts +++ b/packages/svelte-ux/src/lib/utils/table.ts @@ -4,6 +4,7 @@ import { parseISO } from 'date-fns'; import type { ColumnDef } from '../types/table'; import { PeriodType } from '../utils/date'; import { format } from '../utils/format'; +import type { Settings } from '../components/settings'; export function getHeaders(columns: ColumnDef[]) { const maxDepth = getDepth(columns); @@ -121,8 +122,3 @@ export function getCellValue(column: ColumnDef, rowData: any, rowIndex?: number) return value; } - -export function getCellContent(column: ColumnDef, rowData: any, rowIndex?: number) { - const value = getCellValue(column, rowData, rowIndex); - return format(value, column?.format, rowData, rowIndex); -} diff --git a/packages/svelte-ux/src/routes/+error.svelte b/packages/svelte-ux/src/routes/+error.svelte index 48835e3c7..f2eec1df6 100644 --- a/packages/svelte-ux/src/routes/+error.svelte +++ b/packages/svelte-ux/src/routes/+error.svelte @@ -10,23 +10,25 @@ <div> <h2 class="text-lg font-bold mb-1">Message:</h2> - <pre class="ml-2 p-4 border rounded-md text-xs bg-black/80 text-white">{$page.error - .message}</pre> + <pre class="ml-2 p-4 border rounded-md text-xs bg-surface-content/80 text-surface-100">{$page + .error.message}</pre> </div> {#if $page.error.frame} <div> <h2 class="text-lg font-bold mb-1">Frame:</h2> - <pre class="ml-2 p-4 border rounded-md text-xs bg-black/80 text-white">{$page.error - .frame}</pre> + <pre + class="ml-2 p-4 border rounded-md text-xs bg-surface-content/80 text-surface-100">{$page + .error.frame}</pre> </div> {/if} {#if $page.error.stack} <div> <h2 class="text-lg font-bold mb-1">Stack:</h2> - <pre class="ml-2 p-4 border rounded-md text-xs bg-black/80 text-white">{$page.error - .stack}</pre> + <pre + class="ml-2 p-4 border rounded-md text-xs bg-surface-content/80 text-surface-100">{$page + .error.stack}</pre> </div> {/if} </div> diff --git a/packages/svelte-ux/src/routes/+layout.server.ts b/packages/svelte-ux/src/routes/+layout.server.ts index da729965e..416704c48 100644 --- a/packages/svelte-ux/src/routes/+layout.server.ts +++ b/packages/svelte-ux/src/routes/+layout.server.ts @@ -2,6 +2,9 @@ import { redirect } from '@sveltejs/kit'; import { env } from '$env/dynamic/private'; +import themes from '../../themes.json'; +import { getThemeNames } from '$lib/styles/theme'; + export async function load({ url }) { // Redirect `svelte-ux.vercel.app` to `svelte-ux.techniq.dev` if (url.host === 'svelte-ux.vercel.app') { @@ -10,5 +13,9 @@ export async function load({ url }) { throw redirect(302, newUrl.toString()); } - return { pr_id: env.VERCEL_GIT_PULL_REQUEST_ID }; + return { + themes: getThemeNames(themes), + // themes: { light: ['light'], dark: ['dark'] }, + pr_id: env.VERCEL_GIT_PULL_REQUEST_ID, + }; } diff --git a/packages/svelte-ux/src/routes/+layout.svelte b/packages/svelte-ux/src/routes/+layout.svelte index 4c102bbb6..981fd3227 100644 --- a/packages/svelte-ux/src/routes/+layout.svelte +++ b/packages/svelte-ux/src/routes/+layout.svelte @@ -2,22 +2,29 @@ import { onMount } from 'svelte'; import posthog from 'posthog-js'; import 'prism-themes/themes/prism-vsc-dark-plus.css'; - import { mdiArrowTopRight, mdiGithub, mdiTwitter } from '@mdi/js'; + import { mdiArrowTopRight, mdiDotsVertical, mdiGithub, mdiTwitter } from '@mdi/js'; import AppBar from '$lib/components/AppBar.svelte'; import AppLayout from '$lib/components/AppLayout.svelte'; import Button from '$lib/components/Button.svelte'; - import Tooltip from '$lib/components/Tooltip.svelte'; + import MenuButton from '$lib/components/MenuButton.svelte'; import NavMenu from './_NavMenu.svelte'; import QuickSearch from '$lib/components/QuickSearch.svelte'; + import ThemeSelect from '$lib/components/ThemeSelect.svelte'; + import ThemeSwitch from '$lib/components/ThemeSwitch.svelte'; + import Tooltip from '$lib/components/Tooltip.svelte'; import { dev } from '$app/environment'; import { afterNavigate, goto } from '$app/navigation'; import { page } from '$app/stores'; - import { settings } from '$lib'; + import { settings } from '$lib/components/settings'; + import { lgScreen } from '$lib/stores/matchMedia'; import type { PageData } from './$types'; + import { createLocaleSettings } from '$lib'; + import LanguageSelect from '$lib/components/LanguageSelect.svelte'; + export let data: PageData; const baseGh = 'https://github.com/techniq/svelte-ux'; @@ -26,17 +33,96 @@ $: title = data.pr_id ? `🚧 (pr:${data.pr_id}) - ${baseTitle}` : baseTitle; settings({ - // formats: { - // numbers: { - // defaults: { - // locales: 'fr', - // currency: 'EUR', - // }, - // }, - // }, - // theme: { - // AppBar: 'bg-red-500 text-white shadow-md', - // }, + // fallbackLocale: 'fr', + localeFormats: { + fr: createLocaleSettings({ + locale: 'fr', + formats: { + dates: { + baseParsing: 'dd/MM/yyyy', + ordinalSuffixes: { + one: 'er', + }, + }, + numbers: { + defaults: { + currency: 'EUR', + }, + }, + }, + dictionary: { + Ok: 'Valider', + Cancel: 'Annuler', + Date: { + Start: 'Début', + End: 'Fin', + Empty: 'Vide', + + Day: 'Jour', + DayTime: 'Jour & Heure', + Time: 'Heure', + Week: 'Semaine', + Month: 'Mois', + Quarter: 'Trimestre', + CalendarYear: 'Année', + FiscalYearOct: 'Année fiscale (octobre)', + BiWeek: 'Bi-hebdomadaire', + + PeriodDay: { + Current: "Aujourd'hui", + Last: 'Hier', + LastX: 'Les {0} derniers jours', + }, + PeriodWeek: { + Current: 'Cette semaine', + Last: 'La semaine dernière', + LastX: 'Les {0} dernières semaines', + }, + PeriodBiWeek: { + Current: 'Cette quinzaine', + Last: 'La quinzaine dernière', + LastX: 'Les {0} dernières quinzaines', + }, + PeriodMonth: { + Current: 'Ce mois-ci', + Last: 'Le mois dernier', + LastX: 'Les {0} derniers mois', + }, + PeriodQuarter: { + Current: 'Ce trimestre', + Last: 'Le trimestre dernier', + LastX: 'Les {0} derniers trimestres', + }, + PeriodQuarterSameLastyear: "Même trimestre l'année dernière", + PeriodYear: { + Current: 'Cette année', + Last: "L'année dernière", + LastX: 'Les {0} dernières années', + }, + PeriodFiscalYear: { + Current: 'Cette année fiscale', + Last: "L'année fiscale dernière", + LastX: 'Les {0} dernières années fiscales', + }, + }, + }, + }), + }, + + classes: { + AppLayout: { + aside: 'border-r', + nav: 'bg-surface-300 py-2', + }, + AppBar: + 'bg-primary text-primary-content shadow-md [text-shadow:1px_1px_2px_theme(colors.primary-700)]', + NavItem: { + root: 'text-sm text-surface-content/70 pl-6 py-2 hover:bg-surface-100/70 relative', + active: + 'text-primary bg-surface-100 font-medium before:absolute before:bg-primary before:rounded-full before:w-1 before:h-2/3 before:left-[6px] shadow z-10', + }, + }, + themes: data.themes, }); let mainEl: HTMLElement; @@ -119,34 +205,82 @@ href="https://www.layerchart.com" icon={{ data: mdiArrowTopRight, class: 'opacity-50' }} target="_blank" - class="p-2 max-md:hidden flex-row-reverse" + class="p-2 max-lg:hidden flex-row-reverse" > LayerChart </Button> - <QuickSearch options={quickSearchOptions} on:change={(e) => goto(e.detail.value)} /> - - <Tooltip title="Discord" placement="left" offset={2}> - <Button - icon="M20.33 5.06C18.78 4.33 17.12 3.8 15.38 3.5 15.17 3.89 14.92 4.4 14.74 4.82 12.9 4.54 11.07 4.54 9.26 4.82 9.09 4.4 8.83 3.89 8.62 3.5 6.88 3.8 5.21 4.33 3.66 5.06 0.53 9.79-0.32 14.41 0.1 18.96 2.18 20.52 4.19 21.46 6.17 22.08 6.66 21.4 7.1 20.69 7.48 19.93 6.76 19.66 6.07 19.33 5.43 18.94 5.6 18.81 5.77 18.68 5.93 18.54 9.88 20.39 14.17 20.39 18.07 18.54 18.23 18.68 18.4 18.81 18.57 18.94 17.92 19.33 17.24 19.66 16.52 19.94 16.9 20.69 17.33 21.41 17.82 22.08 19.8 21.46 21.82 20.52 23.9 18.96 24.4 13.69 23.05 9.11 20.33 5.06ZM8.01 16.17C6.83 16.17 5.86 15.06 5.86 13.71 5.86 12.36 6.81 11.25 8.01 11.25 9.22 11.25 10.19 12.36 10.17 13.71 10.17 15.06 9.22 16.17 8.01 16.17ZM15.99 16.17C14.8 16.17 13.83 15.06 13.83 13.71 13.83 12.36 14.78 11.25 15.99 11.25 17.19 11.25 18.17 12.36 18.14 13.71 18.14 15.06 17.19 16.17 15.99 16.17Z" - href="https://discord.gg/697JhMPD3t" - class="p-2" - target="_blank" - /> - </Tooltip> - - <Tooltip title="Open Twitter / X" placement="left" offset={2}> - <Button - icon={mdiTwitter} - href="https://twitter.com/techniq35" - class="p-2" - target="_blank" - /> - </Tooltip> - - <Tooltip title="View repository" placement="left" offset={2}> - <Button icon={mdiGithub} href={ghLink} class="p-2" target="_blank" /> - </Tooltip> + <QuickSearch + options={quickSearchOptions} + on:change={(e) => goto(e.detail.value)} + classes={{ button: 'max-sm:-mr-3' }} + /> + + <div class="border-r border-primary-content/20 pr-2 grid grid-cols-2 items-center"> + <LanguageSelect /> + {#if data.themes.light.length > 1 || data.themes.dark.length > 1} + <ThemeSelect /> + {:else} + <ThemeSwitch classes={{ switch: 'bg-black/10 bornder-none' }} /> + {/if} + </div> + + {#if $lgScreen} + <Tooltip title="Discord" placement="left" offset={2}> + <Button + icon="M20.33 5.06C18.78 4.33 17.12 3.8 15.38 3.5 15.17 3.89 14.92 4.4 14.74 4.82 12.9 4.54 11.07 4.54 9.26 4.82 9.09 4.4 8.83 3.89 8.62 3.5 6.88 3.8 5.21 4.33 3.66 5.06 0.53 9.79-0.32 14.41 0.1 18.96 2.18 20.52 4.19 21.46 6.17 22.08 6.66 21.4 7.1 20.69 7.48 19.93 6.76 19.66 6.07 19.33 5.43 18.94 5.6 18.81 5.77 18.68 5.93 18.54 9.88 20.39 14.17 20.39 18.07 18.54 18.23 18.68 18.4 18.81 18.57 18.94 17.92 19.33 17.24 19.66 16.52 19.94 16.9 20.69 17.33 21.41 17.82 22.08 19.8 21.46 21.82 20.52 23.9 18.96 24.4 13.69 23.05 9.11 20.33 5.06ZM8.01 16.17C6.83 16.17 5.86 15.06 5.86 13.71 5.86 12.36 6.81 11.25 8.01 11.25 9.22 11.25 10.19 12.36 10.17 13.71 10.17 15.06 9.22 16.17 8.01 16.17ZM15.99 16.17C14.8 16.17 13.83 15.06 13.83 13.71 13.83 12.36 14.78 11.25 15.99 11.25 17.19 11.25 18.17 12.36 18.14 13.71 18.14 15.06 17.19 16.17 15.99 16.17Z" + href="https://discord.gg/697JhMPD3t" + class="p-2" + target="_blank" + /> + </Tooltip> + + <Tooltip title="Open Twitter / X" placement="left" offset={2}> + <Button + icon={mdiTwitter} + href="https://twitter.com/techniq35" + class="p-2" + target="_blank" + /> + </Tooltip> + + <Tooltip title="View repository" placement="left" offset={2}> + <Button icon={mdiGithub} href={ghLink} class="p-2" target="_blank" /> + </Tooltip> + {:else} + <MenuButton + icon={mdiDotsVertical} + menuIcon={null} + iconOnly={true} + options={[ + { + label: 'LayerChart', + value: 'https://www.layerchart.com', + icon: mdiArrowTopRight, + }, + { + label: 'Github', + value: ghLink, + icon: mdiGithub, + }, + { + label: 'Discord', + value: 'https://discord.gg/697JhMPD3t', + icon: 'M20.33 5.06C18.78 4.33 17.12 3.8 15.38 3.5 15.17 3.89 14.92 4.4 14.74 4.82 12.9 4.54 11.07 4.54 9.26 4.82 9.09 4.4 8.83 3.89 8.62 3.5 6.88 3.8 5.21 4.33 3.66 5.06 0.53 9.79-0.32 14.41 0.1 18.96 2.18 20.52 4.19 21.46 6.17 22.08 6.66 21.4 7.1 20.69 7.48 19.93 6.76 19.66 6.07 19.33 5.43 18.94 5.6 18.81 5.77 18.68 5.93 18.54 9.88 20.39 14.17 20.39 18.07 18.54 18.23 18.68 18.4 18.81 18.57 18.94 17.92 19.33 17.24 19.66 16.52 19.94 16.9 20.69 17.33 21.41 17.82 22.08 19.8 21.46 21.82 20.52 23.9 18.96 24.4 13.69 23.05 9.11 20.33 5.06ZM8.01 16.17C6.83 16.17 5.86 15.06 5.86 13.71 5.86 12.36 6.81 11.25 8.01 11.25 9.22 11.25 10.19 12.36 10.17 13.71 10.17 15.06 9.22 16.17 8.01 16.17ZM15.99 16.17C14.8 16.17 13.83 15.06 13.83 13.71 13.83 12.36 14.78 11.25 15.99 11.25 17.19 11.25 18.17 12.36 18.14 13.71 18.14 15.06 17.19 16.17 15.99 16.17Z', + }, + { + label: 'Twitter / X', + value: 'https://twitter.com/techniq35', + icon: mdiTwitter, + }, + ]} + on:change={(e) => { + window.open(e.detail.value, '_blank'); + }} + > + <span slot="selection" class="hidden" /> + </MenuButton> + {/if} </div> </AppBar> @@ -160,8 +294,23 @@ @tailwind components; @tailwind utilities; + :global(body) { + @apply bg-surface-200 accent-primary; + /* background-image: + radial-gradient(at 0% 0%, hsl(var(--color-secondary) / 0.33) 0px, transparent 50%), + radial-gradient(at 98% 1%, hsl(var(--color-primary) / 0.33) 0px, transparent 50%); */ + } + + :global(nav h1) { + @apply py-2 pl-4 mt-4 text-sm text-surface-content font-bold bg-surface-200 border-t border-b; + } + + :global(nav h2) { + @apply pt-4 pb-2 pl-4 text-xs text-surface-content font-bold; + } + :global(main h1:not(.prose *, .related *, .ApiDocs *)) { - @apply text-xl font-semibold mt-4 mb-2 border-b border-gray-400 pb-1; + @apply text-xl font-semibold mt-4 mb-2 border-b pb-1; scroll-margin-top: 128px; /* sticky header */ } @@ -171,7 +320,7 @@ } :global(main h3:not(.prose *, .related *, .ApiDocs *)) { - @apply text-xs text-black/50 mb-1; + @apply text-xs text-surface-content/50 mb-1; scroll-margin-top: 128px; /* sticky header */ } :global(main :not(.prose) h2 + h3) { @@ -179,85 +328,19 @@ } :global(main small) { - @apply text-xs text-black/50 inline-block; + @apply text-xs text-surface-content/50 inline-block; } :global(.TableOfContents small) { @apply hidden; } - /* Material */ - - :global(body) { - @apply bg-neutral-200 accent-accent-500; - } - - :global(nav) { - @apply bg-neutral-800 py-2; - } - - :global(nav h1) { - @apply py-2 pl-4 mt-4 text-sm text-gray-200 font-bold bg-black/20 border-t border-b border-white/10; + /* Code/Preview backgrounds */ + :global(pre[class*='language-']) { + @apply bg-surface-content; } - :global(nav h2) { - @apply pt-4 pb-2 pl-4 text-xs text-gray-200 font-bold; + :global(.dark pre[class*='language-']) { + @apply bg-surface-300; } - - :global(nav .NavItem) { - @apply text-sm text-gray-400 pl-5 py-2 border-l-4 border-transparent; - - &:hover { - @apply text-white bg-gray-300/10; - } - - &.is-active { - @apply text-accent-100 bg-gray-500/10 border-accent-500; - } - } - - :global(.AppLayout > .AppBar) { - @apply bg-accent-500 text-white shadow-md; - } - - /* New theme */ - /* :global(body) { - @apply bg-neutral-900; - } - - :global(aside) { - @apply border-r border-neutral-700; - } - - :global(nav) { - @apply bg-neutral-900 py-2; - } - - :global(nav h1) { - @apply py-2 pl-4 mt-4 text-sm text-gray-200 font-bold bg-black/20 border-t border-b border-white/10; - } - - :global(nav h2) { - @apply pt-4 pb-2 pl-4 text-xs text-gray-200 font-bold; - } - - :global(nav .NavItem) { - @apply text-sm text-gray-400 py-1 border-l border-neutral-700 pl-4 ml-4; - } - - :global(nav .NavItem:hover) { - @apply text-white bg-gray-300/10; - } - - :global(nav .NavItem.is-active) { - @apply text-accent-200 bg-accent-500/20 border-accent-300; - } - - :global(.AppBar) { - @apply bg-neutral-800/70 text-white shadow-md backdrop-blur-lg; - } - - :global(main) { - @apply text-neutral-200; - } */ </style> diff --git a/packages/svelte-ux/src/routes/+page.md b/packages/svelte-ux/src/routes/+page.md index a433e7ef9..702fb99a4 100644 --- a/packages/svelte-ux/src/routes/+page.md +++ b/packages/svelte-ux/src/routes/+page.md @@ -2,7 +2,7 @@ import Button from '$lib/components/Button.svelte'; </script> -<div class="prose max-w-none bg-white rounded border p-4"> +<div class="prose max-w-none bg-surface-100 rounded border p-4"> <h1>Installation</h1> @@ -110,12 +110,4 @@ Using `components`, `actions`, or `stores` is as simple as importing from `svelt <Button>Click here</Button> ``` -Currently, `utils` are not exposed as top-level exports to not polute the namespace, although this may change in the future. For now, you can import them using the full path. - -```js -import { dateDisplay } from 'svelte-ux/utils/dateDisplay'; -``` - -See each component page for detailed usage examples. - </div> diff --git a/packages/svelte-ux/src/routes/_NavMenu.svelte b/packages/svelte-ux/src/routes/_NavMenu.svelte index 8104a66d6..07e144fce 100644 --- a/packages/svelte-ux/src/routes/_NavMenu.svelte +++ b/packages/svelte-ux/src/routes/_NavMenu.svelte @@ -1,7 +1,7 @@ <script lang="ts"> import { page } from '$app/stores'; import NavItem from '$lib/components/NavItem.svelte'; - import { mdiFormatListBulleted, mdiHome, mdiPalette } from '@mdi/js'; + import { mdiCog, mdiFormatListBulleted, mdiHome, mdiPalette } from '@mdi/js'; const components = { App: ['AppBar', 'AppLayout', 'NavItem', 'Settings'], @@ -52,7 +52,6 @@ ], Feedback: ['Badge', 'Progress', 'ProgressCircle'], Date: [ - 'dateDisplay', 'DateField', 'DatePickerField', 'DateRange', @@ -70,7 +69,6 @@ }; const actions = [ - 'cssVars', 'dataBackground', 'input', 'layout', @@ -82,6 +80,7 @@ 'scroll', 'spotlight', 'sticky', + 'styleProps', 'table', ]; @@ -108,7 +107,8 @@ </script> <NavItem text="Getting Started" icon={mdiHome} currentUrl={$page.url} path="/" /> -<NavItem text="Customization" icon={mdiPalette} currentUrl={$page.url} path="/customization" /> +<NavItem text="Customization" icon={mdiCog} currentUrl={$page.url} path="/customization" /> +<NavItem text="Theme" icon={mdiPalette} currentUrl={$page.url} path="/theme" /> <NavItem text="Changelog" icon={mdiFormatListBulleted} currentUrl={$page.url} path="/changelog" /> <h1>Components</h1> diff --git a/packages/svelte-ux/src/routes/changelog/+page.svelte b/packages/svelte-ux/src/routes/changelog/+page.svelte index 379ddea61..2844d0d82 100644 --- a/packages/svelte-ux/src/routes/changelog/+page.svelte +++ b/packages/svelte-ux/src/routes/changelog/+page.svelte @@ -10,7 +10,7 @@ </script> <div class="grid grid-cols-[1fr,auto] gap-6 pt-2 pb-4"> - <div class="bg-white p-2 m-2 rounded shadow-lg border overflow-auto"> + <div class="bg-surface-100 p-2 m-2 rounded shadow-lg border overflow-auto"> <div class="prose px-4"> {@html marked.parse(sanitize(changelog))} </div> @@ -18,7 +18,9 @@ <div class="hidden lg:block w-[224px]"> <div class="sticky top-0 pr-2 max-h-[calc(100vh-64px)] overflow-auto"> - <div class="text-xs uppercase leading-8 tracking-widest text-black/50">On this page</div> + <div class="text-xs uppercase leading-8 tracking-widest text-surface-content/50"> + On this page + </div> <TableOfContents maxDepth={2} /> </div> </div> diff --git a/packages/svelte-ux/src/routes/customization/+layout.svelte b/packages/svelte-ux/src/routes/customization/+layout.svelte index fbe95767e..a6ef2008f 100644 --- a/packages/svelte-ux/src/routes/customization/+layout.svelte +++ b/packages/svelte-ux/src/routes/customization/+layout.svelte @@ -1,3 +1,3 @@ -<div class="prose max-w-none p-4 bg-white"> +<div class="prose max-w-none p-4 bg-surface-100"> <slot /> </div> diff --git a/packages/svelte-ux/src/routes/customization/+page.md b/packages/svelte-ux/src/routes/customization/+page.md index 4cb1e15f9..57d280faf 100644 --- a/packages/svelte-ux/src/routes/customization/+page.md +++ b/packages/svelte-ux/src/routes/customization/+page.md @@ -55,31 +55,61 @@ On each `ComponentName: ...` you can pass `class` (when value is a `string`) or import { settings } from 'svelte-ux'; settings({ - theme: { + classes: { Button: 'flex-2', // same as <Button class="flex-2"> TextField: { container: 'hover:shadow-none group-focus-within:shadow-none', // same as <TextField classes={{ container: '...' }}> }, }, - formats: { - numbers: { - // This is the default, but you can override it here for your app globally - default: { - locales: 'en', - currency: 'USD', - fractionDigits: 2, - currencyDisplay: 'symbol', - }, - // and/or per preset - currency: { - locales: 'fr', - currency: 'EUR', + // fallbackLocale: 'fr', + localeFormats: { + fr: createLocaleSettings({ + locale: 'fr', + + formats: { + dates: { + baseParsing: 'dd/MM/yyyy', + ordinalSuffixes: { + one: 'er', + }, + }, + + numbers: { + defaults: { + currency: 'EUR', + }, + }, }, - decimal: { - fractionDigits: 4, + + dictionary: { + Ok: 'Valider', + Cancel: 'Annuler', + + Date: { + Start: 'Début', + End: 'Fin', + + Day: 'Jour', + DayTime: 'Jour & Heure', + Time: 'Heure', + Week: 'Semaine', + Month: 'Mois', + Quarter: 'Trimestre', + CalendarYear: 'Année', + FiscalYearOct: 'Année fiscale (octobre)', + BiWeek: 'Bi-hebdomadaire', + + PeriodDay: { + Current: "Aujourd'hui", + Last: 'Hier', + LastX: 'Les {0} derniers jours', + }, + + //... + }, }, - }, + }), }, }); ``` diff --git a/packages/svelte-ux/src/routes/docs/+layout.svelte b/packages/svelte-ux/src/routes/docs/+layout.svelte index 059546b1a..50c8abf12 100644 --- a/packages/svelte-ux/src/routes/docs/+layout.svelte +++ b/packages/svelte-ux/src/routes/docs/+layout.svelte @@ -69,17 +69,17 @@ } // Clear root layout theme so doesn't show on doc examples - settings({ ...getSettings(), theme: {} }); + settings({ ...getSettings(), classes: {} }); </script> <div - class="[@media(min-height:900px)]:sticky top-0 z-20 bg-neutral-200/90 backdrop-blur px-5 py-4 [mask-image:linear-gradient(to_bottom,rgba(0,0,0,1)calc(100%-4px),rgba(0,0,0,0))]" + class="[@media(min-height:900px)]:sticky top-0 z-20 bg-surface-200/90 backdrop-blur px-5 py-4 [mask-image:linear-gradient(to_bottom,rgba(0,0,0,1)calc(100%-4px),rgba(0,0,0,0))]" > {#if title} <div> - <div class="inline-block text-xs font-bold text-gray-500 capitalize">Docs</div> + <div class="inline-block text-xs font-bold text-surface-content/50 capitalize">Docs</div> <Icon path={mdiChevronRight} class="divider opacity-25" /> - <div class="inline-block text-xs font-bold text-accent-500 capitalize"> + <div class="inline-block text-xs font-bold text-primary capitalize"> {type} </div> </div> @@ -100,7 +100,7 @@ </div> {#if description} - <div class="text-sm text-black/60"> + <div class="text-sm text-surface-content/60 xl:pr-[240px]"> {description} </div> {/if} @@ -131,7 +131,7 @@ showTableOfContents = !showTableOfContents; }} variant="fill-light" - color="accent" + color="primary" size="sm" > On this page @@ -145,7 +145,7 @@ {#if showTableOfContents && !$xlScreen} <div transition:fade class="mt-3"> {#key $page.route.id} - <TableOfContents /> + <TableOfContents icon={mdiChevronRight} /> {/key} </div> {/if} @@ -162,10 +162,10 @@ {#if features} {#key $page.route.id} <h1 id="features">Features</h1> - <ul class="pl-4 text-gray-700 divide-y-4"> + <ul class="grid gap-2 pl-4 text-surface-content"> {#each features as feature} <li class="grid grid-cols-[auto,1fr] gap-2"> - <Icon data={mdiCheckCircle} class="text-emerald-600 pt-1" /> + <Icon data={mdiCheckCircle} class="text-success pt-1" /> <span>{@html feature}</span> </li> {/each} @@ -182,7 +182,7 @@ <div> <h2 id="related-{type}" - class="text-xs uppercase leading-8 tracking-widest text-black/50" + class="text-xs uppercase leading-8 tracking-widest text-surface-content/50" > {type} </h2> @@ -201,7 +201,7 @@ <ListItem title={item.name} {icon} - avatar={{ size: 'sm', class: 'text-xs text-white bg-accent-500' }} + avatar={{ size: 'sm', class: 'text-xs text-white bg-primary' }} on:click={() => { if (item.url instanceof URL) { // open in new window @@ -211,10 +211,10 @@ goto(item.url); } }} - class="hover:bg-accent-50 cursor-pointer" + class="hover:bg-surface-200 cursor-pointer" > <div slot="actions"> - <Icon data={mdiChevronRight} class="text-black/50" /> + <Icon data={mdiChevronRight} class="text-surface-content/50" /> </div> </ListItem> {/each} @@ -233,10 +233,12 @@ {#if showTableOfContents && $xlScreen} <div transition:slide={{ axis: 'x' }}> <div class="w-[224px] sticky top-0 pr-2 max-h-[calc(100dvh-64px)] overflow-auto z-20"> - <div class="text-xs uppercase leading-8 tracking-widest text-black/50">On this page</div> + <div class="text-xs uppercase leading-8 tracking-widest text-surface-content/50"> + On this page + </div> <!-- Rebuild toc when page changes --> {#key $page.route.id} - <TableOfContents /> + <TableOfContents icon={mdiChevronRight} class="text-surface-content" /> {/key} </div> </div> diff --git a/packages/svelte-ux/src/routes/docs/actions/cssVars/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/cssVars/+page.svelte deleted file mode 100644 index 36801e382..000000000 --- a/packages/svelte-ux/src/routes/docs/actions/cssVars/+page.svelte +++ /dev/null @@ -1,47 +0,0 @@ -<script lang="ts"> - import Preview from '$lib/components/Preview.svelte'; - import Code from '$lib/components/Code.svelte'; - import TextField from '$lib/components/TextField.svelte'; - - import { cssVars } from '$lib/actions/cssVars'; - import Blockquote from '$docs/Blockquote.svelte'; - - let background = '#ddd'; - let border = '1px solid #aaa'; -</script> - -<h1>Usage</h1> - -<Code source={`import { cssVars } from 'svelte-ux';`} language="javascript" class="mb-4" /> - -<Preview> - <div class="grid gap-4" use:cssVars={{ background, border }}> - <div - class="w-10 h-10 rounded" - style:background-color="var(--background)" - style:border="var(--border)" - /> - <div class="grid grid-flow-col gap-2"> - <TextField label="Background" bind:value={background} /> - <TextField label="Border" bind:value={border} /> - </div> - </div> -</Preview> - -<Blockquote - >With the Svelte addition of `style:`, this actions is less useful (but a little more concise)</Blockquote -> - -<Preview> - <div class="grid gap-4" style:--background={background} style:--border={border}> - <div - class="w-10 h-10 rounded" - style:background-color="var(--background)" - style:border="var(--border)" - /> - <div class="grid grid-flow-col gap-2"> - <TextField label="Background" bind:value={background} /> - <TextField label="Border" bind:value={border} /> - </div> - </div> -</Preview> diff --git a/packages/svelte-ux/src/routes/docs/actions/cssVars/+page.ts b/packages/svelte-ux/src/routes/docs/actions/cssVars/+page.ts deleted file mode 100644 index 07a2d4596..000000000 --- a/packages/svelte-ux/src/routes/docs/actions/cssVars/+page.ts +++ /dev/null @@ -1,13 +0,0 @@ -import source from '$lib/actions/cssVars.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - description: - 'Reactively set CSS variables using a single object. Not as commonly needed after `<div style:--prop={value}>` support was added, but cssVars is more terse', - }, - }; -} diff --git a/packages/svelte-ux/src/routes/docs/actions/dataBackground/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/dataBackground/+page.svelte index 15e7fa945..8884c3b80 100644 --- a/packages/svelte-ux/src/routes/docs/actions/dataBackground/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/actions/dataBackground/+page.svelte @@ -87,7 +87,8 @@ </div> </Field> - <Button on:click={() => (values = getValues())} variant="fill" color="accent">Update data</Button> + <Button on:click={() => (values = getValues())} variant="fill" color="primary">Update data</Button + > </div> <h2>Basic</h2> @@ -99,7 +100,7 @@ {#key duration} <tr> <td - class="text-right border border-gray-100 tabular-nums" + class="text-right border tabular-nums" use:dataBackground={{ value, color: value > 0 ? 'hsl(140 80% 80%)' : 'hsl(0 80% 80%)', @@ -128,7 +129,7 @@ <tr> <td class={cls( - 'text-right border border-gray-100 tabular-nums', + 'text-right border tabular-nums', value > 0 ? 'from-green-300 to-green-500' : 'from-red-500 to-red-300' )} use:dataBackground={{ diff --git a/packages/svelte-ux/src/routes/docs/actions/layout/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/layout/+page.svelte index 5fcde372b..c409b1e62 100644 --- a/packages/svelte-ux/src/routes/docs/actions/layout/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/actions/layout/+page.svelte @@ -42,15 +42,15 @@ <Preview> <div class="mb-2"> - <Button on:click={() => (overflowItems += 1)} variant="fill" color="accent">+ item</Button> + <Button on:click={() => (overflowItems += 1)} variant="fill" color="primary">+ item</Button> <Button on:click={() => (overflowItems -= overflowItems > 1 ? 1 : 0)} variant="fill" - color="accent">- item</Button + color="primary">- item</Button > </div> <div - class="w-1/2 h-[100px] border border-black/20 rounded-lg bg-white whitespace-nowrap truncate p-4 resize overflow-auto" + class="w-1/2 h-[100px] border rounded-lg bg-surface-100 whitespace-nowrap truncate p-4 resize overflow-auto" use:overflow on:overflow={(e) => { overflowX = e.detail.overflowX; diff --git a/packages/svelte-ux/src/routes/docs/actions/mouse/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/mouse/+page.svelte index 2550740dd..60f492ddf 100644 --- a/packages/svelte-ux/src/routes/docs/actions/mouse/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/actions/mouse/+page.svelte @@ -26,14 +26,14 @@ <Preview> <button - class="border rounded p-2 text-sm hover:bg-black/5" + class="border rounded p-2 text-sm hover:bg-surface-content/5" use:longpress={1000} on:longpress={() => (longpressed = !longpressed)} > Click and hold </button> {#if longpressed} - <span class="text-xs text-black/50">Success! Repeat to hide</span> + <span class="text-xs text-surface-content/50">Success! Repeat to hide</span> {/if} </Preview> diff --git a/packages/svelte-ux/src/routes/docs/actions/observer/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/observer/+page.svelte index 3ffa1f22f..c88d50acf 100644 --- a/packages/svelte-ux/src/routes/docs/actions/observer/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/actions/observer/+page.svelte @@ -24,7 +24,7 @@ console.log(e.detail); e.target.innerText = JSON.stringify(e.detail.contentRect, null, 2); }} - class="resize overflow-auto whitespace-pre outline outline-gray-200 rounded" + class="resize overflow-auto whitespace-pre outline rounded" /> </Preview> @@ -36,7 +36,7 @@ on:resize={(e) => { e.target.innerText = JSON.stringify(e.target.getBoundingClientRect(), null, 2); }} - class="resize overflow-auto whitespace-pre outline outline-gray-200 rounded" + class="resize overflow-auto whitespace-pre outline rounded" /> </Preview> @@ -90,7 +90,7 @@ <div class="relative overflow-hidden"> {#if showHeader} <div - class="absolute top-0 left-0 bg-accent-500 text-white p-4 w-full" + class="absolute top-0 left-0 bg-primary text-primary-content p-4 w-full" transition:fly={{ y: '-100%', opacity: 1 }} > Header diff --git a/packages/svelte-ux/src/routes/docs/actions/scroll/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/scroll/+page.svelte index fc527b9bc..9923f0073 100644 --- a/packages/svelte-ux/src/routes/docs/actions/scroll/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/actions/scroll/+page.svelte @@ -6,6 +6,7 @@ import Preview from '$lib/components/Preview.svelte'; import { scrollIntoView, scrollFade, scrollShadow } from '$lib/actions/scroll'; + import { cls } from '$lib/utils/styles'; let filterItems = false; @@ -32,7 +33,7 @@ {#each items as item, i} <div use:scrollIntoView={{ condition: scrolledIndex === i }} - class:bg-gray-200={scrolledIndex === i} + class={cls(scrolledIndex === i && 'bg-surface-content/10')} > {item} </div> @@ -51,7 +52,7 @@ {#each items as item, i} <div use:scrollIntoView={{ condition: scrolledIndex === i, onlyIfNeeded: true }} - class:bg-gray-200={scrolledIndex === i} + class={cls(scrolledIndex === i && 'bg-surface-content/10')} > {item} </div> @@ -149,7 +150,7 @@ </Preview> <div> - <Button variant="fill" color="accent" on:click={() => (filterItems = !filterItems)} + <Button variant="fill" color="primary" on:click={() => (filterItems = !filterItems)} >Toggle filter</Button > </div> diff --git a/packages/svelte-ux/src/routes/docs/actions/spotlight/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/spotlight/+page.svelte index 8f3fe38af..79171494b 100644 --- a/packages/svelte-ux/src/routes/docs/actions/spotlight/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/actions/spotlight/+page.svelte @@ -33,16 +33,24 @@ use:spotlight={{ radius: '200px', borderWidth: '1px', - borderColorStops: '#999, #999, transparent', - surfaceColorStops: '#fff, #fff', + borderColorStops: 'var(--border_base), var(--border_base), transparent', + surfaceColorStops: 'var(--surface_base), var(--surface_base)', hover: { radius: '400px', borderWidth: '2px', - borderColorStops: 'var(--color-cyan-300) 5%, var(--color-blue-500)', - surfaceColorStops: 'rgb(255 255 255 / 90%), #fff', + borderColorStops: 'var(--border_hover_1) 5%, var(--border_hover_2)', + surfaceColorStops: 'var(--surface_hover_1), var(--surface_hover_2)', }, }} - class="border p-4 transition-shadow hover:shadow-md rounded-lg before:rounded-lg" + class={cls( + 'border p-4 transition-shadow hover:shadow-md rounded-lg before:rounded-lg', + '[--border_base:theme(colors.surface-content/50%)]', + '[--border_hover_1:theme(colors.primary)]', + '[--border_hover_2:theme(colors.secondary)]', + '[--surface_base:theme(colors.surface-200)]', + '[--surface_hover_1:theme(colors.surface-100/90%)]', + '[--surface_hover_2:theme(colors.surface-100)]' + )} > {item} </div> @@ -61,11 +69,11 @@ 'border p-4 transition-shadow hover:shadow-md rounded-lg before:rounded-lg', '[--spotlight-radius:200px]', '[--spotlight-border-width:1px]', - '[--spotlight-border-color-stops:#999,#999,transparent]', - '[--spotlight-surface-color-stops:#fff,#fff]', + '[--spotlight-border-color-stops:theme(colors.surface-content/50%),theme(colors.surface-content/50%),transparent]', + '[--spotlight-surface-color-stops:theme(colors.surface-200),theme(colors.surface-200)]', 'hover:[--spotlight-border-width:2px]', - 'hover:[--spotlight-border-color-stops:var(--color-cyan-300)_5%,_var(--color-blue-500)]', - 'hover:[--spotlight-surface-color-stops:rgb(255_255_255/90%),_#fff]' + 'hover:[--spotlight-border-color-stops:theme(colors.primary)_5%,theme(colors.secondary)]', + 'hover:[--spotlight-surface-color-stops:theme(colors.surface-100/90%),theme(colors.surface-100)]' )} > {item} @@ -74,51 +82,24 @@ </div> </Preview> -<h2>Effect example 1</h2> - -<Preview> - <div class="grid grid-cols-sm gap-3"> - {#each items as item, i} - <div - use:spotlight={{ - radius: '200px', - borderWidth: '1px', - borderColorStops: '#999, #999, transparent', - surfaceColorStops: '#fff, #fff', - hover: { - radius: '400px', - borderWidth: '2px', - borderColorStops: 'var(--color-cyan-300) 5%, var(--color-blue-500)', - surfaceColorStops: 'rgb(255 255 255 / 90%), #fff', - }, - }} - class="p-4 transition-shadow hover:shadow-md rounded-lg before:rounded-lg" - > - {item} - </div> - {/each} - </div> -</Preview> - -<h2>Effect example 1</h2> +<h2>Line example</h2> <Preview> <div class="grid grid-cols-sm gap-3"> {#each items as item, i} <div - use:spotlight={{ - radius: '100px', - borderWidth: '1px', - borderColorStops: '#999, #999, transparent', - surfaceColorStops: '#fff, #fff', - hover: { - radius: '50px', - borderWidth: '2px', - borderColorStops: 'var(--color-cyan-300) 100%, transparent', - surfaceColorStops: 'rgb(255 255 255 / 90%), #fff', - }, - }} - class="border px-4 py-8 transition-shadow rounded-lg before:rounded-lg" + use:spotlight + class={cls( + 'border px-4 py-8 transition-shadow hover:shadow-md rounded-lg before:rounded-lg', + '[--spotlight-radius:100px]', + '[--spotlight-border-width:1px]', + '[--spotlight-border-color-stops:theme(colors.surface-content/50%),theme(colors.surface-content/50%),transparent]', + '[--spotlight-surface-color-stops:theme(colors.surface-200),theme(colors.surface-200)]', + 'hover:[--spotlight-radius:50px]', + 'hover:[--spotlight-border-width:2px]', + 'hover:[--spotlight-border-color-stops:theme(colors.primary)_100%,transparent]', + 'hover:[--spotlight-surface-color-stops:theme(colors.surface-200/90%),theme(colors.surface-200)]' + )} > {item} </div> diff --git a/packages/svelte-ux/src/routes/docs/actions/styleProps/+page.svelte b/packages/svelte-ux/src/routes/docs/actions/styleProps/+page.svelte new file mode 100644 index 000000000..5dfc7c8e0 --- /dev/null +++ b/packages/svelte-ux/src/routes/docs/actions/styleProps/+page.svelte @@ -0,0 +1,29 @@ +<script lang="ts"> + import Preview from '$lib/components/Preview.svelte'; + import Code from '$lib/components/Code.svelte'; + import TextField from '$lib/components/TextField.svelte'; + + import { styleProps } from '$lib/actions/styleProps'; + + let background = '#ddd'; + let border = '1px solid #aaa'; +</script> + +<h1>Usage</h1> + +<Code source={`import { styleProps } from 'svelte-ux';`} language="javascript" class="mb-4" /> + +<Preview> + {@const styles = { '--background': background, '--border': border }} + <div class="grid gap-4" use:styleProps={styles}> + <div + class="w-10 h-10 rounded" + style:background-color="var(--background)" + style:border="var(--border)" + /> + <div class="grid grid-flow-col gap-2"> + <TextField label="Background" bind:value={background} /> + <TextField label="Border" bind:value={border} /> + </div> + </div> +</Preview> diff --git a/packages/svelte-ux/src/routes/docs/actions/styleProps/+page.ts b/packages/svelte-ux/src/routes/docs/actions/styleProps/+page.ts new file mode 100644 index 000000000..08689da4e --- /dev/null +++ b/packages/svelte-ux/src/routes/docs/actions/styleProps/+page.ts @@ -0,0 +1,12 @@ +import source from '$lib/actions/styleProps.ts?raw'; +import pageSource from './+page.svelte?raw'; + +export async function load() { + return { + meta: { + source, + pageSource, + description: 'Reactively set style properties using a single object.', + }, + }; +} diff --git a/packages/svelte-ux/src/routes/docs/components/AppBar/+page.svelte b/packages/svelte-ux/src/routes/docs/components/AppBar/+page.svelte index de68d0f25..0a912ef63 100644 --- a/packages/svelte-ux/src/routes/docs/components/AppBar/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/AppBar/+page.svelte @@ -42,7 +42,7 @@ <Preview> <AppBar title="Example"> <div slot="actions"> - <Button icon={mdiRefresh} class="p-2 hover:bg-white/10" /> + <Button icon={mdiRefresh} class="p-2 hover:bg-surface-100/10" /> </div> </AppBar> </Preview> @@ -51,7 +51,7 @@ <Preview> <div class="grid gap-2"> - <AppBar title="Example" class="bg-accent-500 text-white" /> - <AppBar title="Example" class="bg-purple-500 text-white" /> + <AppBar title="Example" class="bg-primary text-primary-content" /> + <AppBar title="Example" class="bg-blue-500 text-primary-content" /> </div> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Avatar/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Avatar/+page.svelte index cb4fafefb..d9be8c302 100644 --- a/packages/svelte-ux/src/routes/docs/components/Avatar/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Avatar/+page.svelte @@ -17,7 +17,7 @@ <h2>Color</h2> <Preview> - <Avatar class="bg-accent-500 text-white font-bold">A</Avatar> + <Avatar class="bg-primary text-primary-content font-bold">A</Avatar> </Preview> <h2>Border</h2> @@ -29,21 +29,21 @@ <h2>Size</h2> <Preview> - <Avatar class="bg-accent-500 text-white font-bold text-xs" size="sm">sm</Avatar> - <Avatar class="bg-accent-500 text-white font-bold" size="md">md</Avatar> - <Avatar class="bg-accent-500 text-white font-bold" size="lg">lg</Avatar> + <Avatar class="bg-primary text-primary-content font-bold text-xs" size="sm">sm</Avatar> + <Avatar class="bg-primary text-primary-content font-bold" size="md">md</Avatar> + <Avatar class="bg-primary text-primary-content font-bold" size="lg">lg</Avatar> </Preview> <h2>Icon (prop)</h2> <Preview> - <Avatar class="bg-accent-500 text-white" icon={mdiAccount} /> + <Avatar class="bg-primary text-primary-content" icon={mdiAccount} /> </Preview> <h2>Icon (slot)</h2> <Preview> - <Avatar class="bg-accent-500"> - <Icon path={mdiAccount} class="text-white" /> + <Avatar class="bg-primary"> + <Icon path={mdiAccount} class="text-primary-content" /> </Avatar> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Badge/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Badge/+page.svelte index 132a7686c..7cc19b969 100644 --- a/packages/svelte-ux/src/routes/docs/components/Badge/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Badge/+page.svelte @@ -66,7 +66,7 @@ <h2>Style</h2> <Preview> - <Badge {value} circle class="bg-green-500"> + <Badge {value} circle class="bg-success text-success-content"> <Button icon={mdiFilterVariant} variant="outline" class="p-3" /> </Badge> </Preview> @@ -76,7 +76,7 @@ <Preview> <Badge {value} circle> <Button icon={mdiFilterVariant} variant="outline" class="p-3" /> - <div slot="value" class="bg-green-500 text-white rounded-full"> + <div slot="value" class="bg-success text-success-content rounded-full"> <Icon path={mdiPlus} /> </div> </Badge> @@ -85,8 +85,8 @@ <h2>Multiple</h2> <Preview> - <Badge placement="bottom-right" {value} dot circle class="bg-red-500"> - <Badge placement="top-right" {value} dot circle class="bg-green-500"> + <Badge placement="bottom-right" {value} dot circle class="bg-danger"> + <Badge placement="top-right" {value} dot circle class="bg-success"> <Button icon={mdiFilterVariant} variant="outline" class="p-3" /> </Badge> </Badge> @@ -96,7 +96,7 @@ <div class="grid grid-cols-5 gap-4"> <div> - <h3 class="text-sm text-black/50">Button w/ default</h3> + <h3 class="text-sm text-surface-content/50">Button w/ default</h3> <Preview> <Badge {value}> <Button variant="outline">Example</Button> @@ -105,7 +105,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ top-left</h3> + <h3 class="text-sm text-surface-content/50">Button w/ top-left</h3> <Preview> <Badge {value} placement="top-left"> <Button variant="outline">Example</Button> @@ -114,7 +114,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ top-right</h3> + <h3 class="text-sm text-surface-content/50">Button w/ top-right</h3> <Preview> <Badge {value} placement="top-right"> <Button variant="outline">Example</Button> @@ -123,7 +123,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ bottom-left</h3> + <h3 class="text-sm text-surface-content/50">Button w/ bottom-left</h3> <Preview> <Badge {value} placement="bottom-left"> <Button variant="outline">Example</Button> @@ -132,7 +132,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ bottom-right</h3> + <h3 class="text-sm text-surface-content/50">Button w/ bottom-right</h3> <Preview> <Badge {value} placement="bottom-right"> <Button variant="outline">Example</Button> @@ -141,7 +141,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ default</h3> + <h3 class="text-sm text-surface-content/50">Button w/ default</h3> <Preview> <Badge {value} small> <Button variant="outline">Example</Button> @@ -150,7 +150,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ top-left</h3> + <h3 class="text-sm text-surface-content/50">Button w/ top-left</h3> <Preview> <Badge {value} small placement="top-left"> <Button variant="outline">Example</Button> @@ -159,7 +159,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ top-right</h3> + <h3 class="text-sm text-surface-content/50">Button w/ top-right</h3> <Preview> <Badge {value} small placement="top-right"> <Button variant="outline">Example</Button> @@ -168,7 +168,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ bottom-left</h3> + <h3 class="text-sm text-surface-content/50">Button w/ bottom-left</h3> <Preview> <Badge {value} small placement="bottom-left"> <Button variant="outline">Example</Button> @@ -177,7 +177,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Button w/ bottom-right</h3> + <h3 class="text-sm text-surface-content/50">Button w/ bottom-right</h3> <Preview> <Badge {value} small placement="bottom-right"> <Button variant="outline">Example</Button> @@ -186,7 +186,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ default</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ default</h3> <Preview> <Badge {value} circle> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -195,7 +195,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ top-left</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ top-left</h3> <Preview> <Badge {value} circle placement="top-left"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -204,7 +204,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ top-right</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ top-right</h3> <Preview> <Badge {value} circle placement="top-right"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -213,7 +213,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ bottom-left</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ bottom-left</h3> <Preview> <Badge {value} circle placement="bottom-left"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -222,7 +222,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ bottom-right</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ bottom-right</h3> <Preview> <Badge {value} circle placement="bottom-right"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -231,7 +231,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ default</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ default</h3> <Preview> <Badge {value} circle small> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -240,7 +240,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ top-left</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ top-left</h3> <Preview> <Badge {value} circle small placement="top-left"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -249,7 +249,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ top-right</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ top-right</h3> <Preview> <Badge {value} circle small placement="top-right"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -258,7 +258,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ bottom-left</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ bottom-left</h3> <Preview> <Badge {value} circle small placement="bottom-left"> <Button icon={mdiFilterVariant} class="border p-3" /> @@ -267,7 +267,7 @@ </div> <div> - <h3 class="text-sm text-black/50">Icon Button w/ bottom-right</h3> + <h3 class="text-sm text-surface-content/50">Icon Button w/ bottom-right</h3> <Preview> <Badge {value} circle small placement="bottom-right"> <Button icon={mdiFilterVariant} class="border p-3" /> diff --git a/packages/svelte-ux/src/routes/docs/components/Breadcrumb/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Breadcrumb/+page.svelte index 70e656d8c..171034667 100644 --- a/packages/svelte-ux/src/routes/docs/components/Breadcrumb/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Breadcrumb/+page.svelte @@ -44,7 +44,7 @@ <Preview> <Breadcrumb {items} class="gap-2"> - <Icon slot="divider" path={mdiArrowRight} class="text-black/25" /> + <Icon slot="divider" path={mdiArrowRight} class="text-surface-content/25" /> </Breadcrumb> </Preview> @@ -55,7 +55,7 @@ <Preview> <Breadcrumb items={labeledItems} class="gap-2"> <span slot="item" let:item> - <div class="text-black/50 text-xs uppercase">{item.label}</div> + <div class="text-surface-content/50 text-xs uppercase">{item.label}</div> <div>{item.value}</div> </span> </Breadcrumb> @@ -69,7 +69,7 @@ <Breadcrumb items={labeledItems}> <Button slot="item" let:item> <div> - <div class="text-black/50 text-xs uppercase">{item.label}</div> + <div class="text-surface-content/50 text-xs uppercase">{item.label}</div> <div>{item.value}</div> </div> </Button> @@ -81,10 +81,10 @@ <Preview> <Breadcrumb items={labeledItems} class="gap-2"> <span slot="item" let:item> - <span class="text-black/50 text-sm font-extrabold">{item.label}:</span> - <span class="text-black/50 text-sm">{item.value}</span> + <span class="text-surface-content/50 text-sm font-extrabold">{item.label}:</span> + <span class="text-surface-content/50 text-sm">{item.value}</span> </span> - <DividerDot slot="divider" class="text-black/50" /> + <DividerDot slot="divider" class="text-surface-content/50" /> </Breadcrumb> </Preview> @@ -105,7 +105,7 @@ <h3>inherit</h3> <Preview> - <div class="bg-black text-white p-2 rounded"> + <div class="bg-primary text-primary-content p-2 rounded"> <Breadcrumb {items} /> </div> </Preview> @@ -115,7 +115,7 @@ <h3>text class</h3> <Preview> - <Breadcrumb {items} class="text-accent-500" /> + <Breadcrumb {items} class="text-primary" /> </Preview> <h2>Truncate long text</h2> diff --git a/packages/svelte-ux/src/routes/docs/components/Button/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Button/+page.svelte index d13db9a2f..4d4862c0c 100644 --- a/packages/svelte-ux/src/routes/docs/components/Button/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Button/+page.svelte @@ -3,10 +3,15 @@ import { faUser } from '@fortawesome/free-solid-svg-icons'; import Button from '$lib/components/Button.svelte'; + import Field from '$lib/components/Field.svelte'; import Preview from '$lib/components/Preview.svelte'; import SectionDivider from '$lib/components/SectionDivider.svelte'; import Tooltip from '$lib/components/Tooltip.svelte'; import Toggle from '$lib/components/Toggle.svelte'; + import ToggleGroup from '$lib/components/ToggleGroup.svelte'; + import ToggleOption from '$lib/components/ToggleOption.svelte'; + + let size: 'sm' | 'md' | 'lg' = 'md'; </script> <h1>Examples</h1> @@ -33,30 +38,30 @@ <Preview> <Button loading>Loading...</Button> - <Button variant="outline" color="accent" loading>Loading...</Button> - <Button variant="fill" color="accent" loading>Loading...</Button> - <Button variant="fill-light" color="accent" loading>Loading...</Button> - <Button variant="fill-outline" color="accent" loading>Loading...</Button> - <Button variant="text" color="accent" loading>Loading...</Button> + <Button variant="outline" color="primary" loading>Loading...</Button> + <Button variant="fill" color="primary" loading>Loading...</Button> + <Button variant="fill-light" color="primary" loading>Loading...</Button> + <Button variant="fill-outline" color="primary" loading>Loading...</Button> + <Button variant="text" color="primary" loading>Loading...</Button> <div class="mt-2"> <Toggle let:on={loading} let:toggle> <Button {loading} on:click={toggle}>Click me</Button> </Toggle> <Toggle let:on={loading} let:toggle> - <Button variant="outline" color="accent" {loading} on:click={toggle}>Click me</Button> + <Button variant="outline" color="primary" {loading} on:click={toggle}>Click me</Button> </Toggle> <Toggle let:on={loading} let:toggle> - <Button variant="fill" color="accent" {loading} on:click={toggle}>Click me</Button> + <Button variant="fill" color="primary" {loading} on:click={toggle}>Click me</Button> </Toggle> <Toggle let:on={loading} let:toggle> - <Button variant="fill-light" color="accent" {loading} on:click={toggle}>Click me</Button> + <Button variant="fill-light" color="primary" {loading} on:click={toggle}>Click me</Button> </Toggle> <Toggle let:on={loading} let:toggle> - <Button variant="fill-outline" color="accent" {loading} on:click={toggle}>Click me</Button> + <Button variant="fill-outline" color="primary" {loading} on:click={toggle}>Click me</Button> </Toggle> <Toggle let:on={loading} let:toggle> - <Button variant="text" color="accent" {loading} on:click={toggle}>Click me</Button> + <Button variant="text" color="primary" {loading} on:click={toggle}>Click me</Button> </Toggle> </div> @@ -65,79 +70,77 @@ <Button icon={faUser} {loading} on:click={toggle}>Click me</Button> </Toggle> <Toggle let:on={loading} let:toggle> - <Button icon={faUser} variant="outline" color="accent" {loading} on:click={toggle} + <Button icon={faUser} variant="outline" color="primary" {loading} on:click={toggle} >Click me</Button > </Toggle> <Toggle let:on={loading} let:toggle> - <Button icon={faUser} variant="fill" color="accent" {loading} on:click={toggle} + <Button icon={faUser} variant="fill" color="primary" {loading} on:click={toggle} >Click me</Button > </Toggle> <Toggle let:on={loading} let:toggle> - <Button icon={faUser} variant="fill-light" color="accent" {loading} on:click={toggle} + <Button icon={faUser} variant="fill-light" color="primary" {loading} on:click={toggle} >Click me</Button > </Toggle> <Toggle let:on={loading} let:toggle> - <Button icon={faUser} variant="fill-outline" color="accent" {loading} on:click={toggle} + <Button icon={faUser} variant="fill-outline" color="primary" {loading} on:click={toggle} >Click me</Button > </Toggle> <Toggle let:on={loading} let:toggle> - <Button icon={faUser} variant="text" color="accent" {loading} on:click={toggle} + <Button icon={faUser} variant="text" color="primary" {loading} on:click={toggle} >Click me</Button > </Toggle> </div> </Preview> -<h2>Variants</h2> +<div class="grid grid-cols-[1fr,auto] gap-2 items-end"> + <h2>Variants, Color & Size</h2> + <Field label="size: " labelPlacement="left" class="mb-1"> + <ToggleGroup bind:value={size} size="sm"> + <ToggleOption value="sm">sm</ToggleOption> + <ToggleOption value="md">md</ToggleOption> + <ToggleOption value="lg">lg</ToggleOption> + </ToggleGroup> + </Field> +</div> <Preview> - <div class="grid gap-2"> - <div> - <Button>default</Button> - <Button color="blue">default</Button> - <Button color="red">default</Button> - <Button color="green">default</Button> - <Button color="gray">default</Button> - </div> - <div> - <Button variant="outline">outline</Button> - <Button variant="outline" color="blue">outline</Button> - <Button variant="outline" color="red">outline</Button> - <Button variant="outline" color="green">outline</Button> - <Button variant="outline" color="gray">outline</Button> - </div> - <div> - <Button variant="fill">fill</Button> - <Button variant="fill" color="blue">fill</Button> - <Button variant="fill" color="red">fill</Button> - <Button variant="fill" color="green">fill</Button> - <Button variant="fill" color="gray">fill</Button> - </div> - <div> - <Button variant="fill-light">fill-light</Button> - <Button variant="fill-light" color="blue">fill-light</Button> - <Button variant="fill-light" color="red">fill-light</Button> - <Button variant="fill-light" color="green">fill-light</Button> - <Button variant="fill-light" color="gray">fill-light</Button> - </div> - <div> - <Button variant="fill-outline">fill-outline</Button> - <Button variant="fill-outline" color="blue">fill-outline</Button> - <Button variant="fill-outline" color="red">fill-outline</Button> - <Button variant="fill-outline" color="green">fill-outline</Button> - <Button variant="fill-outline" color="gray">fill-outline</Button> - </div> - <div> - <Button variant="text">text</Button> - <Button variant="text" color="blue">text</Button> - <Button variant="text" color="red">text</Button> - <Button variant="text" color="green">text</Button> - <Button variant="text" color="gray">text</Button> - </div> + <div class="grid gap-3 divide-y"> + {#each ['default', 'outline', 'fill', 'fill-light', 'fill-outline', 'text'] as variant} + <div> + <div class="font-semibold my-2">{variant}</div> + <div class="grid gap-2 ml-4"> + <!-- Theme colors --> + <div> + <Button {variant} {size}>Default</Button> + <Button {variant} {size} color="primary">Primary</Button> + <Button {variant} {size} color="secondary">Secondary</Button> + <Button {variant} {size} color="accent">Accent</Button> + <Button {variant} {size} color="neutral">Neutral</Button> + </div> + <div> + <!-- State colors --> + <Button {variant} {size} color="info">Info</Button> + <Button {variant} {size} color="success">Success</Button> + <Button {variant} {size} color="warning">Warning</Button> + <Button {variant} {size} color="danger">Danger</Button> + </div> + <div> + <!-- TODO: CSS variables for each variant --> + <!-- <Button {variant} {size} class="[--bg-color:theme(colors.blue.500)] [--text-color:white]"> + Color Variables + </Button> + <Button {variant} {size} class="[--bg-color:theme(colors.emerald.500)] [--text-color:white]"> + Color Variables + </Button> --> + </div> + </div> + </div> + {/each} </div> </Preview> @@ -147,58 +150,6 @@ <Button variant="none">Click me</Button> </Preview> -<h2>Size</h2> - -<Preview> - {#each ['sm', 'md', 'lg'] as size} - <div class="[&:not(:first-child)]:mt-4">{size}</div> - <div class="grid gap-2 ml-3"> - <div> - <Button {size}>default</Button> - <Button color="blue" {size}>default</Button> - <Button color="red" {size}>default</Button> - <Button color="green" {size}>default</Button> - <Button color="gray" {size}>default</Button> - </div> - <div> - <Button variant="outline" {size}>outline</Button> - <Button variant="outline" {size} color="blue">outline</Button> - <Button variant="outline" {size} color="red">outline</Button> - <Button variant="outline" {size} color="green">outline</Button> - <Button variant="outline" {size} color="gray">outline</Button> - </div> - <div> - <Button variant="fill" {size}>fill</Button> - <Button variant="fill" {size} color="blue">fill</Button> - <Button variant="fill" {size} color="red">fill</Button> - <Button variant="fill" {size} color="green">fill</Button> - <Button variant="fill" {size} color="gray">fill</Button> - </div> - <div> - <Button variant="fill-light" {size}>fill-light</Button> - <Button variant="fill-light" {size} color="blue">fill-light</Button> - <Button variant="fill-light" {size} color="red">fill-light</Button> - <Button variant="fill-light" {size} color="green">fill-light</Button> - <Button variant="fill-light" {size} color="gray">fill-light</Button> - </div> - <div> - <Button variant="fill-outline" {size}>fill-outline</Button> - <Button variant="fill-outline" {size} color="blue">fill-outline</Button> - <Button variant="fill-outline" {size} color="red">fill-outline</Button> - <Button variant="fill-outline" {size} color="green">fill-outline</Button> - <Button variant="fill-outline" {size} color="gray">fill-outline</Button> - </div> - <div> - <Button variant="text" {size}>text</Button> - <Button variant="text" {size} color="blue">text</Button> - <Button variant="text" {size} color="red">text</Button> - <Button variant="text" {size} color="green">text</Button> - <Button variant="text" {size} color="gray">text</Button> - </div> - </div> - {/each} -</Preview> - <h2>Rounded</h2> <Preview> @@ -210,28 +161,28 @@ <Button rounded={false}>false</Button> </div> <div> - <Button variant="outline" color="accent">default</Button> - <Button variant="outline" color="accent" rounded>rounded</Button> - <Button variant="outline" color="accent" rounded="full">full</Button> - <Button variant="outline" color="accent" rounded={false}>false</Button> + <Button variant="outline" color="primary">default</Button> + <Button variant="outline" color="primary" rounded>rounded</Button> + <Button variant="outline" color="primary" rounded="full">full</Button> + <Button variant="outline" color="primary" rounded={false}>false</Button> </div> <div> - <Button variant="fill" color="accent">default</Button> - <Button variant="fill" color="accent" rounded>rounded</Button> - <Button variant="fill" color="accent" rounded="full">full</Button> - <Button variant="fill" color="accent" rounded={false}>false</Button> + <Button variant="fill" color="primary">default</Button> + <Button variant="fill" color="primary" rounded>rounded</Button> + <Button variant="fill" color="primary" rounded="full">full</Button> + <Button variant="fill" color="primary" rounded={false}>false</Button> </div> <div> - <Button variant="fill-light" color="accent">default</Button> - <Button variant="fill-light" color="accent" rounded>rounded</Button> - <Button variant="fill-light" color="accent" rounded="full">full</Button> - <Button variant="fill-light" color="accent" rounded={false}>false</Button> + <Button variant="fill-light" color="primary">default</Button> + <Button variant="fill-light" color="primary" rounded>rounded</Button> + <Button variant="fill-light" color="primary" rounded="full">full</Button> + <Button variant="fill-light" color="primary" rounded={false}>false</Button> </div> <div> - <Button variant="fill-outline" color="accent">default</Button> - <Button variant="fill-outline" color="accent" rounded>rounded</Button> - <Button variant="fill-outline" color="accent" rounded="full">full</Button> - <Button variant="fill-outline" color="accent" rounded={false}>false</Button> + <Button variant="fill-outline" color="primary">default</Button> + <Button variant="fill-outline" color="primary" rounded>rounded</Button> + <Button variant="fill-outline" color="primary" rounded="full">full</Button> + <Button variant="fill-outline" color="primary" rounded={false}>false</Button> </div> </div> </Preview> @@ -240,11 +191,11 @@ <Preview> <Button class="uppercase">default</Button> - <Button class="uppercase" variant="outline" color="accent">outline</Button> - <Button class="uppercase" variant="fill" color="accent">fill</Button> - <Button class="uppercase" variant="fill-light" color="accent">fill-light</Button> - <Button class="uppercase" variant="fill-outline" color="accent">fill-outline</Button> - <Button class="uppercase" variant="text" color="accent">text</Button> + <Button class="uppercase" variant="outline" color="primary">outline</Button> + <Button class="uppercase" variant="fill" color="primary">fill</Button> + <Button class="uppercase" variant="fill-light" color="primary">fill-light</Button> + <Button class="uppercase" variant="fill-outline" color="primary">fill-outline</Button> + <Button class="uppercase" variant="text" color="primary">text</Button> </Preview> <h2>Tooltip</h2> @@ -267,7 +218,7 @@ <Preview> <div class="flex items-center"> - <Button icon={mdiTrashCan} color="red">Delete</Button> + <Button icon={mdiTrashCan} color="danger">Delete</Button> <Button icon={mdiMagnify} class="flex-row-reverse">Search</Button> <Button icon={mdiHome} class="flex-col">Home</Button> <Button icon={mdiHome} class="flex-col-reverse">Home</Button> @@ -278,9 +229,9 @@ <h2>Pass props to Icon</h2> <Preview> - <Button icon={{ data: mdiTrashCan, size: '2rem', style: 'color:#b91c1c' }} color="red" - >Delete</Button - > + <Button icon={{ data: mdiTrashCan, size: '2rem', style: 'color: crimson' }} color="danger"> + Delete + </Button> </Preview> <SectionDivider class="mt-12">Icon only</SectionDivider> @@ -325,26 +276,26 @@ <Preview> <div> <Button icon={mdiMenu} /> - <Button icon={mdiMenu} color="accent" /> + <Button icon={mdiMenu} color="primary" /> </div> <div> <Button icon={mdiMenu} variant="outline" /> - <Button icon={mdiMenu} variant="outline" color="accent" /> + <Button icon={mdiMenu} variant="outline" color="primary" /> </div> <div> <Button icon={mdiMenu} variant="fill" /> - <Button icon={mdiMenu} variant="fill" color="accent" /> + <Button icon={mdiMenu} variant="fill" color="primary" /> </div> <div> <Button icon={mdiMenu} variant="fill-light" /> - <Button icon={mdiMenu} variant="fill-light" color="accent" /> + <Button icon={mdiMenu} variant="fill-light" color="primary" /> </div> <div> <Button icon={mdiMenu} variant="fill-outline" /> - <Button icon={mdiMenu} variant="fill-outline" color="accent" /> + <Button icon={mdiMenu} variant="fill-outline" color="primary" /> </div> <div> <Button icon={mdiMenu} variant="text" /> - <Button icon={mdiMenu} variant="text" color="accent" /> + <Button icon={mdiMenu} variant="text" color="primary" /> </div> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/ButtonGroup/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ButtonGroup/+page.svelte index 9c0f32d20..b2bb57101 100644 --- a/packages/svelte-ux/src/routes/docs/components/ButtonGroup/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ButtonGroup/+page.svelte @@ -22,7 +22,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup color="accent"> + <ButtonGroup color="primary"> <Button>Left</Button> <Button>Center</Button> <Button>Right</Button> @@ -34,19 +34,19 @@ <Button>Right</Button> </ButtonGroup> - <ButtonGroup variant="fill" color="accent"> + <ButtonGroup variant="fill" color="primary"> <Button>Left</Button> <Button>Center</Button> <Button>Right</Button> </ButtonGroup> - <ButtonGroup variant="fill-light" color="accent"> + <ButtonGroup variant="fill-light" color="primary"> <Button>Left</Button> <Button>Center</Button> <Button>Right</Button> </ButtonGroup> - <ButtonGroup variant="fill-outline" color="accent"> + <ButtonGroup variant="fill-outline" color="primary"> <Button>Left</Button> <Button>Center</Button> <Button>Right</Button> @@ -58,7 +58,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup color="accent"> + <ButtonGroup color="primary"> <Button icon={mdiFormatAlignLeft} /> <Button icon={mdiFormatAlignCenter} /> <Button icon={mdiFormatAlignRight} /> @@ -70,19 +70,19 @@ <Button icon={mdiFormatAlignRight} /> </ButtonGroup> - <ButtonGroup variant="fill" color="accent"> + <ButtonGroup variant="fill" color="primary"> <Button icon={mdiFormatAlignLeft} /> <Button icon={mdiFormatAlignCenter} /> <Button icon={mdiFormatAlignRight} /> </ButtonGroup> - <ButtonGroup variant="fill-light" color="accent"> + <ButtonGroup variant="fill-light" color="primary"> <Button icon={mdiFormatAlignLeft} /> <Button icon={mdiFormatAlignCenter} /> <Button icon={mdiFormatAlignRight} /> </ButtonGroup> - <ButtonGroup variant="fill-outline" color="accent"> + <ButtonGroup variant="fill-outline" color="primary"> <Button icon={mdiFormatAlignLeft} /> <Button icon={mdiFormatAlignCenter} /> <Button icon={mdiFormatAlignRight} /> @@ -94,7 +94,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup color="accent"> + <ButtonGroup color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> @@ -106,19 +106,19 @@ <Button icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> - <ButtonGroup variant="fill" color="accent"> + <ButtonGroup variant="fill" color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> - <ButtonGroup variant="fill-light" color="accent"> + <ButtonGroup variant="fill-light" color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> - <ButtonGroup variant="fill-outline" color="accent"> + <ButtonGroup variant="fill-outline" color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> @@ -130,7 +130,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup color="accent"> + <ButtonGroup color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} variant="fill-light" /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> @@ -142,29 +142,29 @@ icon={mdiFormatAlignCenter} iconOnly={false} variant="fill-outline" - color="accent" + color="primary" class="z-10" /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> - <ButtonGroup variant="fill" color="accent"> + <ButtonGroup variant="fill" color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} - class="bg-accent-600 hover:bg-accent-700" + class="bg-primary-700 hover:bg-primary-900" /> </ButtonGroup> - <ButtonGroup variant="fill-light" color="accent"> + <ButtonGroup variant="fill-light" color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} variant="fill" /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> - <ButtonGroup variant="fill-outline" color="accent"> + <ButtonGroup variant="fill-outline" color="primary"> <Button icon={mdiFormatAlignLeft} iconOnly={false} variant="fill" /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> @@ -176,7 +176,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup size="sm" color="accent"> + <ButtonGroup size="sm" color="primary"> <Button icon={mdiBookmark}>Bookmark</Button> <Button>12k</Button> </ButtonGroup> @@ -186,17 +186,17 @@ <Button>12k</Button> </ButtonGroup> - <ButtonGroup variant="fill" size="sm" color="accent"> + <ButtonGroup variant="fill" size="sm" color="primary"> <Button icon={mdiBookmark}>Bookmark</Button> <Button>12k</Button> </ButtonGroup> - <ButtonGroup variant="fill-light" size="sm" color="accent"> + <ButtonGroup variant="fill-light" size="sm" color="primary"> <Button icon={mdiBookmark}>Bookmark</Button> <Button>12k</Button> </ButtonGroup> - <ButtonGroup variant="fill-outline" size="sm" color="accent"> + <ButtonGroup variant="fill-outline" size="sm" color="primary"> <Button icon={mdiBookmark}>Bookmark</Button> <Button>12k</Button> </ButtonGroup> @@ -207,7 +207,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup color="accent" disabled> + <ButtonGroup color="primary" disabled> <Button icon={mdiFormatAlignLeft} iconOnly={false} /> <Button icon={mdiFormatAlignCenter} iconOnly={false} /> <Button icon={mdiFormatAlignRight} iconOnly={false} /> @@ -220,21 +220,21 @@ </ButtonGroup> <ButtonGroup variant="fill" disabled> - <Button color="accent" icon={mdiFormatAlignLeft} iconOnly={false} /> - <Button color="accent" icon={mdiFormatAlignCenter} iconOnly={false} /> - <Button color="accent" icon={mdiFormatAlignRight} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignLeft} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignCenter} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> <ButtonGroup variant="fill-light" disabled> - <Button color="accent" icon={mdiFormatAlignLeft} iconOnly={false} /> - <Button color="accent" icon={mdiFormatAlignCenter} iconOnly={false} /> - <Button color="accent" icon={mdiFormatAlignRight} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignLeft} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignCenter} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> <ButtonGroup variant="fill-outline" disabled> - <Button color="accent" icon={mdiFormatAlignLeft} iconOnly={false} /> - <Button color="accent" icon={mdiFormatAlignCenter} iconOnly={false} /> - <Button color="accent" icon={mdiFormatAlignRight} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignLeft} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignCenter} iconOnly={false} /> + <Button color="primary" icon={mdiFormatAlignRight} iconOnly={false} /> </ButtonGroup> </div> </Preview> @@ -273,7 +273,7 @@ </Toggle> </ButtonGroup> - <ButtonGroup variant="fill" color="accent"> + <ButtonGroup variant="fill" color="primary"> <Button>Click me</Button> <Toggle let:on={open} let:toggle> <span> @@ -288,7 +288,7 @@ </Toggle> </ButtonGroup> - <ButtonGroup variant="fill-light" color="accent"> + <ButtonGroup variant="fill-light" color="primary"> <Button>Click me</Button> <Toggle let:on={open} let:toggle> <span> @@ -303,7 +303,7 @@ </Toggle> </ButtonGroup> - <ButtonGroup variant="fill-outline" color="accent"> + <ButtonGroup variant="fill-outline" color="primary"> <Button>Click me</Button> <Toggle let:on={open} let:toggle> <span> @@ -324,7 +324,7 @@ <Preview> <div class="grid gap-2"> - <ButtonGroup color="accent"> + <ButtonGroup color="primary"> <Tooltip title="left" offset={2}> <Button icon={mdiFormatAlignLeft} /> </Tooltip> @@ -348,7 +348,7 @@ </Tooltip> </ButtonGroup> - <ButtonGroup variant="fill" color="accent"> + <ButtonGroup variant="fill" color="primary"> <Tooltip title="left" offset={2}> <Button icon={mdiFormatAlignLeft} /> </Tooltip> @@ -360,7 +360,7 @@ </Tooltip> </ButtonGroup> - <ButtonGroup variant="fill-light" color="accent"> + <ButtonGroup variant="fill-light" color="primary"> <Tooltip title="left" offset={2}> <Button icon={mdiFormatAlignLeft} /> </Tooltip> @@ -372,7 +372,7 @@ </Tooltip> </ButtonGroup> - <ButtonGroup variant="fill-outline" color="accent"> + <ButtonGroup variant="fill-outline" color="primary"> <Tooltip title="left" offset={2}> <Button icon={mdiFormatAlignLeft} /> </Tooltip> diff --git a/packages/svelte-ux/src/routes/docs/components/Card/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Card/+page.svelte index 93ea09b7f..6b351dec4 100644 --- a/packages/svelte-ux/src/routes/docs/components/Card/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Card/+page.svelte @@ -47,7 +47,7 @@ <Card> <Header title="Title" subheading="Subheading" slot="header"> <div slot="avatar"> - <Avatar class="bg-accent-500 text-white font-bold">A</Avatar> + <Avatar class="bg-primary text-primary-content font-bold">A</Avatar> </div> </Header> </Card> @@ -71,7 +71,7 @@ <Card> <Header title="Title" subheading="Subheading" slot="header"> <div slot="avatar"> - <Avatar class="bg-accent-500 text-white font-bold">A</Avatar> + <Avatar class="bg-primary text-primary-content font-bold">A</Avatar> </div> <div slot="actions"> <Button icon={mdiDotsVertical} class="w-12 h-12" /> diff --git a/packages/svelte-ux/src/routes/docs/components/Card/+page.ts b/packages/svelte-ux/src/routes/docs/components/Card/+page.ts index 375198e5d..f2c0242a4 100644 --- a/packages/svelte-ux/src/routes/docs/components/Card/+page.ts +++ b/packages/svelte-ux/src/routes/docs/components/Card/+page.ts @@ -5,6 +5,7 @@ import pageSource from './+page.svelte?raw'; export async function load() { return { meta: { + api, source, pageSource, }, diff --git a/packages/svelte-ux/src/routes/docs/components/Collapse/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Collapse/+page.svelte index 06d115779..0a05b8bc1 100644 --- a/packages/svelte-ux/src/routes/docs/components/Collapse/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Collapse/+page.svelte @@ -73,7 +73,7 @@ {#each Array(5) as _, i} <Collapse> <div slot="trigger" class="flex-1 px-3 py-3">Item {i + 1}</div> - <div class="px-3 pb-3 bg-gray-100 border-t"> + <div class="px-3 pb-3 border-t"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Reiciendis quod culpa et, dolores omnis, ipsum in perspiciatis porro ut nihil molestiae molestias tenetur delectus velit! Inventore laborum rerum at id? @@ -91,10 +91,10 @@ {#each Array(5) as _, i} <Collapse popout - class="bg-white elevation-1 border-t first:border-t-0 first:rounded-t last:rounded-b" + class="bg-surface-100 elevation-1 border-t first:border-t-0 first:rounded-t last:rounded-b" > <div slot="trigger" class="flex-1 px-3 py-3">Item {i + 1}</div> - <div class="px-3 pb-3 bg-gray-100 border-t"> + <div class="px-3 pb-3 bg-surface-200 border-t"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Reiciendis quod culpa et, dolores omnis, ipsum in perspiciatis porro ut nihil molestiae molestias tenetur delectus velit! Inventore laborum rerum at id? diff --git a/packages/svelte-ux/src/routes/docs/components/CopyButton/+page.svelte b/packages/svelte-ux/src/routes/docs/components/CopyButton/+page.svelte index 9973541a2..83df28e10 100644 --- a/packages/svelte-ux/src/routes/docs/components/CopyButton/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/CopyButton/+page.svelte @@ -13,19 +13,19 @@ <CopyButton value="Stop copying me!" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" /> + <CopyButton value="Stop copying me!" color="primary" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="outline" /> + <CopyButton value="Stop copying me!" color="primary" variant="outline" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="fill" /> + <CopyButton value="Stop copying me!" color="primary" variant="fill" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="fill-light" /> + <CopyButton value="Stop copying me!" color="primary" variant="fill-light" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="fill-outline" /> + <CopyButton value="Stop copying me!" color="primary" variant="fill-outline" /> </div> </div> </Preview> @@ -38,19 +38,19 @@ <CopyButton value="Stop copying me!" size="sm" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" size="sm" /> + <CopyButton value="Stop copying me!" color="primary" size="sm" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="outline" size="sm" /> + <CopyButton value="Stop copying me!" color="primary" variant="outline" size="sm" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="fill" size="sm" /> + <CopyButton value="Stop copying me!" color="primary" variant="fill" size="sm" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="fill-light" size="sm" /> + <CopyButton value="Stop copying me!" color="primary" variant="fill-light" size="sm" /> </div> <div> - <CopyButton value="Stop copying me!" color="accent" variant="fill-outline" size="sm" /> + <CopyButton value="Stop copying me!" color="primary" variant="fill-outline" size="sm" /> </div> </div> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/DateField/+page.svelte b/packages/svelte-ux/src/routes/docs/components/DateField/+page.svelte index 0a48fdd37..840223c8a 100644 --- a/packages/svelte-ux/src/routes/docs/components/DateField/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/DateField/+page.svelte @@ -7,7 +7,10 @@ import DateField from '$lib/components/DateField.svelte'; import Preview from '$lib/components/Preview.svelte'; - let value; + import { getSettings } from '$lib/components/settings'; + const { localeSettings } = getSettings(); + + let value: Date; </script> <h1>Examples</h1> @@ -29,8 +32,10 @@ <Preview> <DateField {value} /> - <Button on:click={() => (value = new Date())}>Today</Button> - <Button on:click={() => (value = addDays(new Date(), -1))}>Yesterday</Button> + <Button on:click={() => (value = new Date())}>{$localeSettings.dictionary.Date.Today}</Button> + <Button on:click={() => (value = addDays(new Date(), -1))} + >{$localeSettings.dictionary.Date.Yesterday}</Button + > <Button on:click={() => (value = addDays(new Date(), -7))}>Last Week</Button> <Button on:click={() => (value = addDays(new Date(), 7))}>Next Week</Button> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/DateRange/+page.svelte b/packages/svelte-ux/src/routes/docs/components/DateRange/+page.svelte index 8e6e6701d..6c0ee686c 100644 --- a/packages/svelte-ux/src/routes/docs/components/DateRange/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/DateRange/+page.svelte @@ -4,6 +4,9 @@ import Preview from '$lib/components/Preview.svelte'; import DateRange from '$lib/components/DateRange.svelte'; import { PeriodType, getDateFuncsByPeriodType } from '$lib/utils/date'; + import { getSettings } from '$lib/components/settings'; + + const { localeSettings } = getSettings(); let selected = { from: new Date('1982-03-01T00:00:00'), @@ -57,10 +60,10 @@ <Preview> <DateRange periodTypes={[PeriodType.Day, PeriodType.Month]} - getPeriodTypePresets={(periodType) => { - const { start, end, add } = getDateFuncsByPeriodType(periodType); + getPeriodTypePresets={(fnSettings, fnPeriodType) => { + const { start, end, add } = getDateFuncsByPeriodType($localeSettings, fnPeriodType); - if (periodType === PeriodType.Day) { + if (fnPeriodType === PeriodType.Day) { const today = startOfDay(new Date()); const yesterday = start(add(today, -1)); return [ @@ -69,7 +72,7 @@ value: { from: startOfMonth(today), to: end(today), - periodType, + periodType: fnPeriodType, }, }, { @@ -77,7 +80,7 @@ value: { from: startOfYear(today), to: end(today), - periodType, + periodType: fnPeriodType, }, }, { @@ -85,7 +88,7 @@ value: { from: add(yesterday, -29), to: end(yesterday), - periodType, + periodType: fnPeriodType, }, }, { @@ -93,7 +96,7 @@ value: { from: add(yesterday, -59), to: end(yesterday), - periodType, + periodType: fnPeriodType, }, }, { @@ -101,7 +104,7 @@ value: { from: add(yesterday, -89), to: end(yesterday), - periodType, + periodType: fnPeriodType, }, }, { @@ -109,7 +112,7 @@ value: { from: add(yesterday, -179), to: end(yesterday), - periodType, + periodType: fnPeriodType, }, }, { @@ -117,11 +120,11 @@ value: { from: add(yesterday, -364), to: end(yesterday), - periodType, + periodType: fnPeriodType, }, }, ]; - } else if (periodType === PeriodType.Month) { + } else if (fnPeriodType === PeriodType.Month) { const today = endOfMonth(new Date()); const lastMonth = start(add(today, -1)); @@ -131,7 +134,7 @@ value: { from: start(today), to: end(today), - periodType, + periodType: fnPeriodType, }, }, { @@ -139,7 +142,7 @@ value: { from: lastMonth, to: end(lastMonth), - periodType, + periodType: fnPeriodType, }, }, { @@ -147,7 +150,7 @@ value: { from: start(add(lastMonth, -2)), to: end(lastMonth), - periodType, + periodType: fnPeriodType, }, }, { @@ -155,7 +158,7 @@ value: { from: start(add(lastMonth, -5)), to: end(lastMonth), - periodType, + periodType: fnPeriodType, }, }, { @@ -163,7 +166,7 @@ value: { from: start(add(lastMonth, -11)), to: end(lastMonth), - periodType, + periodType: fnPeriodType, }, }, ]; diff --git a/packages/svelte-ux/src/routes/docs/components/Dialog/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Dialog/+page.svelte index d5d35fc68..aa1c6d68b 100644 --- a/packages/svelte-ux/src/routes/docs/components/Dialog/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Dialog/+page.svelte @@ -21,7 +21,7 @@ <Dialog bind:open> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Preview> @@ -34,7 +34,7 @@ <Dialog {open} on:close={toggle}> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> @@ -58,7 +58,7 @@ }, 1000); }} variant="fill" - color="accent" + color="primary" > Save </Button> @@ -86,7 +86,7 @@ }, 1000); }} variant="fill" - color="accent" + color="primary" > Save </Button> @@ -100,7 +100,7 @@ <Preview> <Toggle let:on={open} let:toggle> - <Button icon={mdiTrashCan} on:click={toggle} color="red">Delete</Button> + <Button icon={mdiTrashCan} on:click={toggle} color="danger">Delete</Button> <Dialog {open} on:close={toggle}> <div slot="title">Are you sure?</div> <div class="px-6 py-3">This will permanently delete the item and can not be undone.</div> @@ -110,7 +110,7 @@ console.log('Deleting item...'); }} variant="fill" - color="red" + color="danger" > Yes, delete item </Button> @@ -124,7 +124,7 @@ <Preview> <Toggle let:on={open} let:toggle={toggleDelete}> - <Button icon={mdiTrashCan} on:click={toggleDelete} color="red">Delete</Button> + <Button icon={mdiTrashCan} on:click={toggleDelete} color="danger">Delete</Button> <Dialog {open}> <div slot="title">Delete this item ?</div> <div class="px-6 py-3">This will permanently delete the item</div> @@ -136,7 +136,7 @@ e.stopPropagation(); toggleConfirm(); }} - color="red" + color="danger" variant="fill" > Yes @@ -154,7 +154,7 @@ toggleDelete(); }} variant="fill" - color="red" + color="danger" > Yes, delete item </Button> @@ -177,7 +177,7 @@ <Dialog {open} on:close={toggle} loading> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> @@ -191,7 +191,7 @@ <Dialog {open} on:close={toggle} persistent> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Yes</Button> + <Button variant="fill" color="primary">Yes</Button> <Button>No</Button> </div> </Dialog> @@ -209,7 +209,7 @@ <TextField label="Age" autofocus /> </div> <div slot="actions"> - <Button variant="fill" color="accent">OK</Button> + <Button variant="fill" color="primary">OK</Button> <Button>Cancel</Button> </div> </Dialog> @@ -224,7 +224,7 @@ <Dialog {open} on:close={toggle}> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent" disabled>Don't touch</Button> + <Button variant="fill" color="primary" disabled>Don't touch</Button> <Button>Close</Button> </div> </Dialog> diff --git a/packages/svelte-ux/src/routes/docs/components/Drawer/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Drawer/+page.svelte index 752320dc9..80af768fa 100644 --- a/packages/svelte-ux/src/routes/docs/components/Drawer/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Drawer/+page.svelte @@ -23,10 +23,7 @@ <Preview> <Drawer bind:open={topOpen} placement="top" class="h-64"> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={() => (topOpen = false)}>Close</Button> </div> </Drawer> @@ -34,10 +31,7 @@ <Drawer bind:open={bottomOpen} placement="bottom" class="h-64"> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={() => (bottomOpen = false)}>Close</Button> </div> </Drawer> @@ -45,10 +39,7 @@ <Drawer bind:open={leftOpen} placement="left" class="w-[400px]"> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={() => (leftOpen = false)}>Close</Button> </div> </Drawer> @@ -56,10 +47,7 @@ <Drawer bind:open={rightOpen} placement="right" class="w-[400px]"> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={() => (rightOpen = false)}>Close</Button> </div> </Drawer> @@ -72,10 +60,7 @@ <Toggle let:on={open} let:toggle let:toggleOff> <Drawer {open} on:close={toggleOff} persistent class="w-[400px]"> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -89,10 +74,7 @@ <Toggle let:on={open} let:toggle let:toggleOff> <Drawer {open} on:close={toggleOff} class="w-[400px]" loading> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -108,10 +90,7 @@ <div class="p-2"> <TextField autofocus /> </div> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -130,15 +109,12 @@ <Dialog {open} on:close={toggle}> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> </div> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -160,10 +136,7 @@ ]} /> </div> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -192,10 +165,7 @@ <Switch bind:checked={isChanged} /> </div> </div> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={isChanged ? openConfirmation : closeDrawer}>Close</Button> </div> </Drawer> @@ -212,7 +182,7 @@ isChanged = false; }} variant="fill" - color="red" + color="danger" > Yes, lose changes </Button> @@ -237,10 +207,7 @@ portal={{ target: '#portal' }} > <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> diff --git a/packages/svelte-ux/src/routes/docs/components/ExpansionPanel/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ExpansionPanel/+page.svelte index 2b9e063ee..477e3630e 100644 --- a/packages/svelte-ux/src/routes/docs/components/ExpansionPanel/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ExpansionPanel/+page.svelte @@ -28,7 +28,7 @@ <Preview> {#each Array(5) as _, i} - <ExpansionPanel classes={{ toggle: 'bg-gray-100 border-t border-gray-300' }}> + <ExpansionPanel classes={{ toggle: 'bg-surface-200 border-t' }}> <div slot="trigger" class="flex-1 p-3">Item {i + 1}</div> <div slot="actions" class="p-2"> <Button>Action 1</Button> @@ -68,7 +68,7 @@ title="Item {i + 1}" subheading="List Item" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} class="flex-1" noShadow /> @@ -92,7 +92,7 @@ title="Item 1" subheading="Expansion Panel" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} class="flex-1" noShadow /> @@ -106,7 +106,7 @@ title="Item 2" subheading="List Item" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} /> <ExpansionPanel> <ListItem @@ -114,7 +114,7 @@ title="Item 3" subheading="Expansion Panel" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} class="flex-1" noShadow /> @@ -135,7 +135,7 @@ title="Item 1" subheading="List Item" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} /> <ExpansionPanel> <ListItem @@ -143,7 +143,7 @@ title="Item 2" subheading="Expansion Panel" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} class="flex-1" noShadow /> @@ -157,6 +157,6 @@ title="Item 3" subheading="List Item" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} /> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Field/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Field/+page.svelte index edf463135..0be42d3da 100644 --- a/packages/svelte-ux/src/routes/docs/components/Field/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Field/+page.svelte @@ -67,7 +67,7 @@ <div class="grid grid-cols-2 gap-2"> <div> <div class="text-lg font-semibold mt-8 ml-2">ToggleGroup</div> - <div class="text-xs font-semibold text-black/50 mb-1 ml-2">default width</div> + <div class="text-xs font-semibold text-surface-content/50 mb-1 ml-2">default width</div> <Preview> <Field label="Is Active"> <ToggleGroup variant="outline" inset> @@ -81,7 +81,7 @@ <div> <div class="text-lg font-semibold mt-8 ml-2">ToggleGroup</div> - <div class="text-xs font-semibold text-black/50 mb-1 ml-2">full width</div> + <div class="text-xs font-semibold text-surface-content/50 mb-1 ml-2">full width</div> <Preview> <Field label="Is Active"> <ToggleGroup variant="outline" inset class="w-full"> @@ -95,7 +95,9 @@ <div> <div class="text-lg font-semibold mt-8 ml-2">ToggleGroup</div> - <div class="text-xs font-semibold text-black/50 mb-1 ml-2">full rounded and small</div> + <div class="text-xs font-semibold text-surface-content/50 mb-1 ml-2"> + full rounded and small + </div> <Preview> <Field label="Is Active"> <ToggleGroup variant="outline" inset rounded="full" size="sm" class="w-full"> @@ -109,7 +111,7 @@ <div> <div class="text-lg font-semibold mt-8 ml-2">ToggleGroup</div> - <div class="text-xs font-semibold text-black/50 mb-1 ml-2">with icons</div> + <div class="text-xs font-semibold text-surface-content/50 mb-1 ml-2">with icons</div> <Preview> <Field label="Is Active"> <ToggleGroup variant="outline" inset rounded="full"> @@ -140,7 +142,7 @@ <Preview> <Field label="Date of Birth" let:id> - <input {id} type="date" class="text-sm w-full outline-none" /> + <input {id} type="date" class="text-sm w-full outline-none bg-surface-100" /> </Field> </Preview> @@ -148,7 +150,14 @@ <Preview> <Field label="Number" let:id> - <input {id} type="number" min={0} max={10} step={1} class="w-full outline-none" /> + <input + {id} + type="number" + min={0} + max={10} + step={1} + class="w-full outline-none bg-surface-100" + /> </Field> </Preview> @@ -164,7 +173,7 @@ <Preview> <Field label="Position" let:id> - <select {id} class="text-sm w-full outline-none appearance-none cursor-pointer"> + <select {id} class="text-sm w-full outline-none appearance-none cursor-pointer bg-surface-100"> <option value={1}>First</option> <option value={2}>Second</option> <option value={3}>Third</option> diff --git a/packages/svelte-ux/src/routes/docs/components/Gooey/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Gooey/+page.svelte index fe23bd367..6709d5da0 100644 --- a/packages/svelte-ux/src/routes/docs/components/Gooey/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Gooey/+page.svelte @@ -43,15 +43,9 @@ </Preview> <Blockquote> - Inspiration: <a - href="https://codepen.io/Valgo/pen/PowZaNY" - target="_blank" - class="text-accent-500" - > - Text Morph - </a> + Inspiration: <a href="https://codepen.io/Valgo/pen/PowZaNY" target="_blank"> Text Morph </a> by - <a href="https://codepen.io/Valgo" target="_blank" class="text-accent-500">Valgo</a> + <a href="https://codepen.io/Valgo" target="_blank">Valgo</a> </Blockquote> <h2>Morphing emoji</h2> @@ -79,11 +73,11 @@ <RangeField label="blur: " labelPlacement="left" bind:value={gooeyBlur} max={13} class="mb-1" /> </div> -<Preview class="bg-indigo-900"> +<Preview class="bg-primary"> <Gooey blur={gooeyBlur} alphaPixel={19} alphaShift={-9} composite="atop"> <div contenteditable="true" - class="inline bg-white box-decoration-clone text-xl leading-7 px-2 py-1 outline-none" + class="inline bg-surface-100 box-decoration-clone text-xl leading-7 px-2 py-1 outline-none" > This is an example of a simple headline<br />or text with rounded corners<br />using a gooey SVG filter.<br />You can edit me! @@ -92,11 +86,11 @@ </Preview> <Blockquote> - Inspiration: <a href="https://codepen.io/ines/pen/NXbmRO" target="_blank" class="text-accent-500"> + Inspiration: <a href="https://codepen.io/ines/pen/NXbmRO" target="_blank"> Gooey text background with SVG filters </a> by - <a href="https://codepen.io/ines" target="_blank" class="text-accent-500">Ines Montani</a> + <a href="https://codepen.io/ines" target="_blank">Ines Montani</a> </Blockquote> <div class="grid grid-cols-[1fr,auto] gap-2 items-end"> @@ -126,15 +120,11 @@ </Preview> <Blockquote> - Inspiration: <a - href="https://codepen.io/hostsamurai/pen/bodZvR" - target="_blank" - class="text-accent-500" - > + Inspiration: <a href="https://codepen.io/hostsamurai/pen/bodZvR" target="_blank"> Spinner with Glowing, Gooey Effect </a> by - <a href="https://codepen.io/hostsamurai" target="_blank" class="text-accent-500">Lou</a> + <a href="https://codepen.io/hostsamurai" target="_blank">Lou</a> </Blockquote> <div class="grid grid-cols-[1fr,auto] gap-2 items-end"> @@ -165,15 +155,11 @@ </Preview> <Blockquote> - Inspiration: <a - href="https://codepen.io/hostsamurai/pen/qPENyb" - target="_blank" - class="text-accent-500" - > + Inspiration: <a href="https://codepen.io/hostsamurai/pen/qPENyb" target="_blank"> Loader/Scanner with Gooey Effect </a> by - <a href="https://codepen.io/hostsamurai" target="_blank" class="text-accent-500">Lou</a> + <a href="https://codepen.io/hostsamurai" target="_blank">Lou</a> </Blockquote> <div class="grid grid-cols-[1fr,auto] gap-2 items-end"> diff --git a/packages/svelte-ux/src/routes/docs/components/GridTailwind/+page.svelte b/packages/svelte-ux/src/routes/docs/components/GridTailwind/+page.svelte index 076732a0a..24dd678d9 100644 --- a/packages/svelte-ux/src/routes/docs/components/GridTailwind/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/GridTailwind/+page.svelte @@ -1,5 +1,5 @@ <script lang="ts"> - import Preview from '$lib/components/Preview.svelte'; + import Preview from '$lib/components/Preview.svelte'; </script> <h1>Examples</h1> @@ -66,7 +66,7 @@ <div class="border">item</div> <div class="border">item</div> <div class="border">item</div> - </div> + </div> </Preview> <h2>Template</h2> diff --git a/packages/svelte-ux/src/routes/docs/components/Icon/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Icon/+page.svelte index 120059917..521de9f95 100644 --- a/packages/svelte-ux/src/routes/docs/components/Icon/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Icon/+page.svelte @@ -61,7 +61,7 @@ <Icon path={mdiAccount} class="text-red-500" /> <Icon path={mdiAccount} class="text-blue-500" /> <Icon path={mdiAccount} class="text-green-500" /> - <Icon path={mdiAccount} class="text-black/50" /> + <Icon path={mdiAccount} class="text-surface-content/50" /> <Icon svgUrl="https://api.iconify.design/mdi:account.svg" class="text-red-500" /> <Icon svg={'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>'} diff --git a/packages/svelte-ux/src/routes/docs/components/ListItem/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ListItem/+page.svelte index fa57dbfa7..56c9c4951 100644 --- a/packages/svelte-ux/src/routes/docs/components/ListItem/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ListItem/+page.svelte @@ -67,7 +67,7 @@ title="Title" subheading="Subheading" icon={mdiAccount} - avatar={{ class: 'bg-gray-400 text-white/90' }} + avatar={{ class: 'bg-surface-content/50 text-surface-100/90' }} /> </Preview> @@ -76,7 +76,7 @@ <Preview> <ListItem title="Title"> <div slot="actions"> - <Button icon={mdiChevronRight} class="p-2 text-black/50" /> + <Button icon={mdiChevronRight} class="p-2 text-surface-content/50" /> </div> </ListItem> </Preview> @@ -112,8 +112,8 @@ on:click={() => (selectedId = choice.id)} class={cls( 'cursor-pointer', - 'hover:bg-accent-50', - selectedId == choice.id ? 'bg-accent-50' : '' + 'hover:bg-primary/5', + selectedId == choice.id ? 'bg-primary/5' : '' )} > <div slot="avatar" class="contents"> @@ -138,9 +138,9 @@ on:click={() => (selectedId = choice.id)} class={cls( 'px-8 py-4', - 'cursor-pointer ring ring-inset ring-accent-500 transition-shadow duration-100', - 'hover:bg-accent-50', - selectedId == choice.id ? 'ring-1 bg-accent-50' : 'ring-0' + 'cursor-pointer ring ring-inset ring-primary transition-shadow duration-100', + 'hover:bg-primary/5', + selectedId == choice.id ? 'ring-1 bg-primary/5' : 'ring-0' )} noShadow /> @@ -152,7 +152,7 @@ <h3>example 3</h3> <Preview> - <div class="grid gap-4 bg-gray-100 p-4"> + <div class="grid gap-4 bg-surface-200 p-4"> {#each choices as choice} <div> <ListItem @@ -161,9 +161,9 @@ on:click={() => (selectedId = choice.id)} class={cls( 'px-8 py-4', - 'cursor-pointer transition-shadow duration-100 border', - 'hover:bg-white', - selectedId == choice.id ? 'bg-white shadow-md' : '' + 'cursor-pointer transition-shadow duration-100', + 'hover:bg-surface-100 hover:outline', + selectedId == choice.id ? 'bg-surface-100 shadow-md' : '' )} noBackground noShadow diff --git a/packages/svelte-ux/src/routes/docs/components/Menu/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Menu/+page.svelte index 8ab50a839..fd734220c 100644 --- a/packages/svelte-ux/src/routes/docs/components/Menu/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Menu/+page.svelte @@ -67,7 +67,7 @@ <Dialog {open} on:close={toggleDialog}> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> @@ -77,7 +77,7 @@ <Dialog {open} on:close={toggleDialog} persistent> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> @@ -85,9 +85,7 @@ <Toggle let:on={open} let:toggle={toggleDrawer} let:toggleOff on:toggleOff={closeMenu}> <MenuItem on:click={toggleDrawer}>Open Drawer...</MenuItem> <Drawer {open} on:close={toggleOff} class="w-[400px]"> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -96,9 +94,7 @@ <Toggle let:on={open} let:toggle={toggleDrawer} let:toggleOff on:toggleOff={closeMenu}> <MenuItem on:click={toggleDrawer}>Open Persistent Drawer...</MenuItem> <Drawer {open} on:close={toggleOff} class="w-[400px]" persistent> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -118,9 +114,7 @@ </Menu> </span> </Toggle> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> diff --git a/packages/svelte-ux/src/routes/docs/components/MenuButton/+page.svelte b/packages/svelte-ux/src/routes/docs/components/MenuButton/+page.svelte index 92bc9f9f0..9a0f736c0 100644 --- a/packages/svelte-ux/src/routes/docs/components/MenuButton/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/MenuButton/+page.svelte @@ -48,7 +48,7 @@ <h2>Variant</h2> <Preview> - <MenuButton {options} variant="fill" color="accent" /> + <MenuButton {options} variant="fill" color="primary" /> </Preview> <h2>Size</h2> diff --git a/packages/svelte-ux/src/routes/docs/components/MenuField/+page.svelte b/packages/svelte-ux/src/routes/docs/components/MenuField/+page.svelte index 711b47cc0..3ace992b0 100644 --- a/packages/svelte-ux/src/routes/docs/components/MenuField/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/MenuField/+page.svelte @@ -121,7 +121,7 @@ <Preview> <MenuField {options}> <div slot="append"> - <Button icon={mdiRefresh} class="p-2 text-black/50" /> + <Button icon={mdiRefresh} class="p-2 text-surface-content/50" /> </div> </MenuField> </Preview> @@ -137,6 +137,6 @@ <Preview> <MenuField {options} - classes={{ container: 'bg-accent-50 rounded-full border-0 text-accent-500' }} + classes={{ container: 'bg-primary/10 rounded-full border-0 text-primary' }} /> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/MultiSelect/+page.svelte b/packages/svelte-ux/src/routes/docs/components/MultiSelect/+page.svelte index 78864a399..09d648125 100644 --- a/packages/svelte-ux/src/routes/docs/components/MultiSelect/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/MultiSelect/+page.svelte @@ -83,7 +83,7 @@ <div class="flex flex-col max-h-[360px] overflow-auto"> <MultiSelect {options} {value} on:change={(e) => (value = e.detail.value)} inlineSearch> <div slot="actions"> - <Button color="accent" icon={mdiPlus}>Add item</Button> + <Button color="primary" icon={mdiPlus}>Add item</Button> </div> </MultiSelect> </div> diff --git a/packages/svelte-ux/src/routes/docs/components/MultiSelectField/+page.svelte b/packages/svelte-ux/src/routes/docs/components/MultiSelectField/+page.svelte index 706806385..e3e4d5c12 100644 --- a/packages/svelte-ux/src/routes/docs/components/MultiSelectField/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/MultiSelectField/+page.svelte @@ -71,7 +71,7 @@ <Preview> <MultiSelectField {options} {value} on:change={(e) => (value = e.detail.value)}> <div slot="actions"> - <Button color="accent" icon={mdiPlus}>Add item</Button> + <Button color="primary" icon={mdiPlus}>Add item</Button> </div> </MultiSelectField> </Preview> @@ -79,16 +79,13 @@ <h2>within Drawer</h2> <Preview> - <ToggleButton let:on={open} let:toggle let:toggleOff> + <ToggleButton let:on={open}> Open Drawer - <Drawer slot="toggle" {open} on:close={toggleOff} class="w-[400px]"> + <Drawer slot="toggle" let:toggleOff {open} on:close={toggleOff} class="w-[400px]"> <div class="p-4"> <MultiSelectField {options} {value} on:change={(e) => (value = e.detail.value)} /> </div> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> diff --git a/packages/svelte-ux/src/routes/docs/components/MultiSelectMenu/+page.svelte b/packages/svelte-ux/src/routes/docs/components/MultiSelectMenu/+page.svelte index 7fb41c36e..e1d664cf4 100644 --- a/packages/svelte-ux/src/routes/docs/components/MultiSelectMenu/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/MultiSelectMenu/+page.svelte @@ -133,7 +133,7 @@ inlineSearch > <div slot="actions"> - <Button color="accent" icon={mdiPlus}>Add item</Button> + <Button color="primary" icon={mdiPlus}>Add item</Button> </div> </MultiSelectMenu> </ToggleButton> diff --git a/packages/svelte-ux/src/routes/docs/components/NavItem/+page.svelte b/packages/svelte-ux/src/routes/docs/components/NavItem/+page.svelte index bd26d0857..f898bfcc8 100644 --- a/packages/svelte-ux/src/routes/docs/components/NavItem/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/NavItem/+page.svelte @@ -20,6 +20,6 @@ text="NavItem" currentUrl={$page.url} path="/docs/components/NavItem" - classes={{ root: 'pl-3', active: 'bg-accent-50 text-accent-500' }} + classes={{ root: 'pl-3', active: 'bg-primary/10 text-primary' }} /> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Notification/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Notification/+page.svelte index f55e727c8..04cc2aa54 100644 --- a/packages/svelte-ux/src/routes/docs/components/Notification/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Notification/+page.svelte @@ -30,7 +30,7 @@ <Notification open actions="right" closeIcon> <div slot="title">Discussion archived</div> <div slot="actions"> - <Button color="accent">Undo</Button> + <Button color="primary">Undo</Button> </div> </Notification> </div> @@ -49,7 +49,7 @@ Lorem ipsum dolor sit amet consectetur adipisicing elit oluptatum tenetur. </div> <div slot="actions"> - <Button color="accent">Undo</Button> + <Button color="primary">Undo</Button> <Button>Dismiss</Button> </div> </Notification> @@ -65,7 +65,7 @@ <div slot="description">Notifications may include alerts, sounds, and badges</div> <div slot="actions" class="h-full"> <div class="grid border-l divide-y h-full"> - <Button color="accent">Reply</Button> + <Button color="primary">Reply</Button> <Button>Don't Allow</Button> </div> </div> diff --git a/packages/svelte-ux/src/routes/docs/components/Overflow/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Overflow/+page.svelte index c102abc87..f6188b03e 100644 --- a/packages/svelte-ux/src/routes/docs/components/Overflow/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Overflow/+page.svelte @@ -20,7 +20,7 @@ <Overflow class="w-1/2 h-[200px] overflow-hidden" let:overflowX let:overflowY> <div>overflowX: {overflowX}</div> <div>overflowY: {overflowY}</div> - <div class="whitespace-nowrap border border-black/20 rounded-lg bg-white"> + <div class="whitespace-nowrap border rounded-lg bg-surface-100"> {#each { length: overflowItems } as _} <div>Resize the window to see text truncate and watch values</div> {/each} @@ -44,7 +44,7 @@ <Button icon={mdiChevronLeft} class="absolute top-1/2 left-0 -translate-y-1/2" size="sm" /> <div class="flex gap-3 overflow-auto scrollbar-none"> {#each { length: 20 } as _} - <div class="border rounded-lg px-4 bg-white">Item</div> + <div class="border rounded-lg px-4 bg-surface-100">Item</div> {/each} </div> <Button icon={mdiChevronRight} class="absolute top-1/2 right-0 -translate-y-1/2" size="sm" /> diff --git a/packages/svelte-ux/src/routes/docs/components/Overlay/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Overlay/+page.svelte index 9f40231b1..f91f15e30 100644 --- a/packages/svelte-ux/src/routes/docs/components/Overlay/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Overlay/+page.svelte @@ -27,7 +27,7 @@ <Preview> <div class="relative"> - <Overlay center class="bg-black/10"> + <Overlay center class="bg-surface-content/10"> <ProgressCircle /> </Overlay> <div>Some content</div> diff --git a/packages/svelte-ux/src/routes/docs/components/Pagination/+page.md b/packages/svelte-ux/src/routes/docs/components/Pagination/+page.md index 9f8ea099a..ef729b6e5 100644 --- a/packages/svelte-ux/src/routes/docs/components/Pagination/+page.md +++ b/packages/svelte-ux/src/routes/docs/components/Pagination/+page.md @@ -71,7 +71,7 @@ <Preview> <Pagination {pagination} show={['actions', 'perPage', 'pagination', 'prevPage', 'nextPage']} classes={{ perPage: 'flex-1 text-right', pagination: 'px-8' }}> <div slot="actions"> - <Button variant="fill" color="accent">Click me</Button> + <Button variant="fill" color="primary">Click me</Button> </div> </Pagination> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Popover/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Popover/+page.svelte index 43fd7c363..6e78179c0 100644 --- a/packages/svelte-ux/src/routes/docs/components/Popover/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Popover/+page.svelte @@ -16,7 +16,7 @@ <Preview> <div class="inline-block"> <Popover bind:open> - <div class="p-2 bg-white border shadow">Example contents</div> + <div class="p-2 bg-surface-100 border shadow">Example contents</div> </Popover> <Button on:click={() => (open = !open)}>Click me</Button> </div> @@ -31,7 +31,7 @@ <div class="col-start-2 text-right"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="top-start"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Top Start</Button> </div> @@ -41,7 +41,7 @@ <div class="col-start-3 text-center"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="top"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Top</Button> </div> @@ -51,7 +51,7 @@ <div class="col-start-4 text-left"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="top-end"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Top End</Button> </div> @@ -61,7 +61,7 @@ <div class="col-start-1 text-right"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="left-start"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Left Start</Button> </div> @@ -71,7 +71,7 @@ <div class="col-start-5 text-left"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="right-start"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Right Start</Button> </div> @@ -81,7 +81,7 @@ <div class="col-start-1 text-right"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="left"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Left</Button> </div> @@ -91,7 +91,7 @@ <div class="col-start-5 text-left"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="right"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Right</Button> </div> @@ -101,7 +101,7 @@ <div class="col-start-1 text-right"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="left-end"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Left End</Button> </div> @@ -111,7 +111,7 @@ <div class="col-start-5 text-left"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="right-end"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Right End</Button> </div> @@ -121,7 +121,7 @@ <div class="col-start-2 text-right"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="bottom-start"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Bottom Start</Button> </div> @@ -131,7 +131,7 @@ <div class="col-start-3 text-center"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="bottom"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Bottom</Button> </div> @@ -141,7 +141,7 @@ <div class="col-start-4 text-left"> <div class="inline-block"> <Popover {open} on:close={toggleOff} placement="bottom-start"> - <div class="px-4 py-8 bg-white border shadow">Contents</div> + <div class="px-4 py-8 bg-surface-100 border shadow">Contents</div> </Popover> <Button on:click={toggle}>Bottom End</Button> </div> diff --git a/packages/svelte-ux/src/routes/docs/components/Progress/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Progress/+page.svelte index d494e32b2..093c4c115 100644 --- a/packages/svelte-ux/src/routes/docs/components/Progress/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Progress/+page.svelte @@ -29,26 +29,26 @@ <h2>Color</h2> <Preview> - <Progress value={0.5} class="[--color:theme(colors.green.500)]" /> - <Progress value={0.7} class="[--color:theme(colors.yellow.500)]" /> - <Progress value={0.9} class="[--color:theme(colors.red.500)]" /> + <Progress value={0.5} class="[--color:theme(colors.success)]" /> + <Progress value={0.7} class="[--color:theme(colors.warning)]" /> + <Progress value={0.9} class="[--color:theme(colors.danger)]" /> </Preview> <h2>Track color</h2> <Preview> - <Progress value={0.5} class="[--track-color:theme(colors.accent.50)]" /> + <Progress value={0.5} class="[--track-color:theme(colors.primary/5%)]" /> <Progress value={0.5} - class="[--color:theme(colors.green.500)] [--track-color:theme(colors.green.50)]" + class="[--color:theme(colors.success)] [--track-color:theme(colors.success/5%)]" /> <Progress value={0.7} - class="[--color:theme(colors.yellow.500)] [--track-color:theme(colors.yellow.50)]" + class="[--color:theme(colors.warning)] [--track-color:theme(colors.warning/5%)]" /> <Progress value={0.9} - class="[--color:theme(colors.red.500)] [--track-color:theme(colors.red.50)]" + class="[--color:theme(colors.danger)] [--track-color:theme(colors.danger/5%)]" /> </Preview> @@ -59,10 +59,10 @@ bind:value class={cls( value > 90 - ? '[--color:theme(colors.red.500)]' - : value > 70 - ? '[--color:theme(colors.yellow.500)]' - : '[--color:theme(colors.green.500)]' + ? '[--color:theme(colors.danger)]' + : value > 50 + ? '[--color:theme(colors.warning)]' + : '[--color:theme(colors.success)]' )} max={100} /> diff --git a/packages/svelte-ux/src/routes/docs/components/ProgressCircle/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ProgressCircle/+page.svelte index b0c4c77e8..a8b3d679e 100644 --- a/packages/svelte-ux/src/routes/docs/components/ProgressCircle/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ProgressCircle/+page.svelte @@ -15,16 +15,16 @@ <h2>Demo</h2> -<div class="border border-black/20 rounded bg-white"> +<div class="border rounded bg-surface-100"> <div class="grid grid-cols-[1fr,auto] items-center justify-items-center gap-4"> <ProgressCircle value={indeterminate ? null : value} {size} {width} {rotate} {track}> {#if label} - <span class="text-black/50 text-xs"> + <span class="text-surface-content/50 text-xs"> {#if indeterminate}Loading...{:else}{value}%{/if} </span> {/if} </ProgressCircle> - <div class="bg-black/5 border-l border-black/20 p-4"> + <div class="bg-surface-content/5 border-l p-4"> <label class="block"> size: <input type="range" min={0} max={120} bind:value={size} /> @@ -94,22 +94,22 @@ <Preview> <div class="flex gap-4"> <ProgressCircle value={0}> - <span class="text-black/50 text-xs">0%</span> + <span class="text-surface-content/50 text-xs">0%</span> </ProgressCircle> <ProgressCircle value={20}> - <span class="text-black/50 text-xs">20%</span> + <span class="text-surface-content/50 text-xs">20%</span> </ProgressCircle> <ProgressCircle value={40}> - <span class="text-black/50 text-xs">40%</span> + <span class="text-surface-content/50 text-xs">40%</span> </ProgressCircle> <ProgressCircle value={60}> - <span class="text-black/50 text-xs">60%</span> + <span class="text-surface-content/50 text-xs">60%</span> </ProgressCircle> <ProgressCircle value={80}> - <span class="text-black/50 text-xs">80%</span> + <span class="text-surface-content/50 text-xs">80%</span> </ProgressCircle> <ProgressCircle value={100}> - <span class="text-black/50 text-xs">100%</span> + <span class="text-surface-content/50 text-xs">100%</span> </ProgressCircle> </div> </Preview> @@ -119,22 +119,22 @@ <Preview> <div class="flex gap-4"> <ProgressCircle value={0} track> - <span class="text-black/50 text-xs">0%</span> + <span class="text-surface-content/50 text-xs">0%</span> </ProgressCircle> <ProgressCircle value={20} track> - <span class="text-black/50 text-xs">20%</span> + <span class="text-surface-content/50 text-xs">20%</span> </ProgressCircle> <ProgressCircle value={40} track> - <span class="text-black/50 text-xs">40%</span> + <span class="text-surface-content/50 text-xs">40%</span> </ProgressCircle> <ProgressCircle value={60} track> - <span class="text-black/50 text-xs">60%</span> + <span class="text-surface-content/50 text-xs">60%</span> </ProgressCircle> <ProgressCircle value={80} track> - <span class="text-black/50 text-xs">80%</span> + <span class="text-surface-content/50 text-xs">80%</span> </ProgressCircle> <ProgressCircle value={100} track> - <span class="text-black/50 text-xs">100%</span> + <span class="text-surface-content/50 text-xs">100%</span> </ProgressCircle> </div> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/ResponsiveMenu/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ResponsiveMenu/+page.svelte index fed21c5e5..ea4c3f563 100644 --- a/packages/svelte-ux/src/routes/docs/components/ResponsiveMenu/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ResponsiveMenu/+page.svelte @@ -69,7 +69,7 @@ <Dialog {open} on:close={toggleDialog}> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> @@ -79,7 +79,7 @@ <Dialog {open} on:close={toggleDialog} persistent> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </Toggle> @@ -87,9 +87,7 @@ <Toggle let:on={open} let:toggle={toggleDrawer} let:toggleOff on:toggleOff={closeMenu}> <MenuItem on:click={toggleDrawer}>Open Drawer...</MenuItem> <Drawer {open} on:close={toggleOff} class="w-[400px]"> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -98,9 +96,7 @@ <Toggle let:on={open} let:toggle={toggleDrawer} let:toggleOff on:toggleOff={closeMenu}> <MenuItem on:click={toggleDrawer}>Open Persistent Drawer...</MenuItem> <Drawer {open} on:close={toggleOff} class="w-[400px]" persistent> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -120,9 +116,7 @@ </ResponsiveMenu> </span> </Toggle> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -174,19 +168,16 @@ <Blockquote> `env()` - <a - href="https://developer.mozilla.org/en-US/docs/Web/CSS/env#usage" - target="_blank" - class="font-semibold text-accent-500">requires</a - > + <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/env#usage" target="_blank">requires</a> setting `viewport-fit=cover` within `viewport` meta tag </Blockquote> See also -<a +<Button + variant="text" + color="primary" href="https://github.com/mvllow/tailwindcss-safe-area" - target="_blank" - class="font-semibold text-accent-500">tailwind-css-safe-area</a + target="_blank">tailwind-css-safe-area</Button > to add `pb-safe` util class @@ -194,11 +185,9 @@ to add `pb-safe` util class <Preview> <Settings - settings={{ - theme: { - Drawer: - '[&.ResponsiveMenu]:rounded-t-xl [&.ResponsiveMenu]:py-2 [&.ResponsiveMenu]:pb-[env(safe-area-inset-bottom)]', - }, + classes={{ + Drawer: + '[&.ResponsiveMenu]:rounded-t-xl [&.ResponsiveMenu]:py-2 [&.ResponsiveMenu]:pb-[env(safe-area-inset-bottom)]', }} > <Toggle let:on={open} let:toggle let:toggleOff> diff --git a/packages/svelte-ux/src/routes/docs/components/ScrollContainer/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ScrollContainer/+page.svelte index aec40d134..4d1f98236 100644 --- a/packages/svelte-ux/src/routes/docs/components/ScrollContainer/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ScrollContainer/+page.svelte @@ -10,12 +10,12 @@ <Preview> <ScrollContainer class="scroll-mt-6 scroll-mb-6" let:scrollIntoView> - <Button variant="fill" color="accent" on:click={() => scrollIntoView({ block: 'end' })} + <Button variant="fill" color="primary" on:click={() => scrollIntoView({ block: 'end' })} >Scroll to bottom</Button > {#each { length: 100 } as _, i} <div>Item: {i + 1}</div> {/each} - <Button variant="fill" color="accent" on:click={() => scrollIntoView()}>Scroll to top</Button> + <Button variant="fill" color="primary" on:click={() => scrollIntoView()}>Scroll to top</Button> </ScrollContainer> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/ScrollingValue/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ScrollingValue/+page.svelte index 6b959f014..5f520ba72 100644 --- a/packages/svelte-ux/src/routes/docs/components/ScrollingValue/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ScrollingValue/+page.svelte @@ -11,7 +11,7 @@ import ToggleGroup from '$lib/components/ToggleGroup.svelte'; import ToggleOption from '$lib/components/ToggleOption.svelte'; - import { PeriodType, format, romanize, timerStore } from '$lib'; + import { PeriodType, getSettings, romanize, timerStore } from '$lib'; let value = 0; let axis: 'x' | 'y' = 'x'; @@ -46,6 +46,7 @@ } } + const { format } = getSettings(); const indexTimer = timerStore({ initial: 0, delay: 2000, @@ -60,7 +61,7 @@ <h1>Examples</h1> <div class="grid grid-cols-[1fr,140px] items-center gap-6"> - <ButtonGroup variant="fill" class="grid grid-flow-col ml-2"> + <ButtonGroup variant="fill-light" class="grid grid-flow-col ml-2"> <Button on:click={() => (value -= 100)}>-100</Button> <Button on:click={() => (value -= 10)}>-10</Button> <Button on:click={() => (value -= 1)}>-1</Button> @@ -71,13 +72,13 @@ </ButtonGroup> <Field label="axis" labelPlacement="left"> - <ToggleGroup bind:value={axis} variant="fill-white" inset> + <ToggleGroup bind:value={axis} variant="fill-surface" inset> <ToggleOption value="x">x</ToggleOption> <ToggleOption value="y">y</ToggleOption> </ToggleGroup> </Field> </div> -<div class="text-xs ml-2 text-black/50"> +<div class="text-xs ml-2 text-surface-content/50"> also keyboard up/down with shift: +/- 10 option: +/- 100 </div> @@ -170,7 +171,7 @@ <Button icon={mdiPlus} on:click={() => (value += 1)} size="sm" iconOnly={false} /> </ButtonGroup> - <ButtonGroup variant="fill"> + <ButtonGroup variant="fill-light"> <Button icon={mdiMinus} on:click={() => (value -= 1)} size="sm" iconOnly={false} /> <Button class="w-20 pointer-events-none"> <ScrollingValue @@ -182,7 +183,7 @@ <Button icon={mdiPlus} on:click={() => (value += 1)} size="sm" iconOnly={false} /> </ButtonGroup> - <ButtonGroup color="accent" variant="fill-light"> + <ButtonGroup color="primary" variant="fill-light"> <Button icon={mdiMinus} on:click={() => (value -= 1)} size="sm" iconOnly={false} /> <Button class="w-20 pointer-events-none"> <ScrollingValue @@ -194,7 +195,7 @@ <Button icon={mdiPlus} on:click={() => (value += 1)} size="sm" iconOnly={false} /> </ButtonGroup> - <ButtonGroup color="accent" variant="fill-outline"> + <ButtonGroup color="primary" variant="fill-outline"> <Button icon={mdiMinus} on:click={() => (value -= 1)} size="sm" iconOnly={false} /> <Button class="w-20 pointer-events-none"> <ScrollingValue @@ -215,7 +216,7 @@ <div class="grid w-96"> <div class="grid grid-cols-[auto,1fr,auto] items-center justify-items-center"> <Button icon={mdiChevronLeft} class="p-2" on:click={() => (value -= 1)} /> - <div>{format(startOfMonth, PeriodType.Month)}</div> + <div>{$format(startOfMonth, PeriodType.Month)}</div> <Button icon={mdiChevronRight} class="p-2" on:click={() => (value += 1)} /> </div> <ScrollingValue {value} {axis} let:value> @@ -229,7 +230,7 @@ <Preview> <ScrollingValue value={$timer ?? 0} {axis} class="text-6xl tabular-nums" /> - <ButtonGroup variant="fill" class="ml-3"> + <ButtonGroup variant="fill-light" class="ml-3"> <Button on:click={timer.start} disabled={$isRunning}>Start</Button> <Button on:click={timer.stop} disabled={!$isRunning}>Stop</Button> </ButtonGroup> diff --git a/packages/svelte-ux/src/routes/docs/components/SelectField/+page.svelte b/packages/svelte-ux/src/routes/docs/components/SelectField/+page.svelte index 21fc6a4ab..8caf51059 100644 --- a/packages/svelte-ux/src/routes/docs/components/SelectField/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/SelectField/+page.svelte @@ -45,7 +45,9 @@ { label: 'Baz', value: 3 }, ]; - const newOption: () => MenuOption = () => { return { label: "", value: null }} + const newOption: () => MenuOption = () => { + return { label: '', value: null }; + }; let optionsAsync: MenuOption[] = []; let loading = false; @@ -150,11 +152,11 @@ <h2>option slot</h2> <Preview> - <SelectField {options} on:change={(e) => console.log('on:change', e.detail)}> + <SelectField {options}> <div slot="option" let:option let:index let:selected let:highlightIndex> <MenuItem class={cls( - index === highlightIndex && 'bg-black/5', + index === highlightIndex && 'bg-surface-content/5', option === selected && 'font-semibold', option.group ? 'px-4' : 'px-2' )} @@ -162,7 +164,7 @@ > <div> <div>{option.label}</div> - <div class="text-sm text-black/50">{option.value}</div> + <div class="text-sm text-text-surface-content/50">{option.value}</div> </div> </MenuItem> </div> @@ -172,16 +174,11 @@ <h2>option slot with icon (field icon updates based on selected option)</h2> <Preview> - <SelectField - {options} - bind:value - activeOptionIcon={true} - on:change={(e) => console.log('on:change', e.detail)} - > + <SelectField {options} bind:value activeOptionIcon={true}> <div slot="option" let:option let:index let:selected let:highlightIndex> <MenuItem class={cls( - index === highlightIndex && 'bg-black/5', + index === highlightIndex && 'bg-surface-content/5', option === selected && 'font-semibold', option.group ? 'px-4' : 'px-2' )} @@ -197,11 +194,11 @@ <h2>option with action</h2> <Preview> - <SelectField {options} on:change={(e) => console.log('on:change', e.detail)}> + <SelectField {options}> <div slot="option" let:option let:index let:selected let:highlightIndex> <MenuItem class={cls( - index === highlightIndex && 'bg-black/5', + index === highlightIndex && 'bg-surface-content/5', option === selected && 'font-semibold', option.group ? 'px-4' : 'px-2' )} @@ -210,22 +207,20 @@ <div class="grid grid-cols-[1fr,auto] items-center w-full"> <div> <div>{option.label}</div> - <div class="text-sm text-black/50">{option.value}</div> + <div class="text-sm text-surface-content/50">{option.value}</div> </div> <div on:click|stopPropagation> <Toggle let:on={open} let:toggle let:toggleOff> <Button icon={mdiPencil} - class="p-1 text-xs text-gray-400 z-[9999]" + class="p-1 text-xs text-surface-content/50 z-[9999]" on:click={toggle} /> <Drawer {open} on:close={toggleOff} class="w-[400px]"> <div class="p-4"> Editing option: {option.label} </div> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 p-1 border-t border-gray-400" - > + <div slot="actions"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -244,7 +239,7 @@ <SelectField {options}> <div slot="prepend" on:click|stopPropagation class="flex items-center"> <select - class="appearance-none bg-black/5 border rounded-full mr-2 px-4" + class="appearance-none bg-surface-content/5 border rounded-full mr-2 px-4" style="text-align-last: center;" > <!-- <option /> --> @@ -266,7 +261,7 @@ <Toggle let:on={open} let:toggle> <SelectField {options}> <span slot="append" on:click|stopPropagation> - <Button icon={mdiPlus} class="text-black/50 p-2" on:click={toggle} /> + <Button icon={mdiPlus} class="text-surface-content/50 p-2" on:click={toggle} /> </span> </SelectField> <Form @@ -298,7 +293,7 @@ /> </div> <div slot="actions"> - <Button on:click={() => commit()} color="accent">Add option</Button> + <Button on:click={() => commit()} color="primary">Add option</Button> <Button on:click={() => revert()}>Cancel</Button> </div> </Dialog> @@ -312,7 +307,7 @@ <SelectField {options} bind:value> <div slot="actions" class="p-2 border-t" on:click|stopPropagation let:hide> <Toggle let:on={open} let:toggle> - <Button icon={mdiPlus} color="blue" on:click={toggle}>New item</Button> + <Button icon={mdiPlus} color="primary" on:click={toggle}>New item</Button> <Form initial={newOption()} on:change={(e) => { @@ -349,7 +344,7 @@ /> </div> <div slot="actions"> - <Button on:click={() => commit()} color="accent">Add option</Button> + <Button on:click={() => commit()} color="primary">Add option</Button> <Button on:click={() => revert()}>Cancel</Button> </div> </Dialog> @@ -383,7 +378,7 @@ <SelectField {options} icon={mdiMagnify} rounded> <span slot="prepend" on:click|stopPropagation> <select - class="appearance-none bg-black/5 border rounded-full mr-2 px-4" + class="appearance-none bg-surface-content/5 border rounded-full mr-2 px-4" style="text-align-last: center;" > <!-- <option /> --> @@ -403,7 +398,6 @@ <Preview> <SelectField {options} - on:change={(e) => console.log('on:change', e.detail)} search={async () => { console.log('search override...'); await delay(1000); @@ -415,11 +409,13 @@ <h2>Placement</h2> <Preview> - <SelectField - {options} - on:change={(e) => console.log('on:change', e.detail)} - placement="top-start" - /> + <SelectField {options} autoPlacement={false} placement="top-start" /> +</Preview> + +<h2>Stepper</h2> + +<Preview> + <SelectField {options} toggleIcon={null} stepper /> </Preview> <h2>Custom selected class</h2> @@ -429,17 +425,12 @@ {options} bind:value clearSearchOnOpen - classes={{ selected: 'bg-accent-500 text-white' }} + classes={{ selected: 'bg-primary text-primary-content' }} /> </Preview> <h2>Inline options with icon (used by search bar dialog in top-right)</h2> <Preview> - <SelectField - {options} - icon={mdiMagnify} - bind:value - inlineOptions={true} - /> + <SelectField {options} icon={mdiMagnify} bind:value inlineOptions={true} /> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Settings/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Settings/+page.svelte index 4d17ebb1b..6bb3e2f41 100644 --- a/packages/svelte-ux/src/routes/docs/components/Settings/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Settings/+page.svelte @@ -13,16 +13,14 @@ <Preview> <Settings - settings={{ - theme: { - Button: 'border-2 font-bold', - Menu: 'shadow-xl border-gray-500', - MenuItem: 'font-bold', - }, + classes={{ + Button: 'border-2 font-bold', + Menu: 'shadow-xl border-gray-500', + MenuItem: 'font-bold', }} > <Toggle let:on={open} let:toggle> - <Button on:click={toggle} variant="outline" color="accent"> + <Button on:click={toggle} variant="outline" color="primary"> Click me <Menu {open} on:close={toggle}> <MenuItem>Refresh</MenuItem> diff --git a/packages/svelte-ux/src/routes/docs/components/Shine/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Shine/+page.svelte index 85cacee15..fa794067a 100644 --- a/packages/svelte-ux/src/routes/docs/components/Shine/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Shine/+page.svelte @@ -20,10 +20,10 @@ <h2>Basic</h2> <Preview> - <div class="inline-block bg-accent-100 rounded-lg"> + <div class="inline-block bg-primary/10 rounded-lg"> <Shine> <div - class="text-8xl text-accent-500 border-[12px] border-accent-500 py-2 font-semibold rounded-lg text-center w-[500px]" + class="text-8xl text-primary border-[12px] border-primary py-2 font-semibold rounded-lg text-center w-[500px]" > Shine </div> @@ -52,12 +52,13 @@ <Preview> <Shine> <div class="flex items-center gap-2"> - <Button variant="fill" color="blue">Button</Button> - <Button icon={mdiTrashCan} variant="fill" color="red">Delete</Button> - <Button icon={mdiMagnify} variant="fill" color="green" class="flex-row-reverse">Search</Button + <Button variant="fill" color="primary">Button</Button> + <Button icon={mdiTrashCan} variant="fill" color="danger">Delete</Button> + <Button icon={mdiMagnify} variant="fill" color="success" class="flex-row-reverse" + >Search</Button > - <Button icon={mdiHome} variant="fill" color="blue" class="flex-col">Home</Button> - <Button icon={mdiHome} variant="fill" color="blue" class="flex-col-reverse">Home</Button> + <Button icon={mdiHome} variant="fill" color="primary" class="flex-col">Home</Button> + <Button icon={mdiHome} variant="fill" color="primary" class="flex-col-reverse">Home</Button> </div> </Shine> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/SpringValue/+page.svelte b/packages/svelte-ux/src/routes/docs/components/SpringValue/+page.svelte index 1cf0b78d1..84bf6fcee 100644 --- a/packages/svelte-ux/src/routes/docs/components/SpringValue/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/SpringValue/+page.svelte @@ -1,11 +1,13 @@ <script lang="ts"> + import { getSettings } from '$lib/components/settings'; import Button from '$lib/components/Button.svelte'; import ButtonGroup from '$lib/components/ButtonGroup.svelte'; import Preview from '$lib/components/Preview.svelte'; import SpringValue from '$lib/components/SpringValue.svelte'; - import { format } from '$lib/utils/format'; import { cls } from '$lib/utils/styles'; + const { format } = getSettings(); + let value: number | null = 0; function onKeyDown(e: KeyboardEvent) { @@ -28,7 +30,7 @@ <h1>Examples</h1> <div class="grid grid-cols-[1fr,auto,auto] gap-2"> - <ButtonGroup variant="fill" class="grid grid-flow-col ml-2"> + <ButtonGroup variant="fill-light" class="grid grid-flow-col ml-2"> <Button on:click={() => (value -= 100)}>-100</Button> <Button on:click={() => (value -= 10)}>-10</Button> <Button on:click={() => (value -= 1)}>-1</Button> @@ -37,10 +39,10 @@ <Button on:click={() => (value += 10)}>+10</Button> <Button on:click={() => (value += 100)}>+100</Button> </ButtonGroup> - <Button variant="fill" on:click={() => (value = Math.random() * 10)}>Random</Button> - <Button variant="fill" on:click={() => (value = null)}>Null</Button> + <Button variant="fill-light" on:click={() => (value = Math.random() * 10)}>Random</Button> + <Button variant="fill-light" on:click={() => (value = null)}>Null</Button> </div> -<span class="text-xs ml-2 text-black/50"> +<span class="text-xs ml-2 text-surface-content/50"> also keyboard up/down with shift: +/- 10 option: +/- 100 </span> @@ -67,7 +69,7 @@ <Preview> <SpringValue {value} let:value> <span class={cls('tabular-nums', (value ?? 0) < 0 ? 'text-red-500' : 'text-green-500')}> - {format(value, 'decimal')} + {$format(value, 'decimal')} </span> </SpringValue> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Stack/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Stack/+page.svelte index b02016334..9fe8b1670 100644 --- a/packages/svelte-ux/src/routes/docs/components/Stack/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Stack/+page.svelte @@ -161,49 +161,49 @@ <Stack stack inline> <Button variant="outline">Example</Button> <div - class="bg-red-500 rounded-full h-4 w-4 text-xs text-white flex items-center justify-center" + class="bg-danger rounded-full h-4 w-4 text-xs text-danger-content flex items-center justify-center" > 3 </div> </Stack> </Preview> -<h2>Corner w/ Button</h2> +<h2>Corner with Button</h2> <Preview> <Stack stack inline> <Button variant="outline">Example</Button> <div - class="bg-red-500 rounded-full h-4 w-4 -mr-1 -mt-1 text-xs text-white flex items-center justify-center self-start justify-self-end" + class="bg-danger rounded-full h-4 w-4 -mr-1 -mt-1 text-xs text-danger-content flex items-center justify-center self-start justify-self-end" > 3 </div> </Stack> </Preview> -<h2>Corner /w Icon Button</h2> +<h2>Corner with Icon Button</h2> <Preview> <Stack stack inline> <Button variant="outline" icon={mdiFilterVariant} class="p-3" /> <div - class="bg-red-500 rounded-full h-4 w-4 text-xs text-white flex items-center justify-center self-start justify-self-end" + class="bg-danger rounded-full h-4 w-4 text-xs text-danger-content flex items-center justify-center self-start justify-self-end" > 3 </div> </Stack> </Preview> -<h2>Corner (multi) /w Icon Button</h2> +<h2>Corner (multi) with Icon Button</h2> <Preview> <Stack stack inline> <Button variant="outline" icon={mdiFilterVariant} class="p-3" /> <div - class="bg-red-500 rounded-full h-4 w-4 -mt-1 text-xs flex items-center justify-center self-start justify-self-end border border-white" + class="bg-danger rounded-full h-4 w-4 -mt-1 text-xs flex items-center justify-center self-start justify-self-end border border-surface-100" /> <div - class="bg-green-500 rounded-full h-4 w-4 text-xs flex items-center justify-center self-end justify-self-end border border-white" + class="bg-success rounded-full h-4 w-4 text-xs flex items-center justify-center self-end justify-self-end border border-surface-100" /> </Stack> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/StackTailwind/+page.svelte b/packages/svelte-ux/src/routes/docs/components/StackTailwind/+page.svelte index b770913db..ca906210f 100644 --- a/packages/svelte-ux/src/routes/docs/components/StackTailwind/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/StackTailwind/+page.svelte @@ -160,49 +160,49 @@ <div class="inline-grid place-items-center"> <Button class="col-span-full row-span-full border">Example</Button> <div - class="col-span-full row-span-full bg-red-500 rounded-full h-4 w-4 text-xs text-white flex items-center justify-center" + class="col-span-full row-span-full bg-danger rounded-full h-4 w-4 text-xs text-danger-content flex items-center justify-center" > 3 </div> </div> </Preview> -<h2>Corner w/ Button</h2> +<h2>Corner with Button</h2> <Preview> <div class="inline-grid"> <Button class="col-span-full row-span-full border">Example</Button> <div - class="col-span-full row-span-full bg-red-500 rounded-full h-4 w-4 -mr-1 -mt-1 text-xs text-white flex items-center justify-center self-start justify-self-end" + class="col-span-full row-span-full bg-danger rounded-full h-4 w-4 -mr-1 -mt-1 text-xs text-danger-content flex items-center justify-center self-start justify-self-end" > 3 </div> </div> </Preview> -<h2>Corner /w Icon Button</h2> +<h2>Corner with Icon Button</h2> <Preview> <div class="inline-grid"> <Button icon={mdiFilterVariant} class="col-span-full row-span-full border p-3" /> <div - class="col-span-full row-span-full bg-red-500 rounded-full h-4 w-4 text-xs text-white flex items-center justify-center self-start justify-self-end" + class="col-span-full row-span-full bg-danger rounded-full h-4 w-4 text-xs text-danger-content flex items-center justify-center self-start justify-self-end" > 3 </div> </div> </Preview> -<h2>Corner (multi) /w Icon Button</h2> +<h2>Corner (multi) with Icon Button</h2> <Preview> <div class="inline-grid"> <Button icon={mdiFilterVariant} class="col-span-full row-span-full border p-3" /> <div - class="col-span-full row-span-full self-start justify-self-end bg-red-500 rounded-full h-4 w-4 -mt-1 text-xs flex items-center justify-center border border-white" + class="col-span-full row-span-full self-start justify-self-end bg-danger rounded-full h-4 w-4 -mt-1 text-xs flex items-center justify-center border border-surface-100" /> <div - class="col-span-full row-span-full self-end justify-self-end bg-green-500 rounded-full h-4 w-4 text-xs flex items-center justify-center border border-white" + class="col-span-full row-span-full self-end justify-self-end bg-success rounded-full h-4 w-4 text-xs flex items-center justify-center border border-surface-100" /> </div> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Steps/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Steps/+page.svelte index 251494b28..6cc2fcb1e 100644 --- a/packages/svelte-ux/src/routes/docs/components/Steps/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Steps/+page.svelte @@ -1,6 +1,6 @@ <script lang="ts"> import { format } from 'date-fns'; - import { mdiCheck, mdiCircle, mdiClockOutline, mdiClose, mdiMapMarker } from '@mdi/js'; + import { mdiCheck, mdiClockOutline, mdiClose, mdiMapMarker, mdiTruck } from '@mdi/js'; import Icon from '$lib/components/Icon.svelte'; import Preview from '$lib/components/Preview.svelte'; @@ -56,11 +56,11 @@ <Steps {items}> <div slot="item" let:item> <div class="text-lg font-bold">{item.title}</div> - <div class="text-sm text-black/50"> + <div class="text-sm text-surface-content/50"> <Icon path={mdiMapMarker} size="1rem" /> {item.location} </div> - <div class="text-sm text-black/50"> + <div class="text-sm text-surface-content/50"> <Icon path={mdiClockOutline} size=".9rem" /> {format(item.date, 'M/d/yyyy @ h:mm aa')} </div> @@ -68,17 +68,17 @@ <div slot="marker" let:item> <div class={cls('w-4 h-4 flex-shrink-0 rounded-full flex items-center', { - 'bg-green-500': item.status === 'completed', - 'border-2 border-accent-500 bg-accent-100': item.status === 'in-progress', - 'bg-red-500': item.status === 'failed', + 'bg-success': item.status === 'completed', + 'bg-info': item.status === 'in-progress', + 'bg-danger': item.status === 'failed', })} > {#if item.status === 'completed'} - <Icon path={mdiCheck} size="1rem" class="text-white" /> + <Icon path={mdiCheck} size="1rem" class="text-success-content" /> {:else if item.status === 'in-progress'} - <Icon path={mdiCircle} size="1rem" class="text-accent-500" /> + <Icon path={mdiTruck} size="1rem" class="text-info-content p-[2px]" /> {:else if item.status === 'failed'} - <Icon path={mdiClose} size="1rem" class="text-white" /> + <Icon path={mdiClose} size="1rem" class="text-danger-content" /> {/if} </div> </div> diff --git a/packages/svelte-ux/src/routes/docs/components/Switch/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Switch/+page.svelte index fbebc2a0f..6af54d065 100644 --- a/packages/svelte-ux/src/routes/docs/components/Switch/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Switch/+page.svelte @@ -41,14 +41,14 @@ <div class="grid gap-2"> <Switch let:checked> {#if checked} - <Icon path={mdiCheck} class="text-accent-500" size=".8em" /> + <Icon path={mdiCheck} class="text-primary" size=".8em" /> {/if} </Switch> <Switch let:checked> {#if checked} - <Icon path={mdiCheck} class="text-accent-500" size=".8em" /> + <Icon path={mdiCheck} class="text-primary" size=".8em" /> {:else} - <Icon path={mdiClose} class="text-gray-400" size=".8em" /> + <Icon path={mdiClose} class="text-surface-content" size=".8em" /> {/if} </Switch> </div> @@ -61,7 +61,7 @@ <Switch disabled /> <Switch disabled checked /> <Switch disabled> - <Icon path={mdiCheck} class="text-black/50" size=".8em" /> + <Icon path={mdiCheck} class="text-surface-content/50" size=".8em" /> </Switch> </div> </Preview> @@ -87,12 +87,18 @@ <Preview> <div class="inline-grid grid-cols-[auto,auto] gap-2"> - <Switch color="red" /> - <Switch checked color="red" /> - <Switch color="green" /> - <Switch checked color="green" /> - <Switch color="purple" /> - <Switch checked color="purple" /> + <Switch color="primary" /> + <Switch checked color="primary" /> + <Switch color="secondary" /> + <Switch checked color="secondary" /> + <Switch color="accent" /> + <Switch checked color="accent" /> + <Switch color="neutral" /> + <Switch checked color="neutral" /> + <Switch color="success" /> + <Switch checked color="success" /> + <Switch color="danger" /> + <Switch checked color="danger" /> </div> </Preview> @@ -101,13 +107,13 @@ <Preview> <div class="grid gap-2"> <Switch - color="green" - classes={{ switch: 'data-[checked=false]:bg-red-500 data-[checked=false]:border-red-500' }} + color="success" + classes={{ switch: 'data-[checked=false]:bg-danger data-[checked=false]:border-danger' }} /> <Switch classes={{ - switch: 'bg-white border-gray-400', - toggle: 'data-[checked=false]:bg-red-500 data-[checked=true]:bg-green-500', + switch: 'bg-surface-100 border-surface-content/50', + toggle: 'data-[checked=false]:bg-danger data-[checked=true]:bg-success', }} /> </div> diff --git a/packages/svelte-ux/src/routes/docs/components/Table/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Table/+page.svelte index 6db2716b8..6eb313766 100644 --- a/packages/svelte-ux/src/routes/docs/components/Table/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Table/+page.svelte @@ -211,8 +211,12 @@ <Preview> <Button on:click={() => (randomData = randomDataGen())} - class="text-accent-500 border border-accent-500 bg-white mb-1">Randomize</Button + variant="outline" + color="primary" + class="mb-1" > + Randomize + </Button> <Table data={randomData} columns={[ @@ -225,40 +229,48 @@ align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-blue-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-primary/5 to-primary/10', + }, }, { name: 'fat', align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-purple-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-secondary/5 to-secondary/10', + }, }, { name: 'carbs', align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-orange-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-success/5 to-success/10', + }, }, { name: 'protein', align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-red-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-danger/5 to-danger/10', + }, }, ]} /> @@ -269,8 +281,12 @@ <Preview> <Button on:click={() => (randomData = randomDataGen())} - class="text-accent-500 border border-accent-500 bg-white mb-1">Randomize</Button + variant="outline" + color="primary" + class="mb-1" > + Randomize + </Button> <Table data={randomData} columns={[ @@ -283,40 +299,48 @@ align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-blue-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-primary/5 to-primary/10', + }, }, { name: 'fat', align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-purple-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-secondary/5 to-secondary/10', + }, }, { name: 'carbs', align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-orange-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-success/5 to-success/10', + }, }, { name: 'protein', align: 'right', format: 'integer', dataBackground: { - color: 'var(--color-red-100)', inset: [1, 2], tweened: { duration: 300 }, }, + classes: { + td: 'from-danger/5 to-danger/10', + }, }, ]} > diff --git a/packages/svelte-ux/src/routes/docs/components/TableOfContents/+page.svelte b/packages/svelte-ux/src/routes/docs/components/TableOfContents/+page.svelte index 446180cc4..81c5b6dd7 100644 --- a/packages/svelte-ux/src/routes/docs/components/TableOfContents/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/TableOfContents/+page.svelte @@ -13,15 +13,28 @@ Let's build some example TableOfContents for the following masterpiece: <h1>The Epic Novel</h1> <h2>Chapter 1</h2> <h3>New Beginnings</h3> - Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas eu ornare purus. Praesent auctor tellus leo, ac ornare nisi egestas eu. Nam tincidunt finibus pretium. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Praesent dolor urna, congue at convallis vel, accumsan ut ante. + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas eu ornare purus. Praesent auctor + tellus leo, ac ornare nisi egestas eu. Nam tincidunt finibus pretium. Pellentesque habitant morbi + tristique senectus et netus et malesuada fames ac turpis egestas. Praesent dolor urna, congue at + convallis vel, accumsan ut ante. <h4>A Brief Interlude</h4> - Proin congue augue ex, eget laoreet nisi tempor ac. Sed a sapien convallis, mollis lectus quis, mollis lorem. + Proin congue augue ex, eget laoreet nisi tempor ac. Sed a sapien convallis, mollis lectus quis, mollis + lorem. <h3>The Journey</h3> - Donec nec rhoncus libero, ut euismod augue. Curabitur lacus dolor, pellentesque nec suscipit at, faucibus id odio. Sed ullamcorper quam nibh, eget hendrerit metus viverra vel. Etiam elementum gravida ipsum, eget vestibulum felis vulputate eget. Vivamus at volutpat sapien. Pellentesque lobortis aliquam mauris, ac volutpat magna convallis et. Praesent hendrerit finibus dui in ullamcorper. + Donec nec rhoncus libero, ut euismod augue. Curabitur lacus dolor, pellentesque nec suscipit at, + faucibus id odio. Sed ullamcorper quam nibh, eget hendrerit metus viverra vel. Etiam elementum gravida + ipsum, eget vestibulum felis vulputate eget. Vivamus at volutpat sapien. Pellentesque lobortis aliquam + mauris, ac volutpat magna convallis et. Praesent hendrerit finibus dui in ullamcorper. <h2>Chapter 2</h2> <h2>Chapter 3</h2> - Donec eget nulla non eros elementum rutrum eu sed nulla. Nam dignissim, neque in elementum vestibulum, nisl libero fringilla nunc, et pellentesque ex nibh porta sem. In sed vehicula justo. Etiam non sagittis tortor. Pellentesque ut sagittis enim. Nulla eget dictum erat. Mauris eu semper nisl, quis posuere arcu. Nunc ut purus quis felis lobortis vehicula. Aliquam varius luctus lectus, in egestas mauris sollicitudin eget. Etiam suscipit, nunc vitae blandit convallis, lorem est laoreet ante, sit amet gravida arcu ligula vitae ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas mattis ac turpis quis luctus. - </div> + Donec eget nulla non eros elementum rutrum eu sed nulla. Nam dignissim, neque in elementum vestibulum, + nisl libero fringilla nunc, et pellentesque ex nibh porta sem. In sed vehicula justo. Etiam non sagittis + tortor. Pellentesque ut sagittis enim. Nulla eget dictum erat. Mauris eu semper nisl, quis posuere + arcu. Nunc ut purus quis felis lobortis vehicula. Aliquam varius luctus lectus, in egestas mauris + sollicitudin eget. Etiam suscipit, nunc vitae blandit convallis, lorem est laoreet ante, sit amet + gravida arcu ligula vitae ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas + mattis ac turpis quis luctus. + </div> </Card> <h2>Basic</h2> @@ -33,5 +46,5 @@ Let's build some example TableOfContents for the following masterpiece: <h2>Limit Max Depth</h2> <Preview> - <TableOfContents element="#epic-novel" maxDepth="{2}" /> -</Preview> \ No newline at end of file + <TableOfContents element="#epic-novel" maxDepth={2} /> +</Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/Tabs/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Tabs/+page.svelte index 43e89b15d..4ee5c081d 100644 --- a/packages/svelte-ux/src/routes/docs/components/Tabs/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Tabs/+page.svelte @@ -134,7 +134,7 @@ <Icon data={mdiClose} - class="rounded-full p-0.5 hover:bg-black/5" + class="rounded-full p-0.5 hover:bg-surface-content/5" on:click={(e) => { e.stopPropagation(); options = options.filter((o) => o.value !== option.value); @@ -149,7 +149,7 @@ options = [...options, { label: 'New ' + newValue, value: newValue }]; }} > - <Icon data={mdiPlus} class="rounded-full p-0.5 hover:bg-black/5" /> + <Icon data={mdiPlus} class="rounded-full p-0.5 hover:bg-surface-content/5" /> </Tab> <svelte:fragment slot="content"> diff --git a/packages/svelte-ux/src/routes/docs/components/TextField/+page.svelte b/packages/svelte-ux/src/routes/docs/components/TextField/+page.svelte index c9aaec8d2..9c4c21ccc 100644 --- a/packages/svelte-ux/src/routes/docs/components/TextField/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/TextField/+page.svelte @@ -255,7 +255,7 @@ <Preview> <TextField label="User Search"> <div slot="prepend"> - <Icon path={mdiAccountSearch} class="text-black/50 mr-2" /> + <Icon path={mdiAccountSearch} class="text-surface-content/50 mr-2" /> </div> </TextField> </Preview> @@ -267,7 +267,7 @@ <TextField label="Start Date"> <div slot="prepend"> <select - class="appearance-none bg-black/5 border rounded-full mr-2 px-4" + class="appearance-none bg-surface-content/5 border rounded-full mr-2 px-4" style="text-align-last: center;" > <!-- <option /> --> @@ -289,7 +289,7 @@ <Preview> <TextField label="Name"> <span slot="append"> - <Button icon={mdiRefresh} class="text-black/50 p-2" /> + <Button icon={mdiRefresh} class="text-surface-content/50 p-2" /> </span> </TextField> </Preview> @@ -299,7 +299,7 @@ <Preview> <TextField label="Amount"> <div slot="prefix"> - <Icon path={mdiCurrencyUsd} size="1.1em" class="text-black/50 -mt-1" /> + <Icon path={mdiCurrencyUsd} size="1.1em" class="text-surface-content/50 -mt-1" /> </div> </TextField> </Preview> @@ -309,7 +309,7 @@ <div class="text-lg font-semibold mt-8 ml-2">Suffix</div> <Preview> <TextField label="Weight"> - <div slot="suffix" class="text-black/50">lbs</div> + <div slot="suffix" class="text-surface-content/50">lbs</div> </TextField> </Preview> </div> @@ -319,7 +319,7 @@ <Preview> <TextField label="Ratio" align="right"> <div slot="suffix"> - <Icon path={mdiPercent} size="1.1em" class="text-black/50 -mt-1 ml-1" /> + <Icon path={mdiPercent} size="1.1em" class="text-surface-content/50 -mt-1 ml-1" /> </div> </TextField> </Preview> @@ -349,7 +349,7 @@ <Preview> <TextField label="Search" clearable> <span slot="append"> - <Button icon={mdiArrowRight} class="text-black/50 p-2" /> + <Button icon={mdiArrowRight} class="text-surface-content/50 p-2" /> </span> </TextField> </Preview> @@ -371,15 +371,15 @@ <Preview> <TextField label="Transfer amount"> <div slot="prepend"> - <Icon path={mdiCreditCardOutline} class="text-black/50 mr-2" /> + <Icon path={mdiCreditCardOutline} class="text-surface-content/50 mr-2" /> </div> <div slot="append"> - <Button icon={mdiArrowRight} class="text-black/50 p-2" /> + <Button icon={mdiArrowRight} class="text-surface-content/50 p-2" /> </div> <div slot="prefix"> - <Icon path={mdiCurrencyUsd} size="1.1em" class="text-black/50 -mt-1" /> + <Icon path={mdiCurrencyUsd} size="1.1em" class="text-surface-content/50 -mt-1" /> </div> - <div slot="suffix" class="text-black/50">usd</div> + <div slot="suffix" class="text-surface-content/50">usd</div> </TextField> </Preview> @@ -388,12 +388,12 @@ <Preview> <TextField label="Date Range"> <div slot="prepend" class="flex items-center"> - <Button icon={mdiChevronLeft} class="text-black/50 p-2" /> - <Icon path={mdiCalendar} class="text-black/50 mr-2" /> + <Button icon={mdiChevronLeft} class="text-surface-content/50 p-2" /> + <Icon path={mdiCalendar} class="text-surface-content/50 mr-2" /> </div> <div slot="append" class="flex items-center"> - <Icon path={mdiRefresh} class="text-black/50 mr-2" /> - <Button icon={mdiChevronRight} class="text-black/50 p-2" /> + <Icon path={mdiRefresh} class="text-surface-content/50 mr-2" /> + <Button icon={mdiChevronRight} class="text-surface-content/50 p-2" /> </div> </TextField> </Preview> @@ -461,9 +461,9 @@ <Preview> <TextField icon={mdiInformationOutline}> - <div slot="prefix" class="text-black/50">http://</div> + <div slot="prefix" class="text-surface-content/50">http://</div> <div slot="append"> - <Button icon={mdiStarOutline} class="text-black/50 p-2" /> + <Button icon={mdiStarOutline} class="text-surface-content/50 p-2" /> </div> </TextField> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/ToggleButton/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ToggleButton/+page.svelte index eeb86026b..05b957f28 100644 --- a/packages/svelte-ux/src/routes/docs/components/ToggleButton/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ToggleButton/+page.svelte @@ -22,7 +22,7 @@ <Dialog slot="toggle" {open} on:close={toggle} let:toggle> <div slot="title">Are you sure you want to do that?</div> <div slot="actions"> - <Button variant="fill" color="accent">Close</Button> + <Button variant="fill" color="primary">Close</Button> </div> </Dialog> </ToggleButton> @@ -35,10 +35,7 @@ Open Drawer <Drawer slot="toggle" let:on={open} {open} on:close={toggleOff} class="w-[400px]" let:toggleOff> <h1>Contents</h1> - <div - class="fixed bottom-0 w-full flex justify-center bg-gray-500/25 - p-1 border-t border-gray-400" - > + <div class="fixed bottom-0 w-full flex justify-center bg-surface-content/5 border-t p-1"> <Button on:click={toggleOff}>Close</Button> </div> </Drawer> @@ -50,7 +47,7 @@ <Preview> <ToggleButton size="sm" transition={slide} let:on={showDetails}> {showDetails ? 'show less' : 'show more'}... - <div slot="toggle" class="mt-2 border-t border-gray-100"> + <div slot="toggle" class="mt-2 border-t"> {#each { length: 10 } as _, i} <div>{i}</div> {/each} @@ -63,7 +60,7 @@ <Preview> <ToggleButton size="sm" transition={slide} let:on={showDetails} buttonPlacement="after"> {showDetails ? 'show less' : 'show more'}... - <div slot="toggle" class="mt-2 border-b border-gray-100"> + <div slot="toggle" class="mt-2 border-b"> {#each { length: 10 } as _, i} <div>{i}</div> {/each} @@ -76,7 +73,7 @@ <Preview> <ToggleButton on size="sm" transition={slide} let:on={showDetails}> {showDetails ? 'show less' : 'show more'}... - <div slot="toggle" class="mt-2 border-t border-b border-gray-100"> + <div slot="toggle" class="mt-2 border-t border-b"> {#each { length: 10 } as _, i} <div>{i}</div> {/each} diff --git a/packages/svelte-ux/src/routes/docs/components/ToggleGroup/+page.svelte b/packages/svelte-ux/src/routes/docs/components/ToggleGroup/+page.svelte index 5d8d9e19b..b7d6fb426 100644 --- a/packages/svelte-ux/src/routes/docs/components/ToggleGroup/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/ToggleGroup/+page.svelte @@ -40,7 +40,7 @@ <ToggleOption value="calls">Calls</ToggleOption> <svelte:fragment slot="panes"> {#if showPanes} - <div class="mt-2 p-4 bg-black/5 rounded border"> + <div class="mt-2 p-4 bg-surface-content/5 rounded border"> <TogglePanel>All panel</TogglePanel> <TogglePanel>Missed panel</TogglePanel> <TogglePanel>Calls panel</TogglePanel> @@ -57,7 +57,7 @@ <Radio name="variant" value="outline" bind:group={variant}>outline</Radio> <Radio name="variant" value="fill" bind:group={variant}>fill</Radio> <Radio name="variant" value="fill-light" bind:group={variant}>fill-light</Radio> - <Radio name="variant" value="fill-white" bind:group={variant}>fill-white</Radio> + <Radio name="variant" value="fill-surface" bind:group={variant}>fill-surface</Radio> <Radio name="variant" value="underline" bind:group={variant}>underline</Radio> </Field> @@ -101,7 +101,7 @@ <h2>Variants</h2> -{#each ['default', 'outline', 'fill', 'fill-light', 'fill-white', 'underline'] as variant} +{#each ['default', 'outline', 'fill', 'fill-light', 'fill-surface', 'underline'] as variant} <h3>{variant}</h3> <Preview> <div class="inline-grid gap-2"> diff --git a/packages/svelte-ux/src/routes/docs/components/Tooltip/+page.svelte b/packages/svelte-ux/src/routes/docs/components/Tooltip/+page.svelte index 70d86af18..fb9a7d521 100644 --- a/packages/svelte-ux/src/routes/docs/components/Tooltip/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/Tooltip/+page.svelte @@ -30,14 +30,14 @@ <Tooltip> <div slot="title" - class="grid grid-cols-[auto,1fr] gap-x-4 gap-y-2 bg-gray-900/90 text-white px-4 py-2 text-xs rounded shadow" + class="grid grid-cols-[auto,1fr] gap-x-4 gap-y-2 bg-surface-content text-surface-100 px-4 py-2 text-xs rounded shadow" > - <div class="col-span-2 justify-self-center text-sm">Tue, March 30</div> - <div class="text-white/50 justify-self-end">Actual:</div> + <div class="col-span-2 justify-self-center text-sm font-semibold">Tue, March 30</div> + <div class="text-surface-100/50 justify-self-end">Actual:</div> <div class="justify-self-end">123.50</div> - <div class="text-white/50 justify-self-end">Target:</div> + <div class="text-surface-100/50 justify-self-end">Target:</div> <div class="justify-self-end">90.00</div> - <div class="text-white/50 justify-self-end">Variance:</div> + <div class="text-surface-100/50 justify-self-end">Variance:</div> <div class="justify-self-end">33.50</div> </div> <Button>Hover me</Button> diff --git a/packages/svelte-ux/src/routes/docs/components/TweenedValue/+page.svelte b/packages/svelte-ux/src/routes/docs/components/TweenedValue/+page.svelte index 3b6acd3cd..495bed60a 100644 --- a/packages/svelte-ux/src/routes/docs/components/TweenedValue/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/components/TweenedValue/+page.svelte @@ -5,11 +5,13 @@ import ButtonGroup from '$lib/components/ButtonGroup.svelte'; import Preview from '$lib/components/Preview.svelte'; import TweenedValue from '$lib/components/TweenedValue.svelte'; - import { format } from '$lib/utils/format'; + import { getSettings } from '$lib/components/settings'; import { cls } from '$lib/utils/styles'; let value: number | null = 0; + const { format } = getSettings(); + function onKeyDown(e: KeyboardEvent) { const step = e.shiftKey ? 10 : e.altKey ? 100 : 1; switch (e.code) { @@ -30,7 +32,7 @@ <h1>Examples</h1> <div class="grid grid-cols-[1fr,auto,auto] gap-2"> - <ButtonGroup variant="fill" class="grid grid-flow-col ml-2"> + <ButtonGroup variant="fill-light" class="grid grid-flow-col ml-2"> <Button on:click={() => (value -= 100)}>-100</Button> <Button on:click={() => (value -= 10)}>-10</Button> <Button on:click={() => (value -= 1)}>-1</Button> @@ -39,10 +41,10 @@ <Button on:click={() => (value += 10)}>+10</Button> <Button on:click={() => (value += 100)}>+100</Button> </ButtonGroup> - <Button variant="fill" on:click={() => (value = Math.random() * 10)}>Random</Button> - <Button variant="fill" on:click={() => (value = null)}>Null</Button> + <Button variant="fill-light" on:click={() => (value = Math.random() * 10)}>Random</Button> + <Button variant="fill-light" on:click={() => (value = null)}>Null</Button> </div> -<span class="text-xs ml-2 text-black/50"> +<span class="text-xs ml-2 text-surface-content/50"> also keyboard up/down with shift: +/- 10 option: +/- 100 </span> @@ -69,7 +71,7 @@ <Preview> <TweenedValue {value} let:value> <span class={cls('tabular-nums', (value ?? 0) < 0 ? 'text-red-500' : 'text-green-500')}> - {format(value, 'decimal')} + {$format(value, 'decimal')} </span> </TweenedValue> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/dateDisplay/+page.svelte b/packages/svelte-ux/src/routes/docs/components/dateDisplay/+page.svelte deleted file mode 100644 index f151cfe41..000000000 --- a/packages/svelte-ux/src/routes/docs/components/dateDisplay/+page.svelte +++ /dev/null @@ -1,139 +0,0 @@ -<script lang="ts"> - import Preview from '$lib/components/Preview.svelte'; - - import { dateDisplay } from '$lib/utils/dateDisplay'; - import { PeriodType } from '$lib/utils/date'; -</script> - -<h1>Examples</h1> - -<h2>No format</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'))} -</Preview> - -<h2>Custom format</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { format: 'EEE, MMMM do' })} -</Preview> - -<h2>PeriodType Day w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.Day, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.Day, - variant: 'short', - })} -</Preview> - -<h2>PeriodType WeekSun w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.WeekSun, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.WeekSun, - variant: 'short', - })} -</Preview> - -<h2>PeriodType BiWeek1Sun w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.BiWeek1Sun, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.BiWeek1Sun, - variant: 'short', - })} -</Preview> - -<h2>PeriodType Month w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.Month, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.Month, - variant: 'short', - })} -</Preview> - -<h2>PeriodType Quarter w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.Quarter, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.Quarter, - variant: 'short', - })} -</Preview> - -<h2>PeriodType CalendarYear w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.CalendarYear, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.CalendarYear, - variant: 'short', - })} -</Preview> - -<h2>PeriodType FiscalYearOctober w/ long (default)</h2> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.FiscalYearOctober, - })} -</Preview> - -<h3>short</h3> - -<Preview> - {dateDisplay(new Date('1982-03-30T00:00:00'), { - periodType: PeriodType.FiscalYearOctober, - variant: 'short', - })} -</Preview> diff --git a/packages/svelte-ux/src/routes/docs/components/dateDisplay/+page.ts b/packages/svelte-ux/src/routes/docs/components/dateDisplay/+page.ts deleted file mode 100644 index 6d4abe1dd..000000000 --- a/packages/svelte-ux/src/routes/docs/components/dateDisplay/+page.ts +++ /dev/null @@ -1,16 +0,0 @@ -import source from '$lib/utils/dateDisplay.ts?raw'; -import pageSource from './+page.svelte?raw'; - -export async function load() { - return { - meta: { - source, - pageSource, - features: [ - 'Pass `periodType` along with `variant` for quick formatting', - 'Pass `format` for <a href="https://date-fns.org/v2.30.0/docs/format" class="underline underline-offset-2 decoration-gray-400">greater control</a>', - 'By default, will be formatted using `date.toLocaleString()`', - ], - }, - }; -} diff --git a/packages/svelte-ux/src/routes/docs/stores/localStore/+page.md b/packages/svelte-ux/src/routes/docs/stores/localStore/+page.md index 97f67b189..8d966fa96 100644 --- a/packages/svelte-ux/src/routes/docs/stores/localStore/+page.md +++ b/packages/svelte-ux/src/routes/docs/stores/localStore/+page.md @@ -10,10 +10,10 @@ ```svelte <script> - import { localStore } from 'svelte-ux'; - import { addDays } from 'date-fns'; + import { localStore } from 'svelte-ux'; + import { addDays } from 'date-fns'; - const store = localStore('some-key', defaultValue, { expiry: addDays(new Date(), 1) }); + const store = localStore('some-key', defaultValue, { expiry: addDays(new Date(), 1) }); </script> ``` diff --git a/packages/svelte-ux/src/routes/docs/stores/matchMedia/+page.md b/packages/svelte-ux/src/routes/docs/stores/matchMedia/+page.md index a5642ab4c..9417eec77 100644 --- a/packages/svelte-ux/src/routes/docs/stores/matchMedia/+page.md +++ b/packages/svelte-ux/src/routes/docs/stores/matchMedia/+page.md @@ -64,71 +64,71 @@ <Preview> <div class="grid grid-cols-[auto,1fr] items-center gap-2"> {#if $smScreen} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $smScreen (640px) {#if $mdScreen} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $mdScreen (768px) {#if $lgScreen} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $lgScreen (1024px) {#if $xlScreen} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $xlScreen (1280px) {#if $xxlScreen} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $xxlScreen (1536px) {#if $screen} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $screen {#if $print} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $print {#if $darkColorScheme} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $darkColorScheme {#if $motionReduce} - <Icon path={mdiCheckCircle} size="1rem" class="text-emerald-500" /> + <Icon path={mdiCheckCircle} size="1rem" class="text-success" /> {:else} - <Icon path={mdiCloseCircle} size="1rem" class="text-red-500" /> + <Icon path={mdiCloseCircle} size="1rem" class="text-danger" /> {/if} $motionReduce </div> - <div class="ml-6 mt-3 text-black/50 text-xs"> + <div class="ml-6 mt-3 text-surface-content/50 text-xs"> current width: {innerWidth}px </div> </Preview> diff --git a/packages/svelte-ux/src/routes/docs/utils/format/+page.svelte b/packages/svelte-ux/src/routes/docs/utils/format/+page.svelte index e1839e59e..b428c2f65 100644 --- a/packages/svelte-ux/src/routes/docs/utils/format/+page.svelte +++ b/packages/svelte-ux/src/routes/docs/utils/format/+page.svelte @@ -1,30 +1,41 @@ <script lang="ts"> import Preview from '$lib/components/Preview.svelte'; - import { format } from '$lib/utils/format'; - import { PeriodType } from '$lib/utils/date'; + import { DateToken, PeriodType } from '$lib/utils/date'; import Code from '$lib/components/Code.svelte'; import TextField from '$lib/components/TextField.svelte'; import MenuField from '$lib/components/MenuField.svelte'; import type { FormatNumberStyle } from '$lib/utils/number'; + import DatePickerField from '$lib/components/DatePickerField.svelte'; + import { getSettings } from '$lib/components/settings'; + + const { format, locale } = getSettings(); let value = 1234.56; let style: FormatNumberStyle = 'decimal'; - let locales: string = 'en'; // let currency: string = 'USD'; - const date = new Date('1982-03-30T00:00:00'); + let myDate = new Date('1982-03-30T07:11:00'); </script> <h1>Usage</h1> -<Code source={`import { format } from 'svelte-ux';`} language="javascript" class="mb-4" /> - -<h1>Examples</h1> +<Code + source={"const { format } = getSettings();\n$format(123.456, 'decimal');"} + language="javascript" + class="mb-4" +/> -<h2>Playground</h2> +<h1>Playgrounds</h1> +<h2>Playground numbers</h2> <div class="grid grid-cols-xs gap-2 mb-2"> - <TextField label="value" bind:value type="decimal" /> + <TextField label="number" bind:value type="decimal" /> + + <MenuField + label="locale" + bind:value={$locale} + options={['en', 'de', 'fr', 'jp'].map((value) => ({ label: value, value }))} + /> <MenuField label="style" @@ -34,12 +45,6 @@ )} /> - <MenuField - label="locale" - bind:value={locales} - options={['en', 'de', 'fr', 'jp'].map((value) => ({ label: value, value }))} - /> - <MenuField label="currency" bind:value={currency} @@ -48,48 +53,354 @@ </div> <Preview> - <div>{format(value, style, { locales, currency })}</div> + <div>{$format(value, style, { currency })}</div> </Preview> -<h2>number formats (defaut settings)</h2> +<h2>Playground dates</h2> + +<div class="grid grid-cols-xs gap-2 mb-2"> + <DatePickerField format="dd/MM/yyyy" label="date" bind:value={myDate}></DatePickerField> + + <MenuField + label="locale" + bind:value={$locale} + options={['en', 'de', 'fr', 'jp'].map((value) => ({ label: value, value }))} + /> +</div> + +<Preview> + <div>{$format(myDate, PeriodType.Day)}</div> +</Preview> + +<h1>Numbers</h1> + +<h2>Number Formats (default settings)</h2> <Preview showCode> - <div>{format(1234.56, 'integer')}</div> - <div>{format(1234.56, 'decimal')}</div> - <div>{format(1234.56, 'currency')}</div> - <div>{format(0.5678, 'percent')}</div> - <div>{format(0.5678, 'percentRound')}</div> - <div>{format(1_234_567, 'metric', { minimumSignificantDigits: 5 })}</div> - <div>{format(1_200_000, 'metric')}</div> - <div>{format(0.5678, 'percent', { fractionDigits: 1 })}</div> + <div>{$format(1234.56, 'integer')}</div> + <div>{$format(1234.56, 'decimal')}</div> + <div>{$format(1234.56, 'currency')}</div> + <div>{$format(0.5678, 'percent')}</div> + <div>{$format(0.5678, 'percentRound')}</div> + <div>{$format(1_234_567, 'metric')}</div> + <div>{$format(1_200_000, 'metric')}</div> + <div>{$format(0.5678, 'percent')}</div> </Preview> -<h2>number formats (local settings)</h2> +<h2>number formats (additional options)</h2> <span> - You can customize numbers with the 3rd arg that is an enhanced <b>`Intl.NumberFormatOptions`</b> - type. You can pass for example locales like <b>fr</b>, <b>de</b>, ... You can also to that - globally in the <a class="text-accent-500" href="/customization#settings">Settings</a>. + You can customize numbers with the 3rd arg that is an enhanced <b>`Intl.NumberFormatOptions`</b> type. </span> <Preview showCode> - <div>{format(1234.56, 'integer', { locales: 'fr' })}</div> - <div>{format(1234.56, 'decimal', { locales: 'fr' })}</div> - <div>{format(1234.56, 'currency', { locales: 'fr', currency: 'EUR' })}</div> - <div>{format(0.5678, 'percent', { locales: 'fr' })}</div> - <div>{format(0.5678, 'percentRound', { locales: 'fr' })}</div> - <div>{format(1_234_567, 'metric', { locales: 'fr', minimumSignificantDigits: 5 })}</div> - <div>{format(1_200_000, 'metric', { locales: 'fr' })}</div> - <div>{format(0.5678, 'percent', { locales: 'fr', fractionDigits: 1 })}</div> + <div>{$format(1234.56, 'integer', { maximumSignificantDigits: 2 })}</div> + <div>{$format(1234.56, 'decimal', { maximumSignificantDigits: 5 })}</div> + <div>{$format(1234.56, 'currency', { currency: 'EUR' })}</div> + <div>{$format(0.5678, 'percent', { signDisplay: 'always' })}</div> + <div>{$format(0.5678, 'percentRound', { signDisplay: 'always' })}</div> + <div>{$format(1_234_567, 'metric', { minimumSignificantDigits: 12 })}</div> + <div>{$format(0.5678, 'percent', { fractionDigits: 1 })}</div> </Preview> -<h2>Period formats</h2> +<h1>Dates</h1> -<Preview showCode> - <div>{format(date, PeriodType.Day)}</div> - <div>{format(date, PeriodType.Month)}</div> - <div>{format(date, PeriodType.CalendarYear)}</div> - <div>{format(date, PeriodType.Day, 'short')}</div> - <div>{format(date, PeriodType.Month, 'short')}</div> - <div>{format(date, PeriodType.CalendarYear, 'short')}</div> -</Preview> +<h2>Custom format</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>With format string</h3> + <Preview> + {$format(myDate, PeriodType.Custom, { + custom: 'eee, MMMM do', + })} + </Preview> + </div> + <div> + <h3>With descriptive tokens</h3> + <Preview> + {$format(myDate, PeriodType.Custom, { + custom: [DateToken.DayOfWeek_short, DateToken.Month_long, DateToken.DayOfMonth_withOrdinal], + })} + </Preview> + </div> + <div> + <h3>With full intl</h3> + <Preview> + {$format(myDate, PeriodType.Custom, { + custom: { weekday: 'short', month: 'long', day: 'numeric', withOrdinal: true }, + })} + </Preview> + </div> +</div> + +<h2>PeriodType Day</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.Day, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.Day, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.Day, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType DayTime</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.DayTime, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.DayTime, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.DayTime, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType TimeOnly</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.TimeOnly, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.TimeOnly, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.TimeOnly, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType Week</h2> +<span> + It will take your default <b>weekStartsOn</b> + <a class="text-accent-500" href="/customization#settings">settings</a>, if you want to be + specific, you can also use + <b>PeriodType.WeekSun</b> +</span> +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.Week, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.Week, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.Week, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType BiWeek1</h2> +<span> + It will take your default <b>weekStartsOn</b> + <a class="text-accent-500" href="/customization#settings">settings</a>, if you want to be + specific, you can also use + <b>PeriodType.BiWeek1Sun</b> +</span> +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.BiWeek1, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.BiWeek1, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.BiWeek1, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType Month</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.Month, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.Month, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.Month, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType Quarter</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.Quarter, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.Quarter, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.Quarter, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType CalendarYear</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.CalendarYear, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.CalendarYear, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.CalendarYear, { + variant: 'long', + })} + </Preview> + </div> +</div> + +<h2>PeriodType FiscalYearOctober</h2> + +<div class="grid grid-cols-3 gap-4"> + <div> + <h3>short</h3> + <Preview> + {$format(myDate, PeriodType.FiscalYearOctober, { + variant: 'short', + })} + </Preview> + </div> + <div> + <h3>default</h3> + <Preview> + {$format(myDate, PeriodType.FiscalYearOctober, { + // variant: 'default', + })} + </Preview> + </div> + <div> + <h3>long</h3> + <Preview> + {$format(myDate, PeriodType.FiscalYearOctober, { + variant: 'long', + })} + </Preview> + </div> +</div> diff --git a/packages/svelte-ux/src/routes/docs/utils/format/+page.ts b/packages/svelte-ux/src/routes/docs/utils/format/+page.ts index 74db8cf11..7c3cef134 100644 --- a/packages/svelte-ux/src/routes/docs/utils/format/+page.ts +++ b/packages/svelte-ux/src/routes/docs/utils/format/+page.ts @@ -6,7 +6,12 @@ export async function load() { meta: { source, pageSource, - description: 'Easily format numbers and dates to a variety of formats', + description: 'Easily format numbers and dates to a variety of formats and locales', + features: [ + 'Number: Pass `style` for quick formatting', + 'Date: Pass `periodType` along with `variant` for quick formatting', + 'Date: Pass `custom` for greater control', + ], }, }; } diff --git a/packages/svelte-ux/src/routes/theme/+page.server.ts b/packages/svelte-ux/src/routes/theme/+page.server.ts new file mode 100644 index 000000000..8b0c74e13 --- /dev/null +++ b/packages/svelte-ux/src/routes/theme/+page.server.ts @@ -0,0 +1,11 @@ +import * as daisy from '$lib/styles/daisy'; +import * as skeleton from '$lib/styles/skeleton'; + +export async function load() { + return { + themes: { + daisy: daisy.themes, + skeleton: skeleton.themes, + }, + }; +} diff --git a/packages/svelte-ux/src/routes/theme/+page.svelte b/packages/svelte-ux/src/routes/theme/+page.svelte new file mode 100644 index 000000000..286c15418 --- /dev/null +++ b/packages/svelte-ux/src/routes/theme/+page.svelte @@ -0,0 +1,657 @@ +<script lang="ts"> + import { mdiChevronDown, mdiPalette, mdiWeatherNight, mdiWhiteBalanceSunny } from '@mdi/js'; + + import Button from '$lib/components/Button.svelte'; + import ButtonGroup from '$lib/components/ButtonGroup.svelte'; + import CopyButton from '$lib/components/CopyButton.svelte'; + import Icon from '$lib/components/Icon.svelte'; + import Menu from '$lib/components/Menu.svelte'; + import MenuItem from '$lib/components/MenuItem.svelte'; + import MenuField from '$lib/components/MenuField.svelte'; + import SelectField from '$lib/components/SelectField.svelte'; + import Switch from '$lib/components/Switch.svelte'; + import Toggle from '$lib/components/Toggle.svelte'; + import Tooltip from '$lib/components/Tooltip.svelte'; + + import { styleProps } from '$lib/actions/styleProps.js'; + import { + getThemeNames, + processThemeColors, + themeStylesString, + type SupportedColorSpace, + } from '$lib/styles/theme.js'; + import type { MenuOption } from '$lib/types/options.js'; + import ColorField from './ColorField.svelte'; + import { getSettings } from '$lib/components/settings'; + + export let data; + + type ThemeMenuOption = MenuOption & { + themeName: string; + theme: typeof customLightTheme | typeof data.themes.daisy | typeof data.themes.skeleton; + }; + + const { currentTheme } = getSettings(); + + let selectedLightThemeValue: string; + let selectedDarkThemeValue: string; + + let showOptionalColors = false; + + let colorSpace: SupportedColorSpace = 'hsl'; + + // Needs to always match app since using tailwind classes + const themeColorSpace: SupportedColorSpace = 'hsl'; + + const daisyThemeNames = getThemeNames(data.themes.daisy); + const skeletonThemeNames = getThemeNames(data.themes.skeleton); + + let customLightTheme = {}; + let customDarkTheme = {}; + + $: lightThemes = [ + { + label: 'Custom', + value: 'custom', + themeName: 'custom', + theme: customLightTheme, + }, + ...daisyThemeNames.light.map((themeName) => { + return { + label: themeName === 'light' ? 'light (daisy)' : themeName, + value: themeName === 'light' ? 'daisy-light' : themeName, + group: 'Daisy', + themeName, + theme: data.themes.daisy[themeName], + }; + }), + ...skeletonThemeNames.light.map((themeName) => { + return { + label: themeName === 'light' ? 'light (skeleton)' : themeName, + value: themeName === 'light' ? 'skeleton-light' : themeName, + group: 'Skeleton', + themeName, + theme: data.themes.skeleton[themeName], + }; + }), + ] as ThemeMenuOption[]; + + $: darkThemes = [ + { + label: 'Custom', + value: 'custom', + themeName: 'custom', + theme: customDarkTheme, + }, + ...daisyThemeNames.dark.map((themeName) => { + return { + label: themeName === 'dark' ? 'dark (daisy)' : themeName, + value: themeName === 'dark' ? 'daisy-dark' : themeName, + group: 'Daisy', + themeName, + theme: data.themes.daisy[themeName], + }; + }), + ...skeletonThemeNames.dark.map((themeName) => { + return { + label: themeName === 'dark' ? 'dark (skeleton)' : themeName, + value: themeName === 'dark' ? 'skeleton-dark' : themeName, + group: 'Skeleton', + themeName, + theme: data.themes.skeleton[themeName], + }; + }), + ] as ThemeMenuOption[]; + + // Set initial theme selections (skip custom) + $: if (selectedLightThemeValue === undefined) { + selectedLightThemeValue = lightThemes[1].value; + } + $: if (selectedDarkThemeValue === undefined) { + selectedDarkThemeValue = darkThemes[1].value; + } + + let showDarkTheme = false; + $: selectedLightTheme = lightThemes.find((d) => d.value === selectedLightThemeValue)?.theme; + $: selectedDarkTheme = darkThemes.find((d) => d.value === selectedDarkThemeValue)?.theme; + $: previewTheme = showDarkTheme ? selectedDarkTheme : selectedLightTheme; + + // Update site dark/light mode with preview for better experience (previewing and applying) + $: currentTheme.setTheme(showDarkTheme ? 'dark' : 'light'); + + // Break cyclical dependency with lightThemes => customLightTheme -> selectedLightTheme -> lightThemes + function updateCustomLightTheme() { + customLightTheme = { + ...selectedLightTheme, + primary: selectedLightTheme?.primary ?? selectedLightTheme?.['primary-500'], + secondary: selectedLightTheme?.secondary ?? selectedLightTheme?.['secondary-500'], + accent: selectedLightTheme?.accent ?? selectedLightTheme?.['accent-500'], + neutral: selectedLightTheme?.neutral ?? selectedLightTheme?.['neutral-500'], + }; + } + $: selectedLightTheme && updateCustomLightTheme(); + + // Break cyclical dependency with darkThemes => customDarkTheme -> selectedDarkTheme -> darkThemes + function updateCustomLDarkTheme() { + customDarkTheme = { + ...selectedDarkTheme, + primary: selectedDarkTheme?.primary ?? selectedDarkTheme?.['primary-500'], + secondary: selectedDarkTheme?.secondary ?? selectedDarkTheme?.['secondary-500'], + accent: selectedDarkTheme?.accent ?? selectedDarkTheme?.['accent-500'], + neutral: selectedDarkTheme?.neutral ?? selectedDarkTheme?.['neutral-500'], + }; + } + $: selectedDarkTheme && updateCustomLDarkTheme(); +</script> + +<main class="p-4 grid gap-3"> + <div class="grid sm:grid-cols-[1fr,1fr,auto,auto] gap-3"> + <SelectField + label="Light theme" + options={lightThemes} + bind:value={selectedLightThemeValue} + clearable={false} + toggleIcon={null} + stepper + on:change={() => (showDarkTheme = false)} + /> + <SelectField + label="Dark theme" + options={darkThemes} + bind:value={selectedDarkThemeValue} + clearable={false} + toggleIcon={null} + stepper + on:change={() => (showDarkTheme = true)} + /> + + <MenuField + label="Color space" + bind:value={colorSpace} + options={[ + { label: 'hex', value: 'hex' }, + { label: 'hsl', value: 'hsl' }, + { label: 'rgb', value: 'rgb' }, + { label: 'oklch', value: 'oklch' }, + ]} + /> + + <ButtonGroup variant="fill" color="primary"> + <Tooltip title="Copy themes to clipboard" offset={2}> + <CopyButton + value={JSON.stringify({ light: selectedLightTheme, dark: selectedDarkTheme }, null, 2)} + /> + </Tooltip> + + <Tooltip title="Override current themes" offset={2}> + <Button + icon={mdiPalette} + iconOnly={false} + on:click={() => { + const style = + document.getElementById('custom-theme') ?? document.createElement('style'); + style.id = 'custom-theme'; + + style.textContent = ` + :root { ${themeStylesString(selectedLightTheme, themeColorSpace)} } + @media (prefers-color-scheme: dark) { + :root { + ${themeStylesString(selectedDarkTheme, themeColorSpace)} + } + } + [data-theme=light] { ${themeStylesString(selectedLightTheme, themeColorSpace)} } + [data-theme=dark] { ${themeStylesString(selectedDarkTheme, themeColorSpace)} } + `; + document.head.appendChild(style); + + // TODO: Update settings({ themes: { light: ['light'], dark: ['dark'] }}) + }} + /> + </Tooltip> + + <Toggle let:on={open} let:toggle> + <div class="grid"> + <Button icon={mdiChevronDown} on:click={toggle} rounded class="px-1" /> + <Menu {open} on:close={toggle} placement="bottom-start"> + <MenuItem + on:click={() => { + const allThemes = { + ...data.themes.daisy, + ...Object.fromEntries( + Object.entries(data.themes.skeleton).map(([themeName, value]) => { + return [ + themeName === 'light' + ? 'skeleton-light' + : themeName === 'dark' + ? 'skeleton-dark' + : themeName, + value, + ]; + }) + ), + }; + const clipboardData = JSON.stringify(allThemes, null, 2); + navigator.clipboard.writeText(clipboardData); + }} + > + Copy All themes + </MenuItem> + <MenuItem + on:click={() => { + const clipboardData = JSON.stringify(data.themes.daisy, null, 2); + navigator.clipboard.writeText(clipboardData); + }} + > + Copy Daisy themes + </MenuItem> + <MenuItem + on:click={() => { + const clipboardData = JSON.stringify(data.themes.skeleton, null, 2); + navigator.clipboard.writeText(clipboardData); + }} + > + Copy Skeleton themes + </MenuItem> + </Menu> + </div> + </Toggle> + </ButtonGroup> + </div> + + <div class="grid sm:grid-cols-2 gap-2"> + <div class="grid gap-2"> + <ColorField + label="Primary" + bind:value={customLightTheme.primary} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <ColorField + label="Secondary" + bind:value={customLightTheme.secondary} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <ColorField + label="Accent" + bind:value={customLightTheme.accent} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + + {#if showOptionalColors} + <ColorField + label="Neutral (optional)" + bind:value={customLightTheme.neutral} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <!-- State colors --> + <ColorField + label="Info (optional)" + bind:value={customLightTheme.info} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <ColorField + label="Success (optional)" + bind:value={customLightTheme.success} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <ColorField + label="Warning (optional)" + bind:value={customLightTheme.warning} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <ColorField + label="Danger (optional)" + bind:value={customLightTheme.danger} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + {/if} + + <ColorField + label="Surface 100" + bind:value={customLightTheme['surface-100']} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + {#if showOptionalColors} + <ColorField + label="Surface 200 (optional)" + bind:value={customLightTheme['surface-200']} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + <ColorField + label="Surface 300 (optional)" + bind:value={customLightTheme['surface-300']} + on:change={() => { + selectedLightThemeValue = 'custom'; + showDarkTheme = false; + }} + {colorSpace} + /> + {/if} + </div> + + <div class="grid gap-2"> + <ColorField + label="Primary" + bind:value={customDarkTheme.primary} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <ColorField + label="Secondary" + bind:value={customDarkTheme.secondary} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <ColorField + label="Accent" + bind:value={customDarkTheme.accent} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + + {#if showOptionalColors} + <ColorField + label="Neutral (optional)" + bind:value={customDarkTheme.neutral} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <!-- State colors --> + <ColorField + label="Info (optional)" + bind:value={customDarkTheme.info} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <ColorField + label="Success (optional)" + bind:value={customDarkTheme.success} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <ColorField + label="Warning (optional)" + bind:value={customDarkTheme.warning} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <ColorField + label="Danger (optional)" + bind:value={customDarkTheme.danger} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + {/if} + + <ColorField + label="Surface 100" + bind:value={customDarkTheme['surface-100']} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + {#if showOptionalColors} + <ColorField + label="Surface 200 (optional)" + bind:value={customDarkTheme['surface-200']} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + <ColorField + label="Surface 300 (optional)" + bind:value={customDarkTheme['surface-300']} + on:change={() => { + selectedDarkThemeValue = 'custom'; + showDarkTheme = true; + }} + {colorSpace} + /> + {/if} + </div> + </div> + <Button color="primary" size="sm" on:click={() => (showOptionalColors = !showOptionalColors)}> + {showOptionalColors ? 'Hide' : 'Show'} optional colors + </Button> + + <h1 class="grid grid-cols-[1fr,auto]"> + Theme preview + + <Switch + checked={showDarkTheme} + on:change={(e) => (showDarkTheme = e.target.checked)} + let:checked + > + {#if checked} + <Icon data={mdiWeatherNight} size=".8rem" class="text-primary" /> + {:else} + <Icon data={mdiWhiteBalanceSunny} size=".8rem" class="text-primary" /> + {/if} + </Switch> + </h1> + + <div + class="bg-surface-100 border rounded py-2 px-3" + style:color={previewTheme?.['color-scheme'] === 'dark' ? 'white' : 'black'} + use:styleProps={previewTheme ? processThemeColors(previewTheme, 'hsl') : {}} + > + <div> + <div class="text-xl font-bold mb-2">Semantic colors</div> + + <div class="grid grid-cols-xs gap-3"> + <div class="swatch"> + <div class="bg-primary text-primary-content name">Primary</div> + <div class="bg-primary-50 shade"><span>50</span></div> + <div class="bg-primary-100 shade"><span>100</span></div> + <div class="bg-primary-200 shade"><span>200</span></div> + <div class="bg-primary-300 shade"><span>300</span></div> + <div class="bg-primary-400 shade"><span>400</span></div> + <div class="bg-primary-500 shade"><span>500</span></div> + <div class="bg-primary-600 shade"><span>600</span></div> + <div class="bg-primary-700 shade"><span>700</span></div> + <div class="bg-primary-800 shade"><span>800</span></div> + <div class="bg-primary-900 shade"><span>900</span></div> + </div> + + <div class="swatch"> + <div class="bg-secondary text-secondary-content name">Secondary</div> + <div class="bg-secondary-50 shade"><span>50</span></div> + <div class="bg-secondary-100 shade"><span>100</span></div> + <div class="bg-secondary-200 shade"><span>200</span></div> + <div class="bg-secondary-300 shade"><span>300</span></div> + <div class="bg-secondary-400 shade"><span>400</span></div> + <div class="bg-secondary-500 shade"><span>500</span></div> + <div class="bg-secondary-600 shade"><span>600</span></div> + <div class="bg-secondary-700 shade"><span>700</span></div> + <div class="bg-secondary-800 shade"><span>800</span></div> + <div class="bg-secondary-900 shade"><span>900</span></div> + </div> + + <div class="swatch"> + <div class="bg-accent text-accent-content name">Accent</div> + <div class="bg-accent-50 shade"><span>50</span></div> + <div class="bg-accent-100 shade"><span>100</span></div> + <div class="bg-accent-200 shade"><span>200</span></div> + <div class="bg-accent-300 shade"><span>300</span></div> + <div class="bg-accent-400 shade"><span>400</span></div> + <div class="bg-accent-500 shade"><span>500</span></div> + <div class="bg-accent-600 shade"><span>600</span></div> + <div class="bg-accent-700 shade"><span>700</span></div> + <div class="bg-accent-800 shade"><span>800</span></div> + <div class="bg-accent-900 shade"><span>900</span></div> + </div> + + <div class="swatch"> + <div class="bg-neutral text-neutral-content name">Neutral</div> + <div class="bg-neutral-50 shade"><span>50</span></div> + <div class="bg-neutral-100 shade"><span>100</span></div> + <div class="bg-neutral-200 shade"><span>200</span></div> + <div class="bg-neutral-300 shade"><span>300</span></div> + <div class="bg-neutral-400 shade"><span>400</span></div> + <div class="bg-neutral-500 shade"><span>500</span></div> + <div class="bg-neutral-600 shade"><span>600</span></div> + <div class="bg-neutral-700 shade"><span>700</span></div> + <div class="bg-neutral-800 shade"><span>800</span></div> + <div class="bg-neutral-900 shade"><span>900</span></div> + </div> + </div> + </div> + + <div> + <div class="text-xl font-bold mt-4 mb-2">State colors</div> + + <div class="grid grid-cols-xs gap-3"> + <div class="swatch"> + <div class="bg-info text-info-content name">Info</div> + <div class="bg-info-50 shade"><span>50</span></div> + <div class="bg-info-100 shade"><span>100</span></div> + <div class="bg-info-200 shade"><span>200</span></div> + <div class="bg-info-300 shade"><span>300</span></div> + <div class="bg-info-400 shade"><span>400</span></div> + <div class="bg-info-500 shade"><span>500</span></div> + <div class="bg-info-600 shade"><span>600</span></div> + <div class="bg-info-700 shade"><span>700</span></div> + <div class="bg-info-800 shade"><span>800</span></div> + <div class="bg-info-900 shade"><span>900</span></div> + </div> + + <div class="swatch"> + <div class="bg-success text-success-content name">Success</div> + <div class="bg-success-50 shade"><span>50</span></div> + <div class="bg-success-100 shade"><span>100</span></div> + <div class="bg-success-200 shade"><span>200</span></div> + <div class="bg-success-300 shade"><span>300</span></div> + <div class="bg-success-400 shade"><span>400</span></div> + <div class="bg-success-500 shade"><span>500</span></div> + <div class="bg-success-600 shade"><span>600</span></div> + <div class="bg-success-700 shade"><span>700</span></div> + <div class="bg-success-800 shade"><span>800</span></div> + <div class="bg-success-900 shade"><span>900</span></div> + </div> + + <div class="swatch"> + <div class="bg-warning text-warning-content name">Warning</div> + <div class="bg-warning-50 shade"><span>50</span></div> + <div class="bg-warning-100 shade"><span>100</span></div> + <div class="bg-warning-200 shade"><span>200</span></div> + <div class="bg-warning-300 shade"><span>300</span></div> + <div class="bg-warning-400 shade"><span>400</span></div> + <div class="bg-warning-500 shade"><span>500</span></div> + <div class="bg-warning-600 shade"><span>600</span></div> + <div class="bg-warning-700 shade"><span>700</span></div> + <div class="bg-warning-800 shade"><span>800</span></div> + <div class="bg-warning-900 shade"><span>900</span></div> + </div> + + <div class="swatch"> + <div class="bg-danger text-danger-content name">Danger</div> + <div class="bg-danger-50 shade"><span>50</span></div> + <div class="bg-danger-100 shade"><span>100</span></div> + <div class="bg-danger-200 shade"><span>200</span></div> + <div class="bg-danger-300 shade"><span>300</span></div> + <div class="bg-danger-400 shade"><span>400</span></div> + <div class="bg-danger-500 shade"><span>500</span></div> + <div class="bg-danger-600 shade"><span>600</span></div> + <div class="bg-danger-700 shade"><span>700</span></div> + <div class="bg-danger-800 shade"><span>800</span></div> + <div class="bg-danger-900 shade"><span>900</span></div> + </div> + </div> + </div> + + <div> + <div class="text-xl font-bold mt-4 mb-2">Surface colors</div> + + <div class="grid grid-cols-xs gap-3"> + <div class="swatch"> + <div class="bg-surface text-surface-content name">Surface</div> + <div class="bg-surface-100 shade"><span>100</span></div> + <div class="bg-surface-200 shade"><span>200</span></div> + <div class="bg-surface-300 shade"><span>300</span></div> + </div> + </div> + </div> + </div> +</main> + +<style lang="postcss"> + .swatch { + @apply rounded-lg overflow-hidden border; + } + .swatch .name { + @apply grid place-items-center items-center font-semibold py-2; + } + .shade { + @apply grid place-items-center py-1 text-sm; + } + .shade span { + @apply bg-black/10 rounded px-2 text-white; + } +</style> diff --git a/packages/svelte-ux/src/routes/theme/ColorField.svelte b/packages/svelte-ux/src/routes/theme/ColorField.svelte new file mode 100644 index 000000000..fcac48ee9 --- /dev/null +++ b/packages/svelte-ux/src/routes/theme/ColorField.svelte @@ -0,0 +1,58 @@ +<script lang="ts"> + import { createEventDispatcher, type ComponentProps } from 'svelte'; + import { formatHex } from 'culori'; + + import TextField from '$lib/components/TextField.svelte'; + import { colorVariableValue, type SupportedColorSpace } from '$lib/styles/theme'; + + const dispatch = createEventDispatcher<{ + change: { value: string | undefined }; + }>(); + + type $$Props = ComponentProps<TextField> & { value: string }; + + export let value: string; + export let colorSpace: SupportedColorSpace | 'hex' = 'rgb'; + + function formatColor(value: string, colorSpace: SupportedColorSpace | 'hex') { + if (value) { + if (colorSpace === 'hex') { + // Only format if not already formatted. Fixes `#123` becoming `#112233` + return value.startsWith('#') ? value : formatHex(value); + } else { + const colorValue = colorVariableValue(value, colorSpace); + if (colorValue) { + return `${colorSpace}(${colorValue})`; + } else { + // Return original if unable to convert (i.e invalid such as `rgb( 20 30)`) + return value; + } + } + } else { + return value; + } + } +</script> + +<TextField + value={formatColor(value, colorSpace)} + on:change={(e) => { + value = formatColor(e.detail.inputValue, colorSpace); + console.log(value, e.detail.inputValue); + dispatch('change', { value }); + }} + {...$$restProps} +> + <div slot="prepend" class="grid grid-stack mr-3"> + <div class="w-6 h-6 border rounded" style:background={value} /> + <input + type="color" + value={formatHex(value)} + on:input={(e) => { + value = formatColor(e.target.value, colorSpace); + dispatch('change', { value }); + }} + class="w-6 h-6 rounded opacity-0 cursor-pointer" + /> + </div> +</TextField> diff --git a/packages/svelte-ux/tailwind.config.cjs b/packages/svelte-ux/tailwind.config.cjs index 0f10b55a6..a487cda9d 100644 --- a/packages/svelte-ux/tailwind.config.cjs +++ b/packages/svelte-ux/tailwind.config.cjs @@ -1,13 +1,26 @@ -const colors = require('tailwindcss/colors'); const plugin = require('tailwindcss/plugin'); +const colors = require('tailwindcss/colors'); + +const svelteUx = require('./src/lib/plugins/tailwind.cjs'); module.exports = { content: ['./src/**/*.{html,svelte,md,ts,js}'], + ux: { + themes: require('./themes.json'), + // themes: { + // light: { + // primary: colors['blue']['500'], + // 'primary-content': 'white', + // secondary: colors['cyan']['300'], + // 'surface-100': 'white', + // 'surface-200': colors['gray']['100'], + // 'surface-300': colors['gray']['300'], + // 'surface-content': colors['gray']['900'], + // }, + // }, + }, theme: { extend: { - colors: { - accent: colors.blue, - }, backgroundImage: { 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 'gradient-conic': 'conic-gradient(var(--tw-gradient-stops))', @@ -18,10 +31,10 @@ module.exports = { extend: {}, }, plugins: [ - require('./src/lib/plugins/tailwind.cjs'), + svelteUx({ colorSpace: 'hsl' }), require('@tailwindcss/typography'), - plugin(function ({ addBase, addComponents, theme }) { + plugin(function ({ addComponents }) { // Consider moving to tailwind plugin addComponents({ '.grid-cols-xs': { @@ -37,24 +50,6 @@ module.exports = { '@apply grid-cols-1 md:grid-cols-[repeat(auto-fill,minmax(600px,1fr))]': {}, }, }); - - // Expose color palette as CSS variables (--color-xxx-yyy) - https://gist.github.com/Merott/d2a19b32db07565e94f10d13d11a8574 - function extractColorVars(colorObj, colorGroup = '') { - return Object.keys(colorObj).reduce((vars, colorKey) => { - const value = colorObj[colorKey]; - - const newVars = - typeof value === 'string' - ? { [`--color${colorGroup}-${colorKey}`]: value } - : extractColorVars(value, `-${colorKey}`); - - return { ...vars, ...newVars }; - }, {}); - } - - addBase({ - ':root': extractColorVars(theme('colors')), - }); }), ], }; diff --git a/packages/svelte-ux/themes.json b/packages/svelte-ux/themes.json new file mode 100644 index 000000000..9b556338d --- /dev/null +++ b/packages/svelte-ux/themes.json @@ -0,0 +1,1798 @@ +{ + "light": { + "color-scheme": "light", + "primary": "oklch(49.12% 0.3096 275.75)", + "secondary": "oklch(69.71% 0.329 342.55)", + "secondary-content": "oklch(98.71% 0.0106 342.55)", + "accent": "oklch(76.76% 0.184 183.61)", + "neutral": "#2B3440", + "neutral-content": "#D7DDE4", + "surface-100": "oklch(100% 0 0)", + "surface-200": "#F2F2F2", + "surface-300": "#E5E6E6", + "surface-content": "#1f2937" + }, + "dark": { + "color-scheme": "dark", + "primary": "oklch(65.69% 0.196 275.75)", + "secondary": "oklch(74.8% 0.26 342.55)", + "accent": "oklch(74.51% 0.167 183.61)", + "neutral": "#2a323c", + "neutral-content": "#A6ADBB", + "surface-100": "#1d232a", + "surface-200": "#191e24", + "surface-300": "#15191e", + "surface-content": "#A6ADBB" + }, + "cupcake": { + "color-scheme": "light", + "primary": "#65c3c8", + "secondary": "#ef9fbc", + "accent": "#eeaf3a", + "neutral": "#291334", + "surface-100": "#faf7f5", + "surface-200": "#efeae6", + "surface-300": "#e7e2df", + "surface-content": "#291334", + "--rounded-btn": "1.9rem", + "--tab-border": "2px", + "--tab-radius": "0.7rem" + }, + "bumblebee": { + "color-scheme": "light", + "primary": "oklch(89.51% 0.2132 96.61)", + "primary-content": "oklch(38.92% 0.046 96.61)", + "secondary": "oklch(80.39% 0.194 70.76)", + "secondary-content": "oklch(39.38% 0.068 70.76)", + "accent": "oklch(81.27% 0.157 56.52)", + "neutral": "oklch(12.75% 0.075 281.99)", + "surface-100": "oklch(100% 0 0)" + }, + "emerald": { + "color-scheme": "light", + "primary": "#66cc8a", + "primary-content": "#223D30", + "secondary": "#377cfb", + "secondary-content": "#fff", + "accent": "#f68067", + "accent-content": "#000", + "neutral": "#333c4d", + "neutral-content": "#f9fafb", + "surface-100": "oklch(100% 0 0)", + "surface-content": "#333c4d", + "--animation-btn": "0", + "--animation-input": "0", + "--btn-focus-scale": "1" + }, + "corporate": { + "color-scheme": "light", + "primary": "oklch(60.39% 0.228 269.1)", + "secondary": "#7b92b2", + "accent": "#67cba0", + "neutral": "#181a2a", + "neutral-content": "#edf2f7", + "surface-100": "oklch(100% 0 0)", + "surface-content": "#181a2a", + "--rounded-box": "0.25rem", + "--rounded-btn": ".125rem", + "--rounded-badge": ".125rem", + "--tab-radius": "0.25rem", + "--animation-btn": "0", + "--animation-input": "0", + "--btn-focus-scale": "1" + }, + "synthwave": { + "color-scheme": "dark", + "primary": "#e779c1", + "secondary": "#58c7f3", + "accent": "oklch(88.04% 0.206 93.72)", + "neutral": "#221551", + "neutral-content": "#f9f7fd", + "surface-100": "#1a103d", + "surface-content": "#f9f7fd", + "info": "#53c0f3", + "info-content": "#201047", + "success": "#71ead2", + "success-content": "#201047", + "warning": "#eace6c", + "warning-content": "#201047", + "danger": "#ec8c78", + "danger-content": "#201047" + }, + "retro": { + "color-scheme": "light", + "primary": "#ef9995", + "primary-content": "#282425", + "secondary": "#a4cbb4", + "secondary-content": "#282425", + "accent": "#DC8850", + "accent-content": "#282425", + "neutral": "#2E282A", + "neutral-content": "#EDE6D4", + "surface-100": "#ece3ca", + "surface-200": "#e4d8b4", + "surface-300": "#DBCA9A", + "surface-content": "#282425", + "info": "#2563eb", + "success": "#16a34a", + "warning": "#d97706", + "danger": "oklch(65.72% 0.199 27.33)", + "--rounded-box": "0.4rem", + "--rounded-btn": "0.4rem", + "--rounded-badge": "0.4rem", + "--tab-radius": "0.4rem" + }, + "cyberpunk": { + "color-scheme": "light", + "fontFamily": "ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace", + "primary": "oklch(74.22% 0.209 6.35)", + "secondary": "oklch(83.33% 0.184 204.72)", + "accent": "oklch(71.86% 0.2176 310.43)", + "neutral": "oklch(23.04% 0.065 269.31)", + "neutral-content": "oklch(94.51% 0.179 104.32)", + "surface-100": "oklch(94.51% 0.179 104.32)", + "--rounded-box": "0", + "--rounded-btn": "0", + "--rounded-badge": "0", + "--tab-radius": "0" + }, + "valentine": { + "color-scheme": "light", + "primary": "#e96d7b", + "secondary": "#a991f7", + "accent": "#66b1b3", + "neutral": "#af4670", + "neutral-content": "#f0d6e8", + "surface-100": "#fae7f4", + "surface-content": "#632c3b", + "info": "#2563eb", + "success": "#16a34a", + "warning": "#d97706", + "danger": "oklch(73.07% 0.207 27.33)", + "--rounded-btn": "1.9rem", + "--tab-radius": "0.7rem" + }, + "halloween": { + "color-scheme": "dark", + "primary": "oklch(77.48% 0.204 60.62)", + "primary-content": "#131616", + "secondary": "oklch(45.98% 0.248 305.03)", + "accent": "oklch(64.8% 0.223 136.07347934356451)", + "accent-content": "#000000", + "neutral": "#2F1B05", + "surface-100": "#212121", + "info": "#2563eb", + "success": "#16a34a", + "warning": "#d97706", + "danger": "oklch(65.72% 0.199 27.33)" + }, + "garden": { + "color-scheme": "light", + "primary": "oklch(62.45% 0.278 3.8363600743192197)", + "primary-content": "#fff", + "secondary": "#8E4162", + "accent": "#5c7f67", + "neutral": "#291E00", + "neutral-content": "#e9e7e7", + "surface-100": "#e9e7e7", + "surface-content": "#100f0f" + }, + "forest": { + "color-scheme": "dark", + "primary": "#1eb854", + "primary-content": "#000000", + "secondary": "#1DB88E", + "accent": "#1DB8AB", + "neutral": "#19362D", + "surface-100": "#171212", + "--rounded-btn": "1.9rem" + }, + "aqua": { + "color-scheme": "dark", + "primary": "#09ecf3", + "primary-content": "#005355", + "secondary": "#966fb3", + "accent": "#ffe999", + "neutral": "#3b8ac4", + "surface-100": "#345da7", + "info": "#2563eb", + "success": "#16a34a", + "warning": "#d97706", + "danger": "oklch(73.95% 0.19 27.33)" + }, + "lofi": { + "color-scheme": "light", + "primary": "#0D0D0D", + "primary-content": "oklch(100% 0 0)", + "secondary": "#1A1919", + "secondary-content": "oklch(100% 0 0)", + "accent": "#262626", + "accent-content": "oklch(100% 0 0)", + "neutral": "#000000", + "neutral-content": "oklch(100% 0 0)", + "surface-100": "oklch(100% 0 0)", + "surface-200": "#F2F2F2", + "surface-300": "#E6E5E5", + "surface-content": "#000000", + "info": "oklch(79.54% 0.103 205.9)", + "success": "oklch(90.13% 0.153 164.14)", + "warning": "oklch(88.37% 0.135 79.94)", + "danger": "oklch(78.66% 0.15 28.47)", + "--rounded-box": "0.25rem", + "--rounded-btn": "0.125rem", + "--rounded-badge": "0.125rem", + "--tab-radius": "0.125rem", + "--animation-btn": "0", + "--animation-input": "0", + "--btn-focus-scale": "1" + }, + "pastel": { + "color-scheme": "light", + "primary": "#d1c1d7", + "secondary": "#f6cbd1", + "accent": "#b4e9d6", + "neutral": "#70acc7", + "surface-100": "oklch(100% 0 0)", + "surface-200": "#f9fafb", + "surface-300": "#d1d5db", + "--rounded-btn": "1.9rem", + "--tab-radius": "0.7rem" + }, + "fantasy": { + "color-scheme": "light", + "primary": "oklch(37.45% 0.189 325.02)", + "secondary": "oklch(53.92% 0.162 241.36)", + "accent": "oklch(75.98% 0.204 56.72)", + "neutral": "#1f2937", + "surface-100": "oklch(100% 0 0)", + "surface-content": "#1f2937" + }, + "wireframe": { + "color-scheme": "light", + "fontFamily": "Chalkboard,comic sans ms,'sans-serif'", + "primary": "#b8b8b8", + "secondary": "#b8b8b8", + "accent": "#b8b8b8", + "neutral": "#ebebeb", + "surface-100": "oklch(100% 0 0)", + "surface-200": "#eeeeee", + "surface-300": "#dddddd", + "info": "#0000ff", + "success": "#008000", + "warning": "#a6a659", + "danger": "#ff0000", + "--rounded-box": "0.2rem", + "--rounded-btn": "0.2rem", + "--rounded-badge": "0.2rem", + "--tab-radius": "0.2rem" + }, + "black": { + "color-scheme": "dark", + "primary": "#373737", + "secondary": "#373737", + "accent": "#373737", + "surface-100": "#000000", + "surface-200": "#141414", + "surface-300": "#262626", + "surface-content": "#d6d6d6", + "neutral": "#373737", + "info": "#0000ff", + "success": "#008000", + "warning": "#ffff00", + "danger": "#ff0000", + "--rounded-box": "0", + "--rounded-btn": "0", + "--rounded-badge": "0", + "--animation-btn": "0", + "--animation-input": "0", + "--btn-focus-scale": "1", + "--tab-radius": "0" + }, + "luxury": { + "color-scheme": "dark", + "primary": "oklch(100% 0 0)", + "secondary": "#152747", + "accent": "#513448", + "neutral": "#331800", + "neutral-content": "#FFE7A3", + "surface-100": "#09090b", + "surface-200": "#171618", + "surface-300": "#2e2d2f", + "surface-content": "#dca54c", + "info": "#66c6ff", + "success": "#87d039", + "warning": "#e2d562", + "danger": "#ff6f6f" + }, + "dracula": { + "color-scheme": "dark", + "primary": "#ff79c6", + "secondary": "#bd93f9", + "accent": "#ffb86c", + "neutral": "#414558", + "surface-100": "#282a36", + "surface-content": "#f8f8f2", + "info": "#8be9fd", + "success": "#50fa7b", + "warning": "#f1fa8c", + "danger": "#ff5555" + }, + "cmyk": { + "color-scheme": "light", + "primary": "#45AEEE", + "secondary": "#E8488A", + "accent": "#FFF232", + "neutral": "#1a1a1a", + "surface-100": "oklch(100% 0 0)", + "info": "#4AA8C0", + "success": "#823290", + "warning": "#EE8133", + "danger": "#E93F33" + }, + "autumn": { + "color-scheme": "light", + "primary": "#8C0327", + "secondary": "#D85251", + "accent": "#D59B6A", + "neutral": "#826A5C", + "surface-100": "#f1f1f1", + "info": "#42ADBB", + "success": "#499380", + "warning": "#E97F14", + "danger": "oklch(53.07% 0.241 24.16)" + }, + "business": { + "color-scheme": "dark", + "primary": "#1C4E80", + "secondary": "#7C909A", + "accent": "#EA6947", + "neutral": "#23282E", + "surface-100": "#202020", + "info": "#0091D5", + "success": "#6BB187", + "warning": "#DBAE59", + "danger": "#AC3E31", + "--rounded-box": "0.25rem", + "--rounded-btn": ".125rem", + "--rounded-badge": ".125rem" + }, + "acid": { + "color-scheme": "light", + "primary": "oklch(71.9% 0.357 330.7595734057481)", + "secondary": "oklch(73.37% 0.224 48.25087840015526)", + "accent": "oklch(92.78% 0.264 122.96295065960891)", + "neutral": "oklch(21.31% 0.128 278.68)", + "surface-100": "#fafafa", + "info": "oklch(60.72% 0.227 252.05)", + "success": "oklch(85.72% 0.266 158.53)", + "warning": "oklch(91.01% 0.212 100.5)", + "danger": "oklch(64.84% 0.293 29.34918758658804)", + "--rounded-box": "1.25rem", + "--rounded-btn": "1rem", + "--rounded-badge": "1rem", + "--tab-radius": "0.7rem" + }, + "lemonade": { + "color-scheme": "light", + "primary": "oklch(58.92% 0.199 134.6)", + "secondary": "oklch(77.75% 0.196 111.09)", + "accent": "oklch(85.39% 0.201 100.73)", + "neutral": "oklch(30.98% 0.075 108.6)", + "surface-100": "oklch(98.71% 0.02 123.72)", + "info": "oklch(86.19% 0.047 224.14)", + "success": "oklch(86.19% 0.047 157.85)", + "warning": "oklch(86.19% 0.047 102.15)", + "danger": "oklch(86.19% 0.047 25.85)" + }, + "night": { + "color-scheme": "dark", + "primary": "#38bdf8", + "secondary": "#818CF8", + "accent": "#F471B5", + "neutral": "#1E293B", + "surface-100": "#0F172A", + "info": "#0CA5E9", + "info-content": "#000000", + "success": "#2DD4BF", + "warning": "#F4BF50", + "danger": "#FB7085" + }, + "coffee": { + "color-scheme": "dark", + "primary": "#DB924B", + "secondary": "#263E3F", + "accent": "#10576D", + "neutral": "#120C12", + "surface-100": "#20161F", + "surface-content": "#c59f60", + "info": "#8DCAC1", + "success": "#9DB787", + "warning": "#FFD25F", + "danger": "#FC9581" + }, + "winter": { + "color-scheme": "light", + "primary": "oklch(56.86% 0.255 257.57)", + "secondary": "#463AA2", + "accent": "#C148AC", + "neutral": "#021431", + "surface-100": "oklch(100% 0 0)", + "surface-200": "#F2F7FF", + "surface-300": "#E3E9F4", + "surface-content": "#394E6A", + "info": "#93E7FB", + "success": "#81CFD1", + "warning": "#EFD7BB", + "danger": "#E58B8B" + }, + "dim": { + "color-scheme": "dark", + "primary": "#9FE88D", + "secondary": "#FF7D5C", + "accent": "#C792E9", + "neutral": "#1c212b", + "neutral-content": "#B2CCD6", + "surface-100": "#2A303C", + "surface-200": "#242933", + "surface-300": "#20252E", + "surface-content": "#B2CCD6", + "info": "#28ebff", + "success": "#62efbd", + "warning": "#efd057", + "danger": "#ffae9b" + }, + "nord": { + "color-scheme": "light", + "primary": "#5E81AC", + "secondary": "#81A1C1", + "accent": "#88C0D0", + "neutral": "#4C566A", + "neutral-content": "#D8DEE9", + "surface-100": "#ECEFF4", + "surface-200": "#E5E9F0", + "surface-300": "#D8DEE9", + "surface-content": "#2E3440", + "info": "#B48EAD", + "success": "#A3BE8C", + "warning": "#EBCB8B", + "danger": "#BF616A", + "--rounded-box": "0.4rem", + "--rounded-btn": "0.2rem", + "--rounded-badge": "0.4rem", + "--tab-radius": "0.2rem" + }, + "sunset": { + "color-scheme": "dark", + "primary": "#FF865B", + "secondary": "#FD6F9C", + "accent": "#B387FA", + "neutral": "oklch(26% 0.019 237.69)", + "neutral-content": "oklch(70% 0.019 237.69)", + "surface-100": "oklch(22% 0.019 237.69)", + "surface-200": "oklch(20% 0.019 237.69)", + "surface-300": "oklch(18% 0.019 237.69)", + "surface-content": "#9fb9d0", + "info": "#89e0eb", + "success": "#addfad", + "warning": "#f1c891", + "danger": "#ffbbbd", + "--rounded-box": "1.2rem", + "--rounded-btn": "0.8rem", + "--rounded-badge": "0.4rem", + "--tab-radius": "0.7rem" + }, + "skeleton-light": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(207 241 230)", + "primary-200": "rgb(195 238 224)", + "primary-300": "rgb(159 227 205)", + "primary-400": "rgb(87 207 167)", + "primary-500": "rgb(15 186 129)", + "primary-600": "rgb(14 167 116)", + "primary-700": "rgb(11 140 97)", + "primary-800": "rgb(9 112 77)", + "primary-900": "rgb(7 91 63)", + "secondary-100": "rgb(220 218 250)", + "secondary-200": "rgb(211 209 249)", + "secondary-300": "rgb(185 181 245)", + "secondary-400": "rgb(132 126 237)", + "secondary-500": "rgb(79 70 229)", + "secondary-600": "rgb(71 63 206)", + "secondary-700": "rgb(59 53 172)", + "secondary-800": "rgb(47 42 137)", + "secondary-900": "rgb(39 34 112)", + "accent-100": "rgb(207 237 251)", + "accent-200": "rgb(195 233 250)", + "accent-300": "rgb(159 219 246)", + "accent-400": "rgb(86 192 240)", + "accent-500": "rgb(14 165 233)", + "accent-600": "rgb(13 149 210)", + "accent-700": "rgb(11 124 175)", + "accent-800": "rgb(8 99 140)", + "accent-900": "rgb(7 81 114)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(251 240 206)", + "warning-200": "rgb(250 236 193)", + "warning-300": "rgb(247 225 156)", + "warning-400": "rgb(240 202 82)", + "warning-500": "rgb(234 179 8)", + "warning-600": "rgb(211 161 7)", + "warning-700": "rgb(176 134 6)", + "warning-800": "rgb(140 107 5)", + "warning-900": "rgb(115 88 4)", + "danger-100": "rgb(246 209 228)", + "danger-200": "rgb(244 198 221)", + "danger-300": "rgb(238 163 200)", + "danger-400": "rgb(225 94 159)", + "danger-500": "rgb(212 25 118)", + "danger-600": "rgb(191 23 106)", + "danger-700": "rgb(159 19 89)", + "danger-800": "rgb(127 15 71)", + "danger-900": "rgb(104 12 58)", + "surface-100": "rgb(228 230 238)", + "surface-200": "rgb(219 222 233)", + "surface-300": "rgb(210 214 227)", + "surface-400": "rgb(128 140 177)", + "surface-500": "rgb(73 90 143)", + "surface-600": "rgb(66 81 129)", + "surface-700": "rgb(55 68 107)", + "surface-800": "rgb(44 54 86)", + "surface-900": "rgb(36 44 70)", + "color-scheme": "light" + }, + "skeleton-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(207 241 230)", + "primary-200": "rgb(195 238 224)", + "primary-300": "rgb(159 227 205)", + "primary-400": "rgb(87 207 167)", + "primary-500": "rgb(15 186 129)", + "primary-600": "rgb(14 167 116)", + "primary-700": "rgb(11 140 97)", + "primary-800": "rgb(9 112 77)", + "primary-900": "rgb(7 91 63)", + "secondary-100": "rgb(220 218 250)", + "secondary-200": "rgb(211 209 249)", + "secondary-300": "rgb(185 181 245)", + "secondary-400": "rgb(132 126 237)", + "secondary-500": "rgb(79 70 229)", + "secondary-600": "rgb(71 63 206)", + "secondary-700": "rgb(59 53 172)", + "secondary-800": "rgb(47 42 137)", + "secondary-900": "rgb(39 34 112)", + "accent-100": "rgb(207 237 251)", + "accent-200": "rgb(195 233 250)", + "accent-300": "rgb(159 219 246)", + "accent-400": "rgb(86 192 240)", + "accent-500": "rgb(14 165 233)", + "accent-600": "rgb(13 149 210)", + "accent-700": "rgb(11 124 175)", + "accent-800": "rgb(8 99 140)", + "accent-900": "rgb(7 81 114)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(251 240 206)", + "warning-200": "rgb(250 236 193)", + "warning-300": "rgb(247 225 156)", + "warning-400": "rgb(240 202 82)", + "warning-500": "rgb(234 179 8)", + "warning-600": "rgb(211 161 7)", + "warning-700": "rgb(176 134 6)", + "warning-800": "rgb(140 107 5)", + "warning-900": "rgb(115 88 4)", + "danger-100": "rgb(246 209 228)", + "danger-200": "rgb(244 198 221)", + "danger-300": "rgb(238 163 200)", + "danger-400": "rgb(225 94 159)", + "danger-500": "rgb(212 25 118)", + "danger-600": "rgb(191 23 106)", + "danger-700": "rgb(159 19 89)", + "danger-800": "rgb(127 15 71)", + "danger-900": "rgb(104 12 58)", + "surface-100": "rgb(55 68 107)", + "surface-200": "rgb(44 54 86)", + "surface-300": "rgb(36 44 70)", + "surface-400": "rgb(128 140 177)", + "surface-500": "rgb(73 90 143)", + "surface-600": "rgb(66 81 129)", + "surface-700": "rgb(55 68 107)", + "surface-800": "rgb(44 54 86)", + "surface-900": "rgb(36 44 70)", + "color-scheme": "dark" + }, + "wintry": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(219 234 254)", + "primary-200": "rgb(191 219 254)", + "primary-300": "rgb(147 197 253)", + "primary-400": "rgb(96 165 250)", + "primary-500": "rgb(59 130 246)", + "primary-600": "rgb(37 99 235)", + "primary-700": "rgb(29 78 216)", + "primary-800": "rgb(30 64 175)", + "primary-900": "rgb(30 58 138)", + "secondary-100": "rgb(224 242 254)", + "secondary-200": "rgb(186 230 253)", + "secondary-300": "rgb(125 211 252)", + "secondary-400": "rgb(56 189 248)", + "secondary-500": "rgb(14 165 233)", + "secondary-600": "rgb(2 132 199)", + "secondary-700": "rgb(3 105 161)", + "secondary-800": "rgb(7 89 133)", + "secondary-900": "rgb(12 74 110)", + "accent-100": "rgb(224 231 255)", + "accent-200": "rgb(199 210 254)", + "accent-300": "rgb(165 180 252)", + "accent-400": "rgb(129 140 248)", + "accent-500": "rgb(99 102 241)", + "accent-600": "rgb(79 70 229)", + "accent-700": "rgb(67 56 202)", + "accent-800": "rgb(55 48 163)", + "accent-900": "rgb(49 46 129)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(251 240 206)", + "warning-200": "rgb(250 236 193)", + "warning-300": "rgb(247 225 156)", + "warning-400": "rgb(240 202 82)", + "warning-500": "rgb(234 179 8)", + "warning-600": "rgb(211 161 7)", + "warning-700": "rgb(176 134 6)", + "warning-800": "rgb(140 107 5)", + "warning-900": "rgb(115 88 4)", + "danger-100": "rgb(246 209 228)", + "danger-200": "rgb(244 198 221)", + "danger-300": "rgb(238 163 200)", + "danger-400": "rgb(225 94 159)", + "danger-500": "rgb(212 25 118)", + "danger-600": "rgb(191 23 106)", + "danger-700": "rgb(159 19 89)", + "danger-800": "rgb(127 15 71)", + "danger-900": "rgb(104 12 58)", + "surface-100": "rgb(249 250 251)", + "surface-200": "rgb(243 244 246)", + "surface-300": "rgb(229 231 235)", + "surface-400": "rgb(156 163 175)", + "surface-500": "rgb(107 114 128)", + "surface-600": "rgb(75 85 99)", + "surface-700": "rgb(55 65 81)", + "surface-800": "rgb(31 41 55)", + "surface-900": "rgb(17 24 39)", + "color-scheme": "light" + }, + "wintry-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(219 234 254)", + "primary-200": "rgb(191 219 254)", + "primary-300": "rgb(147 197 253)", + "primary-400": "rgb(96 165 250)", + "primary-500": "rgb(59 130 246)", + "primary-600": "rgb(37 99 235)", + "primary-700": "rgb(29 78 216)", + "primary-800": "rgb(30 64 175)", + "primary-900": "rgb(30 58 138)", + "secondary-100": "rgb(224 242 254)", + "secondary-200": "rgb(186 230 253)", + "secondary-300": "rgb(125 211 252)", + "secondary-400": "rgb(56 189 248)", + "secondary-500": "rgb(14 165 233)", + "secondary-600": "rgb(2 132 199)", + "secondary-700": "rgb(3 105 161)", + "secondary-800": "rgb(7 89 133)", + "secondary-900": "rgb(12 74 110)", + "accent-100": "rgb(224 231 255)", + "accent-200": "rgb(199 210 254)", + "accent-300": "rgb(165 180 252)", + "accent-400": "rgb(129 140 248)", + "accent-500": "rgb(99 102 241)", + "accent-600": "rgb(79 70 229)", + "accent-700": "rgb(67 56 202)", + "accent-800": "rgb(55 48 163)", + "accent-900": "rgb(49 46 129)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(251 240 206)", + "warning-200": "rgb(250 236 193)", + "warning-300": "rgb(247 225 156)", + "warning-400": "rgb(240 202 82)", + "warning-500": "rgb(234 179 8)", + "warning-600": "rgb(211 161 7)", + "warning-700": "rgb(176 134 6)", + "warning-800": "rgb(140 107 5)", + "warning-900": "rgb(115 88 4)", + "danger-100": "rgb(246 209 228)", + "danger-200": "rgb(244 198 221)", + "danger-300": "rgb(238 163 200)", + "danger-400": "rgb(225 94 159)", + "danger-500": "rgb(212 25 118)", + "danger-600": "rgb(191 23 106)", + "danger-700": "rgb(159 19 89)", + "danger-800": "rgb(127 15 71)", + "danger-900": "rgb(104 12 58)", + "surface-100": "rgb(55 65 81)", + "surface-200": "rgb(31 41 55)", + "surface-300": "rgb(17 24 39)", + "surface-400": "rgb(156 163 175)", + "surface-500": "rgb(107 114 128)", + "surface-600": "rgb(75 85 99)", + "surface-700": "rgb(55 65 81)", + "surface-800": "rgb(31 41 55)", + "surface-900": "rgb(17 24 39)", + "color-scheme": "dark" + }, + "modern": { + "primary-content": "rgb(255 255 255)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(251 218 235)", + "primary-200": "rgb(250 209 230)", + "primary-300": "rgb(247 182 214)", + "primary-400": "rgb(242 127 184)", + "primary-500": "rgb(236 72 153)", + "primary-600": "rgb(212 65 138)", + "primary-700": "rgb(177 54 115)", + "primary-800": "rgb(142 43 92)", + "primary-900": "rgb(116 35 75)", + "secondary-100": "rgb(205 240 246)", + "secondary-200": "rgb(193 237 244)", + "secondary-300": "rgb(155 226 238)", + "secondary-400": "rgb(81 204 225)", + "secondary-500": "rgb(6 182 212)", + "secondary-600": "rgb(5 164 191)", + "secondary-700": "rgb(5 137 159)", + "secondary-800": "rgb(4 109 127)", + "secondary-900": "rgb(3 89 104)", + "accent-100": "rgb(208 241 237)", + "accent-200": "rgb(196 237 233)", + "accent-300": "rgb(161 227 219)", + "accent-400": "rgb(91 205 193)", + "accent-500": "rgb(20 184 166)", + "accent-600": "rgb(18 166 149)", + "accent-700": "rgb(15 138 125)", + "accent-800": "rgb(12 110 100)", + "accent-900": "rgb(10 90 81)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(251 240 206)", + "warning-200": "rgb(250 236 193)", + "warning-300": "rgb(247 225 156)", + "warning-400": "rgb(240 202 82)", + "warning-500": "rgb(234 179 8)", + "warning-600": "rgb(211 161 7)", + "warning-700": "rgb(176 134 6)", + "warning-800": "rgb(140 107 5)", + "warning-900": "rgb(115 88 4)", + "danger-100": "rgb(252 218 218)", + "danger-200": "rgb(251 208 208)", + "danger-300": "rgb(249 180 180)", + "danger-400": "rgb(244 124 124)", + "danger-500": "rgb(239 68 68)", + "danger-600": "rgb(215 61 61)", + "danger-700": "rgb(179 51 51)", + "danger-800": "rgb(143 41 41)", + "danger-900": "rgb(117 33 33)", + "surface-100": "rgb(232 232 253)", + "surface-200": "rgb(224 224 252)", + "surface-300": "rgb(216 217 252)", + "surface-400": "rgb(146 148 245)", + "surface-500": "rgb(99 102 241)", + "surface-600": "rgb(89 92 217)", + "surface-700": "rgb(74 77 181)", + "surface-800": "rgb(59 61 145)", + "surface-900": "rgb(49 50 118)", + "color-scheme": "light" + }, + "modern-dark": { + "primary-content": "rgb(255 255 255)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(251 218 235)", + "primary-200": "rgb(250 209 230)", + "primary-300": "rgb(247 182 214)", + "primary-400": "rgb(242 127 184)", + "primary-500": "rgb(236 72 153)", + "primary-600": "rgb(212 65 138)", + "primary-700": "rgb(177 54 115)", + "primary-800": "rgb(142 43 92)", + "primary-900": "rgb(116 35 75)", + "secondary-100": "rgb(205 240 246)", + "secondary-200": "rgb(193 237 244)", + "secondary-300": "rgb(155 226 238)", + "secondary-400": "rgb(81 204 225)", + "secondary-500": "rgb(6 182 212)", + "secondary-600": "rgb(5 164 191)", + "secondary-700": "rgb(5 137 159)", + "secondary-800": "rgb(4 109 127)", + "secondary-900": "rgb(3 89 104)", + "accent-100": "rgb(208 241 237)", + "accent-200": "rgb(196 237 233)", + "accent-300": "rgb(161 227 219)", + "accent-400": "rgb(91 205 193)", + "accent-500": "rgb(20 184 166)", + "accent-600": "rgb(18 166 149)", + "accent-700": "rgb(15 138 125)", + "accent-800": "rgb(12 110 100)", + "accent-900": "rgb(10 90 81)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(251 240 206)", + "warning-200": "rgb(250 236 193)", + "warning-300": "rgb(247 225 156)", + "warning-400": "rgb(240 202 82)", + "warning-500": "rgb(234 179 8)", + "warning-600": "rgb(211 161 7)", + "warning-700": "rgb(176 134 6)", + "warning-800": "rgb(140 107 5)", + "warning-900": "rgb(115 88 4)", + "danger-100": "rgb(252 218 218)", + "danger-200": "rgb(251 208 208)", + "danger-300": "rgb(249 180 180)", + "danger-400": "rgb(244 124 124)", + "danger-500": "rgb(239 68 68)", + "danger-600": "rgb(215 61 61)", + "danger-700": "rgb(179 51 51)", + "danger-800": "rgb(143 41 41)", + "danger-900": "rgb(117 33 33)", + "surface-100": "rgb(74 77 181)", + "surface-200": "rgb(59 61 145)", + "surface-300": "rgb(49 50 118)", + "surface-400": "rgb(146 148 245)", + "surface-500": "rgb(99 102 241)", + "surface-600": "rgb(89 92 217)", + "surface-700": "rgb(74 77 181)", + "surface-800": "rgb(59 61 145)", + "surface-900": "rgb(49 50 118)", + "color-scheme": "dark" + }, + "rocket": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(205 240 246)", + "primary-200": "rgb(193 237 244)", + "primary-300": "rgb(155 226 238)", + "primary-400": "rgb(81 204 225)", + "primary-500": "rgb(6 182 212)", + "primary-600": "rgb(5 164 191)", + "primary-700": "rgb(5 137 159)", + "primary-800": "rgb(4 109 127)", + "primary-900": "rgb(3 89 104)", + "secondary-100": "rgb(216 230 253)", + "secondary-200": "rgb(206 224 253)", + "secondary-300": "rgb(177 205 251)", + "secondary-400": "rgb(118 168 249)", + "secondary-500": "rgb(59 130 246)", + "secondary-600": "rgb(53 117 221)", + "secondary-700": "rgb(44 98 185)", + "secondary-800": "rgb(35 78 148)", + "secondary-900": "rgb(29 64 121)", + "accent-100": "rgb(238 221 253)", + "accent-200": "rgb(233 213 253)", + "accent-300": "rgb(220 187 252)", + "accent-400": "rgb(194 136 249)", + "accent-500": "rgb(168 85 247)", + "accent-600": "rgb(151 77 222)", + "accent-700": "rgb(126 64 185)", + "accent-800": "rgb(101 51 148)", + "accent-900": "rgb(82 42 121)", + "success-100": "rgb(219 245 208)", + "success-200": "rgb(210 242 197)", + "success-300": "rgb(183 234 161)", + "success-400": "rgb(130 219 91)", + "success-500": "rgb(76 203 21)", + "success-600": "rgb(68 183 19)", + "success-700": "rgb(57 152 16)", + "success-800": "rgb(46 122 13)", + "success-900": "rgb(37 99 10)", + "warning-100": "rgb(253 243 212)", + "warning-200": "rgb(252 240 202)", + "warning-300": "rgb(251 230 170)", + "warning-400": "rgb(247 212 106)", + "warning-500": "rgb(244 193 42)", + "warning-600": "rgb(220 174 38)", + "warning-700": "rgb(183 145 32)", + "warning-800": "rgb(146 116 25)", + "warning-900": "rgb(120 95 21)", + "danger-100": "rgb(240 213 221)", + "danger-200": "rgb(237 202 213)", + "danger-300": "rgb(225 171 187)", + "danger-400": "rgb(203 107 136)", + "danger-500": "rgb(181 44 85)", + "danger-600": "rgb(163 40 77)", + "danger-700": "rgb(136 33 64)", + "danger-800": "rgb(109 26 51)", + "danger-900": "rgb(89 22 42)", + "surface-100": "rgb(232 234 238)", + "surface-200": "rgb(224 227 232)", + "surface-300": "rgb(216 220 226)", + "surface-400": "rgb(147 158 174)", + "surface-500": "rgb(100 116 139)", + "surface-600": "rgb(90 104 125)", + "surface-700": "rgb(75 87 104)", + "surface-800": "rgb(60 70 83)", + "surface-900": "rgb(49 57 68)", + "color-scheme": "light" + }, + "rocket-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(205 240 246)", + "primary-200": "rgb(193 237 244)", + "primary-300": "rgb(155 226 238)", + "primary-400": "rgb(81 204 225)", + "primary-500": "rgb(6 182 212)", + "primary-600": "rgb(5 164 191)", + "primary-700": "rgb(5 137 159)", + "primary-800": "rgb(4 109 127)", + "primary-900": "rgb(3 89 104)", + "secondary-100": "rgb(216 230 253)", + "secondary-200": "rgb(206 224 253)", + "secondary-300": "rgb(177 205 251)", + "secondary-400": "rgb(118 168 249)", + "secondary-500": "rgb(59 130 246)", + "secondary-600": "rgb(53 117 221)", + "secondary-700": "rgb(44 98 185)", + "secondary-800": "rgb(35 78 148)", + "secondary-900": "rgb(29 64 121)", + "accent-100": "rgb(238 221 253)", + "accent-200": "rgb(233 213 253)", + "accent-300": "rgb(220 187 252)", + "accent-400": "rgb(194 136 249)", + "accent-500": "rgb(168 85 247)", + "accent-600": "rgb(151 77 222)", + "accent-700": "rgb(126 64 185)", + "accent-800": "rgb(101 51 148)", + "accent-900": "rgb(82 42 121)", + "success-100": "rgb(219 245 208)", + "success-200": "rgb(210 242 197)", + "success-300": "rgb(183 234 161)", + "success-400": "rgb(130 219 91)", + "success-500": "rgb(76 203 21)", + "success-600": "rgb(68 183 19)", + "success-700": "rgb(57 152 16)", + "success-800": "rgb(46 122 13)", + "success-900": "rgb(37 99 10)", + "warning-100": "rgb(253 243 212)", + "warning-200": "rgb(252 240 202)", + "warning-300": "rgb(251 230 170)", + "warning-400": "rgb(247 212 106)", + "warning-500": "rgb(244 193 42)", + "warning-600": "rgb(220 174 38)", + "warning-700": "rgb(183 145 32)", + "warning-800": "rgb(146 116 25)", + "warning-900": "rgb(120 95 21)", + "danger-100": "rgb(240 213 221)", + "danger-200": "rgb(237 202 213)", + "danger-300": "rgb(225 171 187)", + "danger-400": "rgb(203 107 136)", + "danger-500": "rgb(181 44 85)", + "danger-600": "rgb(163 40 77)", + "danger-700": "rgb(136 33 64)", + "danger-800": "rgb(109 26 51)", + "danger-900": "rgb(89 22 42)", + "surface-100": "rgb(75 87 104)", + "surface-200": "rgb(60 70 83)", + "surface-300": "rgb(49 57 68)", + "surface-400": "rgb(147 158 174)", + "surface-500": "rgb(100 116 139)", + "surface-600": "rgb(90 104 125)", + "surface-700": "rgb(75 87 104)", + "surface-800": "rgb(60 70 83)", + "surface-900": "rgb(49 57 68)", + "color-scheme": "dark" + }, + "seafoam": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(231 246 245)", + "primary-200": "rgb(225 243 242)", + "primary-300": "rgb(207 236 234)", + "primary-400": "rgb(170 222 219)", + "primary-500": "rgb(134 208 203)", + "primary-600": "rgb(121 187 183)", + "primary-700": "rgb(101 156 152)", + "primary-800": "rgb(80 125 122)", + "primary-900": "rgb(66 102 99)", + "secondary-100": "rgb(211 214 221)", + "secondary-200": "rgb(200 204 213)", + "secondary-300": "rgb(166 173 187)", + "secondary-400": "rgb(100 112 136)", + "secondary-500": "rgb(33 51 85)", + "secondary-600": "rgb(30 46 77)", + "secondary-700": "rgb(25 38 64)", + "secondary-800": "rgb(20 31 51)", + "secondary-900": "rgb(16 25 42)", + "accent-100": "rgb(255 216 204)", + "accent-200": "rgb(255 207 191)", + "accent-300": "rgb(255 177 153)", + "accent-400": "rgb(255 119 77)", + "accent-500": "rgb(255 61 0)", + "accent-600": "rgb(230 55 0)", + "accent-700": "rgb(191 46 0)", + "accent-800": "rgb(153 37 0)", + "accent-900": "rgb(125 30 0)", + "success-100": "rgb(205 250 236)", + "success-200": "rgb(193 249 232)", + "success-300": "rgb(155 245 218)", + "success-400": "rgb(81 237 190)", + "success-500": "rgb(6 229 162)", + "success-600": "rgb(5 206 146)", + "success-700": "rgb(5 172 122)", + "success-800": "rgb(4 137 97)", + "success-900": "rgb(3 112 79)", + "warning-100": "rgb(251 250 221)", + "warning-200": "rgb(250 249 213)", + "warning-300": "rgb(247 245 188)", + "warning-400": "rgb(240 237 137)", + "warning-500": "rgb(234 229 87)", + "warning-600": "rgb(211 206 78)", + "warning-700": "rgb(176 172 65)", + "warning-800": "rgb(140 137 52)", + "warning-900": "rgb(115 112 43)", + "danger-100": "rgb(246 218 218)", + "danger-200": "rgb(244 209 209)", + "danger-300": "rgb(237 181 181)", + "danger-400": "rgb(224 126 126)", + "danger-500": "rgb(210 70 70)", + "danger-600": "rgb(189 63 63)", + "danger-700": "rgb(158 53 53)", + "danger-800": "rgb(126 42 42)", + "danger-900": "rgb(103 34 34)", + "surface-100": "rgb(222 248 249)", + "surface-200": "rgb(211 246 246)", + "surface-300": "rgb(201 244 244)", + "surface-400": "rgb(102 223 225)", + "surface-500": "rgb(37 209 212)", + "surface-600": "rgb(33 188 191)", + "surface-700": "rgb(28 157 159)", + "surface-800": "rgb(22 125 127)", + "surface-900": "rgb(18 102 104)", + "color-scheme": "light" + }, + "seafoam-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(231 246 245)", + "primary-200": "rgb(225 243 242)", + "primary-300": "rgb(207 236 234)", + "primary-400": "rgb(170 222 219)", + "primary-500": "rgb(134 208 203)", + "primary-600": "rgb(121 187 183)", + "primary-700": "rgb(101 156 152)", + "primary-800": "rgb(80 125 122)", + "primary-900": "rgb(66 102 99)", + "secondary-100": "rgb(211 214 221)", + "secondary-200": "rgb(200 204 213)", + "secondary-300": "rgb(166 173 187)", + "secondary-400": "rgb(100 112 136)", + "secondary-500": "rgb(33 51 85)", + "secondary-600": "rgb(30 46 77)", + "secondary-700": "rgb(25 38 64)", + "secondary-800": "rgb(20 31 51)", + "secondary-900": "rgb(16 25 42)", + "accent-100": "rgb(255 216 204)", + "accent-200": "rgb(255 207 191)", + "accent-300": "rgb(255 177 153)", + "accent-400": "rgb(255 119 77)", + "accent-500": "rgb(255 61 0)", + "accent-600": "rgb(230 55 0)", + "accent-700": "rgb(191 46 0)", + "accent-800": "rgb(153 37 0)", + "accent-900": "rgb(125 30 0)", + "success-100": "rgb(205 250 236)", + "success-200": "rgb(193 249 232)", + "success-300": "rgb(155 245 218)", + "success-400": "rgb(81 237 190)", + "success-500": "rgb(6 229 162)", + "success-600": "rgb(5 206 146)", + "success-700": "rgb(5 172 122)", + "success-800": "rgb(4 137 97)", + "success-900": "rgb(3 112 79)", + "warning-100": "rgb(251 250 221)", + "warning-200": "rgb(250 249 213)", + "warning-300": "rgb(247 245 188)", + "warning-400": "rgb(240 237 137)", + "warning-500": "rgb(234 229 87)", + "warning-600": "rgb(211 206 78)", + "warning-700": "rgb(176 172 65)", + "warning-800": "rgb(140 137 52)", + "warning-900": "rgb(115 112 43)", + "danger-100": "rgb(246 218 218)", + "danger-200": "rgb(244 209 209)", + "danger-300": "rgb(237 181 181)", + "danger-400": "rgb(224 126 126)", + "danger-500": "rgb(210 70 70)", + "danger-600": "rgb(189 63 63)", + "danger-700": "rgb(158 53 53)", + "danger-800": "rgb(126 42 42)", + "danger-900": "rgb(103 34 34)", + "surface-100": "rgb(28 157 159)", + "surface-200": "rgb(22 125 127)", + "surface-300": "rgb(18 102 104)", + "surface-400": "rgb(102 223 225)", + "surface-500": "rgb(37 209 212)", + "surface-600": "rgb(33 188 191)", + "surface-700": "rgb(28 157 159)", + "surface-800": "rgb(22 125 127)", + "surface-900": "rgb(18 102 104)", + "color-scheme": "dark" + }, + "vintage": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(0 0 0)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(251 231 209)", + "primary-200": "rgb(250 225 198)", + "primary-300": "rgb(247 207 163)", + "primary-400": "rgb(240 170 95)", + "primary-500": "rgb(234 134 26)", + "primary-600": "rgb(211 121 23)", + "primary-700": "rgb(176 101 20)", + "primary-800": "rgb(140 80 16)", + "primary-900": "rgb(115 66 13)", + "secondary-100": "rgb(234 245 237)", + "secondary-200": "rgb(229 243 233)", + "secondary-300": "rgb(213 235 219)", + "secondary-400": "rgb(182 221 192)", + "secondary-500": "rgb(151 206 165)", + "secondary-600": "rgb(136 185 149)", + "secondary-700": "rgb(113 155 124)", + "secondary-800": "rgb(91 124 99)", + "secondary-900": "rgb(74 101 81)", + "accent-100": "rgb(205 240 246)", + "accent-200": "rgb(193 237 244)", + "accent-300": "rgb(155 226 238)", + "accent-400": "rgb(81 204 225)", + "accent-500": "rgb(6 182 212)", + "accent-600": "rgb(5 164 191)", + "accent-700": "rgb(5 137 159)", + "accent-800": "rgb(4 109 127)", + "accent-900": "rgb(3 89 104)", + "success-100": "rgb(230 245 223)", + "success-200": "rgb(224 242 215)", + "success-300": "rgb(206 234 190)", + "success-400": "rgb(169 219 142)", + "success-500": "rgb(132 203 93)", + "success-600": "rgb(119 183 84)", + "success-700": "rgb(99 152 70)", + "success-800": "rgb(79 122 56)", + "success-900": "rgb(65 99 46)", + "warning-100": "rgb(252 238 211)", + "warning-200": "rgb(252 234 200)", + "warning-300": "rgb(250 222 167)", + "warning-400": "rgb(246 197 101)", + "warning-500": "rgb(242 172 35)", + "warning-600": "rgb(218 155 32)", + "warning-700": "rgb(182 129 26)", + "warning-800": "rgb(145 103 21)", + "warning-900": "rgb(119 84 17)", + "danger-100": "rgb(247 229 228)", + "danger-200": "rgb(245 223 221)", + "danger-300": "rgb(238 203 201)", + "danger-400": "rgb(226 165 161)", + "danger-500": "rgb(213 126 120)", + "danger-600": "rgb(192 113 108)", + "danger-700": "rgb(160 95 90)", + "danger-800": "rgb(128 76 72)", + "danger-900": "rgb(104 62 59)", + "surface-100": "rgb(226 225 224)", + "surface-200": "rgb(217 215 214)", + "surface-300": "rgb(207 205 204)", + "surface-400": "rgb(121 115 111)", + "surface-500": "rgb(63 55 49)", + "surface-600": "rgb(57 50 44)", + "surface-700": "rgb(47 41 37)", + "surface-800": "rgb(38 33 29)", + "surface-900": "rgb(31 27 24)", + "color-scheme": "light" + }, + "vintage-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(0 0 0)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(251 231 209)", + "primary-200": "rgb(250 225 198)", + "primary-300": "rgb(247 207 163)", + "primary-400": "rgb(240 170 95)", + "primary-500": "rgb(234 134 26)", + "primary-600": "rgb(211 121 23)", + "primary-700": "rgb(176 101 20)", + "primary-800": "rgb(140 80 16)", + "primary-900": "rgb(115 66 13)", + "secondary-100": "rgb(234 245 237)", + "secondary-200": "rgb(229 243 233)", + "secondary-300": "rgb(213 235 219)", + "secondary-400": "rgb(182 221 192)", + "secondary-500": "rgb(151 206 165)", + "secondary-600": "rgb(136 185 149)", + "secondary-700": "rgb(113 155 124)", + "secondary-800": "rgb(91 124 99)", + "secondary-900": "rgb(74 101 81)", + "accent-100": "rgb(205 240 246)", + "accent-200": "rgb(193 237 244)", + "accent-300": "rgb(155 226 238)", + "accent-400": "rgb(81 204 225)", + "accent-500": "rgb(6 182 212)", + "accent-600": "rgb(5 164 191)", + "accent-700": "rgb(5 137 159)", + "accent-800": "rgb(4 109 127)", + "accent-900": "rgb(3 89 104)", + "success-100": "rgb(230 245 223)", + "success-200": "rgb(224 242 215)", + "success-300": "rgb(206 234 190)", + "success-400": "rgb(169 219 142)", + "success-500": "rgb(132 203 93)", + "success-600": "rgb(119 183 84)", + "success-700": "rgb(99 152 70)", + "success-800": "rgb(79 122 56)", + "success-900": "rgb(65 99 46)", + "warning-100": "rgb(252 238 211)", + "warning-200": "rgb(252 234 200)", + "warning-300": "rgb(250 222 167)", + "warning-400": "rgb(246 197 101)", + "warning-500": "rgb(242 172 35)", + "warning-600": "rgb(218 155 32)", + "warning-700": "rgb(182 129 26)", + "warning-800": "rgb(145 103 21)", + "warning-900": "rgb(119 84 17)", + "danger-100": "rgb(247 229 228)", + "danger-200": "rgb(245 223 221)", + "danger-300": "rgb(238 203 201)", + "danger-400": "rgb(226 165 161)", + "danger-500": "rgb(213 126 120)", + "danger-600": "rgb(192 113 108)", + "danger-700": "rgb(160 95 90)", + "danger-800": "rgb(128 76 72)", + "danger-900": "rgb(104 62 59)", + "surface-100": "rgb(47 41 37)", + "surface-200": "rgb(38 33 29)", + "surface-300": "rgb(31 27 24)", + "surface-400": "rgb(121 115 111)", + "surface-500": "rgb(63 55 49)", + "surface-600": "rgb(57 50 44)", + "surface-700": "rgb(47 41 37)", + "surface-800": "rgb(38 33 29)", + "surface-900": "rgb(31 27 24)", + "color-scheme": "dark" + }, + "sahara": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(251 238 215)", + "primary-200": "rgb(250 234 205)", + "primary-300": "rgb(247 221 175)", + "primary-400": "rgb(242 196 114)", + "primary-500": "rgb(236 170 54)", + "primary-600": "rgb(212 153 49)", + "primary-700": "rgb(177 128 41)", + "primary-800": "rgb(142 102 32)", + "primary-900": "rgb(116 83 26)", + "secondary-100": "rgb(216 245 241)", + "secondary-200": "rgb(206 242 238)", + "secondary-300": "rgb(176 234 227)", + "secondary-400": "rgb(117 219 207)", + "secondary-500": "rgb(58 203 186)", + "secondary-600": "rgb(52 183 167)", + "secondary-700": "rgb(44 152 140)", + "secondary-800": "rgb(35 122 112)", + "secondary-900": "rgb(28 99 91)", + "accent-100": "rgb(241 249 231)", + "accent-200": "rgb(238 247 225)", + "accent-300": "rgb(228 242 207)", + "accent-400": "rgb(207 233 170)", + "accent-500": "rgb(187 223 134)", + "accent-600": "rgb(168 201 121)", + "accent-700": "rgb(140 167 101)", + "accent-800": "rgb(112 134 80)", + "accent-900": "rgb(92 109 66)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(250 243 221)", + "warning-200": "rgb(249 240 213)", + "warning-300": "rgb(245 230 188)", + "warning-400": "rgb(237 212 137)", + "warning-500": "rgb(229 193 87)", + "warning-600": "rgb(206 174 78)", + "warning-700": "rgb(172 145 65)", + "warning-800": "rgb(137 116 52)", + "warning-900": "rgb(112 95 43)", + "danger-100": "rgb(248 222 235)", + "danger-200": "rgb(246 214 230)", + "danger-300": "rgb(241 190 215)", + "danger-400": "rgb(230 141 186)", + "danger-500": "rgb(219 92 156)", + "danger-600": "rgb(197 83 140)", + "danger-700": "rgb(164 69 117)", + "danger-800": "rgb(131 55 94)", + "danger-900": "rgb(107 45 76)", + "surface-100": "rgb(249 228 232)", + "surface-200": "rgb(248 220 224)", + "surface-300": "rgb(246 211 217)", + "surface-400": "rgb(229 131 147)", + "surface-500": "rgb(218 78 101)", + "surface-600": "rgb(196 70 91)", + "surface-700": "rgb(164 59 76)", + "surface-800": "rgb(131 47 61)", + "surface-900": "rgb(107 38 49)", + "color-scheme": "light" + }, + "sahara-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(0 0 0)", + "accent-content": "rgb(0 0 0)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(251 238 215)", + "primary-200": "rgb(250 234 205)", + "primary-300": "rgb(247 221 175)", + "primary-400": "rgb(242 196 114)", + "primary-500": "rgb(236 170 54)", + "primary-600": "rgb(212 153 49)", + "primary-700": "rgb(177 128 41)", + "primary-800": "rgb(142 102 32)", + "primary-900": "rgb(116 83 26)", + "secondary-100": "rgb(216 245 241)", + "secondary-200": "rgb(206 242 238)", + "secondary-300": "rgb(176 234 227)", + "secondary-400": "rgb(117 219 207)", + "secondary-500": "rgb(58 203 186)", + "secondary-600": "rgb(52 183 167)", + "secondary-700": "rgb(44 152 140)", + "secondary-800": "rgb(35 122 112)", + "secondary-900": "rgb(28 99 91)", + "accent-100": "rgb(241 249 231)", + "accent-200": "rgb(238 247 225)", + "accent-300": "rgb(228 242 207)", + "accent-400": "rgb(207 233 170)", + "accent-500": "rgb(187 223 134)", + "accent-600": "rgb(168 201 121)", + "accent-700": "rgb(140 167 101)", + "accent-800": "rgb(112 134 80)", + "accent-900": "rgb(92 109 66)", + "success-100": "rgb(230 245 208)", + "success-200": "rgb(224 242 197)", + "success-300": "rgb(206 235 162)", + "success-400": "rgb(169 219 92)", + "success-500": "rgb(132 204 22)", + "success-600": "rgb(119 184 20)", + "success-700": "rgb(99 153 17)", + "success-800": "rgb(79 122 13)", + "success-900": "rgb(65 100 11)", + "warning-100": "rgb(250 243 221)", + "warning-200": "rgb(249 240 213)", + "warning-300": "rgb(245 230 188)", + "warning-400": "rgb(237 212 137)", + "warning-500": "rgb(229 193 87)", + "warning-600": "rgb(206 174 78)", + "warning-700": "rgb(172 145 65)", + "warning-800": "rgb(137 116 52)", + "warning-900": "rgb(112 95 43)", + "danger-100": "rgb(248 222 235)", + "danger-200": "rgb(246 214 230)", + "danger-300": "rgb(241 190 215)", + "danger-400": "rgb(230 141 186)", + "danger-500": "rgb(219 92 156)", + "danger-600": "rgb(197 83 140)", + "danger-700": "rgb(164 69 117)", + "danger-800": "rgb(131 55 94)", + "danger-900": "rgb(107 45 76)", + "surface-100": "rgb(164 59 76)", + "surface-200": "rgb(131 47 61)", + "surface-300": "rgb(107 38 49)", + "surface-400": "rgb(229 131 147)", + "surface-500": "rgb(218 78 101)", + "surface-600": "rgb(196 70 91)", + "surface-700": "rgb(164 59 76)", + "surface-800": "rgb(131 47 61)", + "surface-900": "rgb(107 38 49)", + "color-scheme": "dark" + }, + "hamlindigo": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(255 255 255)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(238 242 252)", + "primary-200": "rgb(233 239 252)", + "primary-300": "rgb(220 229 249)", + "primary-400": "rgb(194 210 245)", + "primary-500": "rgb(168 190 241)", + "primary-600": "rgb(151 171 217)", + "primary-700": "rgb(126 143 181)", + "primary-800": "rgb(101 114 145)", + "primary-900": "rgb(82 93 118)", + "secondary-100": "rgb(237 232 222)", + "secondary-200": "rgb(232 227 214)", + "secondary-300": "rgb(219 210 189)", + "secondary-400": "rgb(191 176 140)", + "secondary-500": "rgb(164 142 91)", + "secondary-600": "rgb(148 128 82)", + "secondary-700": "rgb(123 107 68)", + "secondary-800": "rgb(98 85 55)", + "secondary-900": "rgb(80 70 45)", + "accent-100": "rgb(223 234 237)", + "accent-200": "rgb(216 229 232)", + "accent-300": "rgb(192 213 218)", + "accent-400": "rgb(144 182 191)", + "accent-500": "rgb(97 151 163)", + "accent-600": "rgb(87 136 147)", + "accent-700": "rgb(73 113 122)", + "accent-800": "rgb(58 91 98)", + "accent-900": "rgb(48 74 80)", + "success-100": "rgb(218 234 229)", + "success-200": "rgb(209 228 223)", + "success-300": "rgb(181 212 203)", + "success-400": "rgb(126 180 164)", + "success-500": "rgb(71 148 125)", + "success-600": "rgb(64 133 113)", + "success-700": "rgb(53 111 94)", + "success-800": "rgb(43 89 75)", + "success-900": "rgb(35 73 61)", + "warning-100": "rgb(248 238 216)", + "warning-200": "rgb(246 234 207)", + "warning-300": "rgb(240 221 178)", + "warning-400": "rgb(229 195 120)", + "warning-500": "rgb(218 169 62)", + "warning-600": "rgb(196 152 56)", + "warning-700": "rgb(164 127 47)", + "warning-800": "rgb(131 101 37)", + "warning-900": "rgb(107 83 30)", + "danger-100": "rgb(236 223 227)", + "danger-200": "rgb(232 216 221)", + "danger-300": "rgb(218 192 200)", + "danger-400": "rgb(190 144 158)", + "danger-500": "rgb(162 97 117)", + "danger-600": "rgb(146 87 105)", + "danger-700": "rgb(122 73 88)", + "danger-800": "rgb(97 58 70)", + "danger-900": "rgb(79 48 57)", + "surface-100": "rgb(232 234 241)", + "surface-200": "rgb(224 228 237)", + "surface-300": "rgb(216 221 232)", + "surface-400": "rgb(146 159 191)", + "surface-500": "rgb(99 118 163)", + "surface-600": "rgb(89 106 147)", + "surface-700": "rgb(74 89 122)", + "surface-800": "rgb(59 71 98)", + "surface-900": "rgb(49 58 80)", + "color-scheme": "light" + }, + "hamlindigo-dark": { + "primary-content": "rgb(0 0 0)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(255 255 255)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(238 242 252)", + "primary-200": "rgb(233 239 252)", + "primary-300": "rgb(220 229 249)", + "primary-400": "rgb(194 210 245)", + "primary-500": "rgb(168 190 241)", + "primary-600": "rgb(151 171 217)", + "primary-700": "rgb(126 143 181)", + "primary-800": "rgb(101 114 145)", + "primary-900": "rgb(82 93 118)", + "secondary-100": "rgb(237 232 222)", + "secondary-200": "rgb(232 227 214)", + "secondary-300": "rgb(219 210 189)", + "secondary-400": "rgb(191 176 140)", + "secondary-500": "rgb(164 142 91)", + "secondary-600": "rgb(148 128 82)", + "secondary-700": "rgb(123 107 68)", + "secondary-800": "rgb(98 85 55)", + "secondary-900": "rgb(80 70 45)", + "accent-100": "rgb(223 234 237)", + "accent-200": "rgb(216 229 232)", + "accent-300": "rgb(192 213 218)", + "accent-400": "rgb(144 182 191)", + "accent-500": "rgb(97 151 163)", + "accent-600": "rgb(87 136 147)", + "accent-700": "rgb(73 113 122)", + "accent-800": "rgb(58 91 98)", + "accent-900": "rgb(48 74 80)", + "success-100": "rgb(218 234 229)", + "success-200": "rgb(209 228 223)", + "success-300": "rgb(181 212 203)", + "success-400": "rgb(126 180 164)", + "success-500": "rgb(71 148 125)", + "success-600": "rgb(64 133 113)", + "success-700": "rgb(53 111 94)", + "success-800": "rgb(43 89 75)", + "success-900": "rgb(35 73 61)", + "warning-100": "rgb(248 238 216)", + "warning-200": "rgb(246 234 207)", + "warning-300": "rgb(240 221 178)", + "warning-400": "rgb(229 195 120)", + "warning-500": "rgb(218 169 62)", + "warning-600": "rgb(196 152 56)", + "warning-700": "rgb(164 127 47)", + "warning-800": "rgb(131 101 37)", + "warning-900": "rgb(107 83 30)", + "danger-100": "rgb(236 223 227)", + "danger-200": "rgb(232 216 221)", + "danger-300": "rgb(218 192 200)", + "danger-400": "rgb(190 144 158)", + "danger-500": "rgb(162 97 117)", + "danger-600": "rgb(146 87 105)", + "danger-700": "rgb(122 73 88)", + "danger-800": "rgb(97 58 70)", + "danger-900": "rgb(79 48 57)", + "surface-100": "rgb(74 89 122)", + "surface-200": "rgb(59 71 98)", + "surface-300": "rgb(49 58 80)", + "surface-400": "rgb(146 159 191)", + "surface-500": "rgb(99 118 163)", + "surface-600": "rgb(89 106 147)", + "surface-700": "rgb(74 89 122)", + "surface-800": "rgb(59 71 98)", + "surface-900": "rgb(49 58 80)", + "color-scheme": "dark" + }, + "gold-nouveau": { + "primary-content": "rgb(255 255 255)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(0 0 0)", + "primary-100": "rgb(242 238 247)", + "primary-200": "rgb(229 220 239)", + "primary-300": "rgb(209 192 226)", + "primary-400": "rgb(162 129 197)", + "primary-500": "rgb(116 74 161)", + "primary-600": "rgb(83 53 115)", + "primary-700": "rgb(60 39 84)", + "primary-800": "rgb(35 22 49)", + "primary-900": "rgb(18 11 24)", + "secondary-100": "rgb(205 227 250)", + "secondary-200": "rgb(193 220 249)", + "secondary-300": "rgb(155 199 245)", + "secondary-400": "rgb(81 156 237)", + "secondary-500": "rgb(6 114 229)", + "secondary-600": "rgb(5 103 206)", + "secondary-700": "rgb(5 86 172)", + "secondary-800": "rgb(4 68 137)", + "secondary-900": "rgb(3 56 112)", + "accent-100": "rgb(229 228 248)", + "accent-200": "rgb(223 221 247)", + "accent-300": "rgb(204 201 241)", + "accent-400": "rgb(165 161 231)", + "accent-500": "rgb(127 120 221)", + "accent-600": "rgb(114 108 199)", + "accent-700": "rgb(95 90 166)", + "accent-800": "rgb(76 72 133)", + "accent-900": "rgb(62 59 108)", + "success-100": "rgb(227 243 231)", + "success-200": "rgb(220 241 225)", + "success-300": "rgb(199 232 206)", + "success-400": "rgb(156 214 170)", + "success-500": "rgb(114 197 133)", + "success-600": "rgb(103 177 120)", + "success-700": "rgb(86 148 100)", + "success-800": "rgb(68 118 80)", + "success-900": "rgb(56 97 65)", + "warning-100": "rgb(250 229 206)", + "warning-200": "rgb(249 223 193)", + "warning-300": "rgb(245 204 156)", + "warning-400": "rgb(238 165 82)", + "warning-500": "rgb(231 127 8)", + "warning-600": "rgb(208 114 7)", + "warning-700": "rgb(173 95 6)", + "warning-800": "rgb(139 76 5)", + "warning-900": "rgb(113 62 4)", + "danger-100": "rgb(233 207 211)", + "danger-200": "rgb(227 195 200)", + "danger-300": "rgb(210 159 167)", + "danger-400": "rgb(177 87 100)", + "danger-500": "rgb(143 15 34)", + "danger-600": "rgb(129 14 31)", + "danger-700": "rgb(107 11 26)", + "danger-800": "rgb(86 9 20)", + "danger-900": "rgb(70 7 17)", + "surface-100": "rgb(250 248 252)", + "surface-200": "rgb(242 238 247)", + "surface-300": "rgb(229 220 239)", + "surface-400": "rgb(162 129 197)", + "surface-500": "rgb(116 74 161)", + "surface-600": "rgb(83 53 115)", + "surface-700": "rgb(60 39 84)", + "surface-800": "rgb(35 22 49)", + "surface-900": "rgb(18 11 24)", + "color-scheme": "light" + }, + "gold-nouveau-dark": { + "primary-content": "rgb(255 255 255)", + "secondary-content": "rgb(255 255 255)", + "accent-content": "rgb(255 255 255)", + "success-content": "rgb(0 0 0)", + "warning-content": "rgb(0 0 0)", + "danger-content": "rgb(255 255 255)", + "surface-content": "rgb(255 255 255)", + "primary-100": "rgb(242 238 247)", + "primary-200": "rgb(229 220 239)", + "primary-300": "rgb(209 192 226)", + "primary-400": "rgb(162 129 197)", + "primary-500": "rgb(116 74 161)", + "primary-600": "rgb(83 53 115)", + "primary-700": "rgb(60 39 84)", + "primary-800": "rgb(35 22 49)", + "primary-900": "rgb(18 11 24)", + "secondary-100": "rgb(205 227 250)", + "secondary-200": "rgb(193 220 249)", + "secondary-300": "rgb(155 199 245)", + "secondary-400": "rgb(81 156 237)", + "secondary-500": "rgb(6 114 229)", + "secondary-600": "rgb(5 103 206)", + "secondary-700": "rgb(5 86 172)", + "secondary-800": "rgb(4 68 137)", + "secondary-900": "rgb(3 56 112)", + "accent-100": "rgb(229 228 248)", + "accent-200": "rgb(223 221 247)", + "accent-300": "rgb(204 201 241)", + "accent-400": "rgb(165 161 231)", + "accent-500": "rgb(127 120 221)", + "accent-600": "rgb(114 108 199)", + "accent-700": "rgb(95 90 166)", + "accent-800": "rgb(76 72 133)", + "accent-900": "rgb(62 59 108)", + "success-100": "rgb(227 243 231)", + "success-200": "rgb(220 241 225)", + "success-300": "rgb(199 232 206)", + "success-400": "rgb(156 214 170)", + "success-500": "rgb(114 197 133)", + "success-600": "rgb(103 177 120)", + "success-700": "rgb(86 148 100)", + "success-800": "rgb(68 118 80)", + "success-900": "rgb(56 97 65)", + "warning-100": "rgb(250 229 206)", + "warning-200": "rgb(249 223 193)", + "warning-300": "rgb(245 204 156)", + "warning-400": "rgb(238 165 82)", + "warning-500": "rgb(231 127 8)", + "warning-600": "rgb(208 114 7)", + "warning-700": "rgb(173 95 6)", + "warning-800": "rgb(139 76 5)", + "warning-900": "rgb(113 62 4)", + "danger-100": "rgb(233 207 211)", + "danger-200": "rgb(227 195 200)", + "danger-300": "rgb(210 159 167)", + "danger-400": "rgb(177 87 100)", + "danger-500": "rgb(143 15 34)", + "danger-600": "rgb(129 14 31)", + "danger-700": "rgb(107 11 26)", + "danger-800": "rgb(86 9 20)", + "danger-900": "rgb(70 7 17)", + "surface-100": "rgb(60 39 84)", + "surface-200": "rgb(35 22 49)", + "surface-300": "rgb(18 11 24)", + "surface-400": "rgb(162 129 197)", + "surface-500": "rgb(116 74 161)", + "surface-600": "rgb(83 53 115)", + "surface-700": "rgb(60 39 84)", + "surface-800": "rgb(35 22 49)", + "surface-900": "rgb(18 11 24)", + "color-scheme": "dark" + } +} diff --git a/packages/svelte-ux/vite.config.js b/packages/svelte-ux/vite.config.js index 97ce538e7..578e7fdd5 100644 --- a/packages/svelte-ux/vite.config.js +++ b/packages/svelte-ux/vite.config.js @@ -6,5 +6,8 @@ export default defineConfig({ plugins: [sveltekit(), sveld()], test: { include: ['src/**/*.{test,spec}.{js,ts}'], + coverage: { + reporter: ['html'], + }, }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 535a5be6b..ca2383813 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,54 +24,45 @@ importers: specifier: ^0.7.0 version: 0.7.0 '@kitql/helpers': - specifier: ^0.8.3 - version: 0.8.3 + specifier: ^0.8.8 + version: 0.8.8 commander: specifier: ^11.1.0 version: 11.1.0 devDependencies: '@types/node': - specifier: ^20.9.2 - version: 20.9.2 + specifier: ^20.10.6 + version: 20.10.6 prettier: - specifier: ^3.1.0 - version: 3.1.0 + specifier: ^3.1.1 + version: 3.1.1 packages/svelte-ux: dependencies: - '@changesets/cli': - specifier: ^2.26.2 - version: 2.26.2 '@floating-ui/dom': specifier: ^1.5.3 version: 1.5.3 '@fortawesome/fontawesome-common-types': - specifier: ^6.4.2 - version: 6.4.2 - '@fortawesome/free-regular-svg-icons': - specifier: ^6.2.1 - version: 6.2.1 - '@fortawesome/free-solid-svg-icons': - specifier: ^6.2.1 - version: 6.2.1 + specifier: ^6.5.1 + version: 6.5.1 '@mdi/js': specifier: ^7.0.96 version: 7.0.96 clsx: - specifier: ^2.0.0 - version: 2.0.0 + specifier: ^2.1.0 + version: 2.1.0 + culori: + specifier: ^3.3.0 + version: 3.3.0 d3-array: specifier: ^3.2.4 version: 3.2.4 d3-scale: specifier: ^4.0.2 version: 4.0.2 - d3-time: - specifier: ^3.1.0 - version: 3.1.0 date-fns: - specifier: ^2.30.0 - version: 2.30.0 + specifier: ^3.0.6 + version: 3.0.6 immer: specifier: ^10.0.3 version: 10.0.3 @@ -79,8 +70,8 @@ importers: specifier: ^4.17.21 version: 4.17.21 posthog-js: - specifier: ^1.95.1 - version: 1.95.1 + specifier: ^1.96.1 + version: 1.96.1 prism-svelte: specifier: ^0.5.0 version: 0.5.0 @@ -90,28 +81,40 @@ importers: prismjs: specifier: ^1.29.0 version: 1.29.0 - rehype-slug: - specifier: ^6.0.0 - version: 6.0.0 + sveld: + specifier: ^0.19.1 + version: 0.19.1(postcss@8.4.31) tailwind-merge: - specifier: ^2.0.0 - version: 2.0.0 + specifier: ^2.2.0 + version: 2.2.0 zod: specifier: ^3.22.4 version: 3.22.4 devDependencies: + '@changesets/cli': + specifier: ^2.27.1 + version: 2.27.1 + '@fortawesome/free-solid-svg-icons': + specifier: ^6.2.1 + version: 6.2.1 + '@skeletonlabs/tw-plugin': + specifier: ^0.3.1 + version: 0.3.1(tailwindcss@3.4.0) '@sveltejs/adapter-auto': specifier: ^2.1.1 - version: 2.1.1(@sveltejs/kit@1.27.6) + version: 2.1.1(@sveltejs/kit@1.30.3) '@sveltejs/kit': - specifier: ^1.27.6 - version: 1.27.6(svelte@4.2.7)(vite@4.5.0) + specifier: ^1.30.3 + version: 1.30.3(svelte@4.2.8)(vite@4.5.1) '@sveltejs/package': - specifier: ^2.2.2 - version: 2.2.2(svelte@4.2.7)(typescript@5.2.2) + specifier: ^2.2.5 + version: 2.2.5(svelte@4.2.8)(typescript@5.3.3) '@tailwindcss/typography': specifier: ^0.5.10 - version: 0.5.10(tailwindcss@3.3.5) + version: 0.5.10(tailwindcss@3.4.0) + '@types/culori': + specifier: ^2.0.4 + version: 2.0.4 '@types/d3-array': specifier: ^3.2.1 version: 3.2.1 @@ -119,17 +122,23 @@ importers: specifier: ^4.0.8 version: 4.0.8 '@types/lodash-es': - specifier: ^4.17.11 - version: 4.17.11 + specifier: ^4.17.12 + version: 4.17.12 '@types/marked': specifier: ^6.0.0 version: 6.0.0 '@types/prismjs': specifier: ^1.26.3 version: 1.26.3 + '@vitest/coverage-v8': + specifier: ^0.34.6 + version: 0.34.6(vitest@0.33.0) autoprefixer: specifier: ^10.4.16 version: 10.4.16(postcss@8.4.31) + daisyui: + specifier: ^4.5.0 + version: 4.5.0(postcss@8.4.31) execa: specifier: ^8.0.1 version: 8.0.1 @@ -138,31 +147,31 @@ importers: version: 10.0.0 mdsvex: specifier: ^0.11.0 - version: 0.11.0(svelte@4.2.7) + version: 0.11.0(svelte@4.2.8) prettier: - specifier: ^3.1.0 - version: 3.1.0 + specifier: ^3.1.1 + version: 3.1.1 prettier-plugin-svelte: - specifier: ^3.1.0 - version: 3.1.0(prettier@3.1.0)(svelte@4.2.7) - sveld: - specifier: ^0.19.1 - version: 0.19.1(postcss@8.4.31) + specifier: ^3.1.2 + version: 3.1.2(prettier@3.1.1)(svelte@4.2.8) + rehype-slug: + specifier: ^6.0.0 + version: 6.0.0 svelte: - specifier: ^4.2.7 - version: 4.2.7 + specifier: ^4.2.8 + version: 4.2.8 svelte-check: - specifier: ^3.6.0 - version: 3.6.0(postcss@8.4.31)(svelte@4.2.7) + specifier: ^3.6.2 + version: 3.6.2(postcss@8.4.31)(svelte@4.2.8) svelte-preprocess: - specifier: ^5.1.0 - version: 5.1.0(postcss@8.4.31)(svelte@4.2.7)(typescript@5.2.2) + specifier: ^5.1.3 + version: 5.1.3(postcss@8.4.31)(svelte@4.2.8)(typescript@5.3.3) svelte2tsx: - specifier: ^0.6.25 - version: 0.6.25(svelte@4.2.7)(typescript@5.2.2) + specifier: ^0.6.27 + version: 0.6.27(svelte@4.2.8)(typescript@5.3.3) tailwindcss: - specifier: ^3.3.5 - version: 3.3.5 + specifier: ^3.4.0 + version: 3.4.0 tslib: specifier: ^2.6.2 version: 2.6.2 @@ -170,14 +179,14 @@ importers: specifier: ^9.0.1 version: 9.0.1 typescript: - specifier: ^5.2.2 - version: 5.2.2 + specifier: ^5.3.3 + version: 5.3.3 unist-util-visit: specifier: ^5.0.0 version: 5.0.0 vite: - specifier: ^4.5.0 - version: 4.5.0(@types/node@20.9.2) + specifier: ^4.5.1 + version: 4.5.1(@types/node@20.10.6) vitest: specifier: ^0.33.0 version: 0.33.0 @@ -195,7 +204,6 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 - dev: true /@babel/code-frame@7.23.4: resolution: {integrity: sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==} @@ -203,10 +211,12 @@ packages: dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 + dev: true /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} + dev: true /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} @@ -215,42 +225,29 @@ packages: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 + dev: true - /@babel/runtime@7.23.2: - resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} + /@babel/runtime@7.23.4: + resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 - dev: false + dev: true - /@babel/runtime@7.23.4: - resolution: {integrity: sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==} + /@babel/runtime@7.23.7: + resolution: {integrity: sha512-w06OXVOFso7LcbzMiDGt+3X7Rh7Ho8MmgPoWU3rarH+8upf+wSU/grlGbWzQyr3DkdN6ZeuMFjpdwW0Q+HxobA==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 - /@changesets/apply-release-plan@6.1.4: - resolution: {integrity: sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/config': 2.3.1 - '@changesets/get-version-range-type': 0.3.2 - '@changesets/git': 2.0.0 - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - detect-indent: 6.1.0 - fs-extra: 7.0.1 - lodash.startcase: 4.4.0 - outdent: 0.5.0 - prettier: 2.8.8 - resolve-from: 5.0.0 - semver: 7.5.4 - dev: false + /@bcoe/v8-coverage@0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true /@changesets/apply-release-plan@7.0.0: resolution: {integrity: sha512-vfi69JR416qC9hWmFGSxj7N6wA5J222XNBmezSVATPWDVPIF7gkd4d8CpbEbXmRWbVrkoli3oerGS6dcL/BGsQ==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/config': 3.0.0 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.0 @@ -265,21 +262,10 @@ packages: semver: 7.5.4 dev: true - /@changesets/assemble-release-plan@5.2.4: - resolution: {integrity: sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/errors': 0.1.4 - '@changesets/get-dependents-graph': 1.3.6 - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - semver: 7.5.4 - dev: false - /@changesets/assemble-release-plan@6.0.0: resolution: {integrity: sha512-4QG7NuisAjisbW4hkLCmGW2lRYdPrKzro+fCtZaILX+3zdUELSvYjpL4GTv0E4aM9Mef3PuIQp89VmHJ4y2bfw==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.0.0 '@changesets/types': 6.0.0 @@ -287,57 +273,12 @@ packages: semver: 7.5.4 dev: true - /@changesets/changelog-git@0.1.14: - resolution: {integrity: sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==} - dependencies: - '@changesets/types': 5.2.1 - dev: false - /@changesets/changelog-git@0.2.0: resolution: {integrity: sha512-bHOx97iFI4OClIT35Lok3sJAwM31VbUM++gnMBV16fdbtBhgYu4dxsphBF/0AZZsyAHMrnM0yFcj5gZM1py6uQ==} dependencies: '@changesets/types': 6.0.0 dev: true - /@changesets/cli@2.26.2: - resolution: {integrity: sha512-dnWrJTmRR8bCHikJHl9b9HW3gXACCehz4OasrXpMp7sx97ECuBGGNjJhjPhdZNCvMy9mn4BWdplI323IbqsRig==} - hasBin: true - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/apply-release-plan': 6.1.4 - '@changesets/assemble-release-plan': 5.2.4 - '@changesets/changelog-git': 0.1.14 - '@changesets/config': 2.3.1 - '@changesets/errors': 0.1.4 - '@changesets/get-dependents-graph': 1.3.6 - '@changesets/get-release-plan': 3.0.17 - '@changesets/git': 2.0.0 - '@changesets/logger': 0.0.5 - '@changesets/pre': 1.0.14 - '@changesets/read': 0.5.9 - '@changesets/types': 5.2.1 - '@changesets/write': 0.2.3 - '@manypkg/get-packages': 1.1.3 - '@types/is-ci': 3.0.4 - '@types/semver': 7.5.5 - ansi-colors: 4.1.3 - chalk: 2.4.2 - enquirer: 2.4.1 - external-editor: 3.1.0 - fs-extra: 7.0.1 - human-id: 1.0.2 - is-ci: 3.0.1 - meow: 6.1.1 - outdent: 0.5.0 - p-limit: 2.3.0 - preferred-pm: 3.1.2 - resolve-from: 5.0.0 - semver: 7.5.4 - spawndamnit: 2.0.0 - term-size: 2.2.1 - tty-table: 4.2.3 - dev: false - /@changesets/cli@2.27.1: resolution: {integrity: sha512-iJ91xlvRnnrJnELTp4eJJEOPjgpF3NOh4qeQehM6Ugiz9gJPRZ2t+TsXun6E3AMN4hScZKjqVXl0TX+C7AB3ZQ==} hasBin: true @@ -376,18 +317,6 @@ packages: tty-table: 4.2.3 dev: true - /@changesets/config@2.3.1: - resolution: {integrity: sha512-PQXaJl82CfIXddUOppj4zWu+987GCw2M+eQcOepxN5s+kvnsZOwjEJO3DH9eVy+OP6Pg/KFEWdsECFEYTtbg6w==} - dependencies: - '@changesets/errors': 0.1.4 - '@changesets/get-dependents-graph': 1.3.6 - '@changesets/logger': 0.0.5 - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - micromatch: 4.0.5 - dev: false - /@changesets/config@3.0.0: resolution: {integrity: sha512-o/rwLNnAo/+j9Yvw9mkBQOZySDYyOr/q+wptRLcAVGlU6djOeP9v1nlalbL9MFsobuBVQbZCTp+dIzdq+CLQUA==} dependencies: @@ -400,28 +329,12 @@ packages: micromatch: 4.0.5 dev: true - /@changesets/errors@0.1.4: - resolution: {integrity: sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==} - dependencies: - extendable-error: 0.1.7 - dev: false - /@changesets/errors@0.2.0: resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} dependencies: extendable-error: 0.1.7 dev: true - /@changesets/get-dependents-graph@1.3.6: - resolution: {integrity: sha512-Q/sLgBANmkvUm09GgRsAvEtY3p1/5OCzgBE5vX3vgb5CvW0j7CEljocx5oPXeQSNph6FXulJlXV3Re/v3K3P3Q==} - dependencies: - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - chalk: 2.4.2 - fs-extra: 7.0.1 - semver: 7.5.4 - dev: false - /@changesets/get-dependents-graph@2.0.0: resolution: {integrity: sha512-cafUXponivK4vBgZ3yLu944mTvam06XEn2IZGjjKc0antpenkYANXiiE6GExV/yKdsCnE8dXVZ25yGqLYZmScA==} dependencies: @@ -441,22 +354,10 @@ packages: - encoding dev: true - /@changesets/get-release-plan@3.0.17: - resolution: {integrity: sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/assemble-release-plan': 5.2.4 - '@changesets/config': 2.3.1 - '@changesets/pre': 1.0.14 - '@changesets/read': 0.5.9 - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - dev: false - /@changesets/get-release-plan@4.0.0: resolution: {integrity: sha512-9L9xCUeD/Tb6L/oKmpm8nyzsOzhdNBBbt/ZNcjynbHC07WW4E1eX8NMGC5g5SbM5z/V+MOrYsJ4lRW41GCbg3w==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/assemble-release-plan': 6.0.0 '@changesets/config': 3.0.0 '@changesets/pre': 2.0.0 @@ -465,30 +366,14 @@ packages: '@manypkg/get-packages': 1.1.3 dev: true - /@changesets/get-version-range-type@0.3.2: - resolution: {integrity: sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==} - dev: false - /@changesets/get-version-range-type@0.4.0: resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} dev: true - /@changesets/git@2.0.0: - resolution: {integrity: sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/errors': 0.1.4 - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - is-subdir: 1.2.0 - micromatch: 4.0.5 - spawndamnit: 2.0.0 - dev: false - /@changesets/git@3.0.0: resolution: {integrity: sha512-vvhnZDHe2eiBNRFHEgMiGd2CT+164dfYyrJDhwwxTVD/OW0FUD6G7+4DIx1dNwkwjHyzisxGAU96q0sVNBns0w==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -497,25 +382,12 @@ packages: spawndamnit: 2.0.0 dev: true - /@changesets/logger@0.0.5: - resolution: {integrity: sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==} - dependencies: - chalk: 2.4.2 - dev: false - /@changesets/logger@0.1.0: resolution: {integrity: sha512-pBrJm4CQm9VqFVwWnSqKEfsS2ESnwqwH+xR7jETxIErZcfd1u2zBSqrHbRHR7xjhSgep9x2PSKFKY//FAshA3g==} dependencies: chalk: 2.4.2 dev: true - /@changesets/parse@0.3.16: - resolution: {integrity: sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==} - dependencies: - '@changesets/types': 5.2.1 - js-yaml: 3.14.1 - dev: false - /@changesets/parse@0.4.0: resolution: {integrity: sha512-TS/9KG2CdGXS27S+QxbZXgr8uPsP4yNJYb4BC2/NeFUj80Rni3TeD2qwWmabymxmrLo7JEsytXH1FbpKTbvivw==} dependencies: @@ -523,43 +395,20 @@ packages: js-yaml: 3.14.1 dev: true - /@changesets/pre@1.0.14: - resolution: {integrity: sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/errors': 0.1.4 - '@changesets/types': 5.2.1 - '@manypkg/get-packages': 1.1.3 - fs-extra: 7.0.1 - dev: false - /@changesets/pre@2.0.0: resolution: {integrity: sha512-HLTNYX/A4jZxc+Sq8D1AMBsv+1qD6rmmJtjsCJa/9MSRybdxh0mjbTvE6JYZQ/ZiQ0mMlDOlGPXTm9KLTU3jyw==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 fs-extra: 7.0.1 dev: true - /@changesets/read@0.5.9: - resolution: {integrity: sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/git': 2.0.0 - '@changesets/logger': 0.0.5 - '@changesets/parse': 0.3.16 - '@changesets/types': 5.2.1 - chalk: 2.4.2 - fs-extra: 7.0.1 - p-filter: 2.1.0 - dev: false - /@changesets/read@0.6.0: resolution: {integrity: sha512-ZypqX8+/im1Fm98K4YcZtmLKgjs1kDQ5zHpc2U1qdtNBmZZfo/IBiG162RoP0CUF05tvp2y4IspH11PLnPxuuw==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/git': 3.0.0 '@changesets/logger': 0.1.0 '@changesets/parse': 0.4.0 @@ -571,29 +420,16 @@ packages: /@changesets/types@4.1.0: resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} - - /@changesets/types@5.2.1: - resolution: {integrity: sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==} - dev: false + dev: true /@changesets/types@6.0.0: resolution: {integrity: sha512-b1UkfNulgKoWfqyHtzKS5fOZYSJO+77adgL7DLRDr+/7jhChN+QcHnbjiQVOz/U+Ts3PGNySq7diAItzDgugfQ==} dev: true - /@changesets/write@0.2.3: - resolution: {integrity: sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==} - dependencies: - '@babel/runtime': 7.23.4 - '@changesets/types': 5.2.1 - fs-extra: 7.0.1 - human-id: 1.0.2 - prettier: 2.8.8 - dev: false - /@changesets/write@0.3.0: resolution: {integrity: sha512-slGLb21fxZVUYbyea+94uFiD6ntQW0M2hIKNznFizDhZPDgn2c/fv1UzzlW43RVzh1BEDuIqW6hzlJ1OflNmcw==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/types': 6.0.0 fs-extra: 7.0.1 human-id: 1.0.2 @@ -848,20 +684,12 @@ packages: resolution: {integrity: sha512-Sz07mnQrTekFWLz5BMjOzHl/+NooTdW8F8kDQxjWwbpOJcnoSg4vUDng8d/WR1wOxM0O+CY9Zw0nR054riNYtQ==} engines: {node: '>=6'} requiresBuild: true - dev: false - - /@fortawesome/fontawesome-common-types@6.4.2: - resolution: {integrity: sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==} - engines: {node: '>=6'} - requiresBuild: true - dev: false + dev: true - /@fortawesome/free-regular-svg-icons@6.2.1: - resolution: {integrity: sha512-wiqcNDNom75x+pe88FclpKz7aOSqS2lOivZeicMV5KRwOAeypxEYWAK/0v+7r+LrEY30+qzh8r2XDaEHvoLsMA==} + /@fortawesome/fontawesome-common-types@6.5.1: + resolution: {integrity: sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==} engines: {node: '>=6'} requiresBuild: true - dependencies: - '@fortawesome/fontawesome-common-types': 6.2.1 dev: false /@fortawesome/free-solid-svg-icons@6.2.1: @@ -870,7 +698,7 @@ packages: requiresBuild: true dependencies: '@fortawesome/fontawesome-common-types': 6.2.1 - dev: false + dev: true /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -884,6 +712,11 @@ packages: wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true + /@istanbuljs/schema@0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + /@jest/schemas@29.6.3: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -898,50 +731,48 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.20 - dev: true /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@kitql/helpers@0.8.3: - resolution: {integrity: sha512-oozUXcSEo7sTAyUF6HOkO1M4D8g9z0w//7MHI1fyXZ1QhA5SQEjq0Q5Js7VQPhVE5tPg0RuDlnqV5GHCOcdwsQ==} + /@kitql/helpers@0.8.8: + resolution: {integrity: sha512-+oKunjiNcYtfwk6J7Vx+4IZjysg8DpJ/XUu2m0GwhXVA889H3ne8dfCko0YZxjmyLTf+5LvmQjbpxb8acqZF5g==} + engines: {node: ^16.14 || >=18} dev: false /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 + dev: true /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.23.4 + '@babel/runtime': 7.23.7 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 globby: 11.1.0 read-yaml-file: 1.1.0 + dev: true /@mdi/js@7.0.96: resolution: {integrity: sha512-lNqhkV3cpPfYb/Avh+vXLFukUTbHbyHoFo4Jdc7Oc9UvURGVhamFIpgOVvEf2bNA78zvjXTZeVWExUTR+DLBfQ==} @@ -989,7 +820,7 @@ packages: is-module: 1.0.0 resolve: 1.22.8 rollup: 2.79.1 - dev: true + dev: false /@rollup/pluginutils@3.1.0(rollup@2.79.1): resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} @@ -1001,7 +832,7 @@ packages: estree-walker: 1.0.1 picomatch: 2.3.1 rollup: 2.79.1 - dev: true + dev: false /@rollup/pluginutils@4.2.1: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} @@ -1009,7 +840,7 @@ packages: dependencies: estree-walker: 2.0.2 picomatch: 2.3.1 - dev: true + dev: false /@sapphire/node-utilities@1.0.0: resolution: {integrity: sha512-xFC4UyzSKs6juyFtsUV4VNybg0KIpwaThED2TH3TGtNT5b0VFpILTXQtqXpPf+Rfmj+O/mLCm319xy4ohsQqxQ==} @@ -1020,17 +851,25 @@ packages: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true - /@sveltejs/adapter-auto@2.1.1(@sveltejs/kit@1.27.6): + /@skeletonlabs/tw-plugin@0.3.1(tailwindcss@3.4.0): + resolution: {integrity: sha512-DjjeOHN3HhFQf6gYPT2MUZMkIdw1jeB9mbuKC8etQxUlOR4XitfC7hssRWFJ8RJsvrrN0myCBbdWkVG1JVA96g==} + peerDependencies: + tailwindcss: '>=3.0.0' + dependencies: + tailwindcss: 3.4.0 + dev: true + + /@sveltejs/adapter-auto@2.1.1(@sveltejs/kit@1.30.3): resolution: {integrity: sha512-nzi6x/7/3Axh5VKQ8Eed3pYxastxoa06Y/bFhWb7h3Nu+nGRVxKAy3+hBJgmPCwWScy8n0TsstZjSVKfyrIHkg==} peerDependencies: '@sveltejs/kit': ^1.0.0 dependencies: - '@sveltejs/kit': 1.27.6(svelte@4.2.7)(vite@4.5.0) + '@sveltejs/kit': 1.30.3(svelte@4.2.8)(vite@4.5.1) import-meta-resolve: 4.0.0 dev: true - /@sveltejs/kit@1.27.6(svelte@4.2.7)(vite@4.5.0): - resolution: {integrity: sha512-GsjTkMbKzXdbeRg0tk8S7HNShQ4879ftRr0ZHaZfjbig1xQwG57Bvcm9U9/mpLJtCapLbLWUnygKrgcLISLC8A==} + /@sveltejs/kit@1.30.3(svelte@4.2.8)(vite@4.5.1): + resolution: {integrity: sha512-0DzVXfU4h+tChFvoc8C61IqErCyskD4ydSIDjpKS2lYlEzIYrtYrY7juSqACFxqcvZAnOEXvSY+zZ8br0+ZMMg==} engines: {node: ^16.14 || >=18} hasBin: true requiresBuild: true @@ -1038,7 +877,7 @@ packages: svelte: ^3.54.0 || ^4.0.0-next.0 || ^5.0.0-next.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 2.5.0(svelte@4.2.7)(vite@4.5.0) + '@sveltejs/vite-plugin-svelte': 2.5.0(svelte@4.2.8)(vite@4.5.1) '@types/cookie': 0.5.4 cookie: 0.5.0 devalue: 4.3.2 @@ -1049,16 +888,16 @@ packages: sade: 1.8.1 set-cookie-parser: 2.6.0 sirv: 2.0.3 - svelte: 4.2.7 + svelte: 4.2.8 tiny-glob: 0.2.9 undici: 5.26.5 - vite: 4.5.0(@types/node@20.9.2) + vite: 4.5.1(@types/node@20.10.6) transitivePeerDependencies: - supports-color dev: true - /@sveltejs/package@2.2.2(svelte@4.2.7)(typescript@5.2.2): - resolution: {integrity: sha512-rP3sVv6cAntcdcG4r4KspLU6nZYYUrHJBAX3Arrw0KJFdgxtlsi2iDwN0Jwr/vIkgjcU0ZPWM8kkT5kpZDlWAw==} + /@sveltejs/package@2.2.5(svelte@4.2.8)(typescript@5.3.3): + resolution: {integrity: sha512-H0dFDrp7b/tr4zrUzOfqPKHG8y6ceNlGKPfSpp4ym1kTPWP79Mea5rvDlcmsbOS26FmHN/vttubalBdOCGA6qA==} engines: {node: ^16.14 || >=18} hasBin: true peerDependencies: @@ -1068,13 +907,13 @@ packages: kleur: 4.1.5 sade: 1.8.1 semver: 7.5.4 - svelte: 4.2.7 - svelte2tsx: 0.6.25(svelte@4.2.7)(typescript@5.2.2) + svelte: 4.2.8 + svelte2tsx: 0.6.27(svelte@4.2.8)(typescript@5.3.3) transitivePeerDependencies: - typescript dev: true - /@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.5.0)(svelte@4.2.7)(vite@4.5.0): + /@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.5.0)(svelte@4.2.8)(vite@4.5.1): resolution: {integrity: sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==} engines: {node: ^14.18.0 || >= 16} peerDependencies: @@ -1082,30 +921,30 @@ packages: svelte: ^3.54.0 || ^4.0.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 2.5.0(svelte@4.2.7)(vite@4.5.0) + '@sveltejs/vite-plugin-svelte': 2.5.0(svelte@4.2.8)(vite@4.5.1) debug: 4.3.4 - svelte: 4.2.7 - vite: 4.5.0(@types/node@20.9.2) + svelte: 4.2.8 + vite: 4.5.1(@types/node@20.10.6) transitivePeerDependencies: - supports-color dev: true - /@sveltejs/vite-plugin-svelte@2.5.0(svelte@4.2.7)(vite@4.5.0): + /@sveltejs/vite-plugin-svelte@2.5.0(svelte@4.2.8)(vite@4.5.1): resolution: {integrity: sha512-FxLZLVfFA2soGw7ej8Ohuav7+AOsJILiPlL8FgY5MABDDmDqb637o8Xd/QGkrXLC1qXyG1bnteOw5Z5yrA2lHA==} engines: {node: ^14.18.0 || >= 16} peerDependencies: svelte: ^3.54.0 || ^4.0.0 || ^5.0.0-next.0 vite: ^4.0.0 dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.5.0)(svelte@4.2.7)(vite@4.5.0) + '@sveltejs/vite-plugin-svelte-inspector': 1.0.4(@sveltejs/vite-plugin-svelte@2.5.0)(svelte@4.2.8)(vite@4.5.1) debug: 4.3.4 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.5 - svelte: 4.2.7 - svelte-hmr: 0.15.3(svelte@4.2.7) - vite: 4.5.0(@types/node@20.9.2) - vitefu: 0.2.5(vite@4.5.0) + svelte: 4.2.8 + svelte-hmr: 0.15.3(svelte@4.2.8) + vite: 4.5.1(@types/node@20.10.6) + vitefu: 0.2.5(vite@4.5.1) transitivePeerDependencies: - supports-color dev: true @@ -1120,7 +959,7 @@ packages: - encoding dev: true - /@tailwindcss/typography@0.5.10(tailwindcss@3.3.5): + /@tailwindcss/typography@0.5.10(tailwindcss@3.4.0): resolution: {integrity: sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==} peerDependencies: tailwindcss: '>=3.0.0 || insiders' @@ -1129,7 +968,7 @@ packages: lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.3.5 + tailwindcss: 3.4.0 dev: true /@types/chai-subset@1.3.5: @@ -1146,6 +985,10 @@ packages: resolution: {integrity: sha512-7z/eR6O859gyWIAjuvBWFzNURmf2oPBmJlfVWkwehU5nzIyjwBsTh7WMmEEV4JFnHuQ3ex4oyTvfKzcyJVDBNA==} dev: true + /@types/culori@2.0.4: + resolution: {integrity: sha512-GeLW8+KBRkwqIgeGrU8EnNbBE2D7waYbQHkx2xnI5exlzSGTMpjWtDaHzLWK1PTYmyJN9u6dPvMYumFevDe+VA==} + dev: true + /@types/d3-array@3.2.1: resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} dev: true @@ -1162,26 +1005,23 @@ packages: /@types/estree@0.0.39: resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} - dev: true + dev: false /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - dev: true /@types/hast@3.0.3: resolution: {integrity: sha512-2fYGlaDy/qyLlhidX42wAH0KBi2TCjKMH8CHmBXgRlJ3Y+OXTiqsPQ6IWarZKwF1JoUcAJdPogv1d4b0COTpmQ==} dependencies: '@types/unist': 3.0.2 - dev: false + dev: true - /@types/is-ci@3.0.4: - resolution: {integrity: sha512-AkCYCmwlXeuH89DagDCzvCAyltI2v9lh3U3DqSg/GrBYoReAaWwxfXCqMx9UV5MajLZ4ZFwZzV4cABGIxk2XRw==} - dependencies: - ci-info: 3.9.0 - dev: false + /@types/istanbul-lib-coverage@2.0.6: + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + dev: true - /@types/lodash-es@4.17.11: - resolution: {integrity: sha512-eCw8FYAWHt2DDl77s+AMLLzPn310LKohruumpucZI4oOFJkIgnlaJcy23OKMJxx4r9PeTF13Gv6w+jqjWQaYUg==} + /@types/lodash-es@4.17.12: + resolution: {integrity: sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==} dependencies: '@types/lodash': 4.14.201 dev: true @@ -1199,18 +1039,20 @@ packages: /@types/minimist@1.2.5: resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + dev: true /@types/node@12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + dev: true - /@types/node@20.9.2: - resolution: {integrity: sha512-WHZXKFCEyIUJzAwh3NyyTHYSR35SevJ6mZ1nWwJafKtiQbqRTIKSRcw3Ma3acqgsent3RRDqeVwpHntMk+9irg==} + /@types/node@20.10.6: + resolution: {integrity: sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==} dependencies: undici-types: 5.26.5 - dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + dev: true /@types/prismjs@1.26.3: resolution: {integrity: sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw==} @@ -1218,16 +1060,16 @@ packages: /@types/pug@2.0.9: resolution: {integrity: sha512-Yg4LkgFYvn1faISbDNWmcAC1XoDT8IoMUFspp5mnagKk+UvD2N0IWt5A7GRdMubsNWqgCLmrkf8rXkzNqb4szA==} - dev: true /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 20.9.2 - dev: true + '@types/node': 20.10.6 + dev: false /@types/semver@7.5.5: resolution: {integrity: sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==} + dev: true /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -1235,6 +1077,28 @@ packages: /@types/unist@3.0.2: resolution: {integrity: sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==} + dev: true + + /@vitest/coverage-v8@0.34.6(vitest@0.33.0): + resolution: {integrity: sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==} + peerDependencies: + vitest: '>=0.32.0 <1' + dependencies: + '@ampproject/remapping': 2.2.1 + '@bcoe/v8-coverage': 0.2.3 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + magic-string: 0.30.5 + picocolors: 1.0.0 + std-env: 3.4.3 + test-exclude: 6.0.0 + v8-to-istanbul: 9.2.0 + vitest: 0.33.0 + transitivePeerDependencies: + - supports-color + dev: true /@vitest/expect@0.33.0: resolution: {integrity: sha512-sVNf+Gla3mhTCxNJx+wJLDPp/WcstOe0Ksqz4Vec51MmgMth/ia0MGFEkIZmVGeTL5HtjYR4Wl/ZxBxBXZJTzQ==} @@ -1283,15 +1147,16 @@ packages: resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + dev: true /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} + dev: true /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} @@ -1307,12 +1172,14 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 + dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} dependencies: color-convert: 2.0.1 + dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -1344,6 +1211,7 @@ packages: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} dependencies: sprintf-js: 1.0.3 + dev: true /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1353,17 +1221,18 @@ packages: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: dequal: 2.0.3 - dev: true /array-buffer-byte-length@1.0.0: resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} dependencies: call-bind: 1.0.5 is-array-buffer: 3.0.2 + dev: true /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + dev: true /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} @@ -1373,6 +1242,7 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 es-shim-unscopables: 1.0.2 + dev: true /arraybuffer.prototype.slice@1.0.2: resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} @@ -1385,10 +1255,12 @@ packages: get-intrinsic: 1.2.2 is-array-buffer: 3.0.2 is-shared-array-buffer: 1.0.2 + dev: true /arrify@1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} + dev: true /assertion-error@1.1.0: resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} @@ -1413,22 +1285,22 @@ packages: /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} + dev: true /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} dependencies: dequal: 2.0.3 - dev: true /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} dependencies: is-windows: 1.0.2 + dev: true /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} @@ -1440,7 +1312,6 @@ packages: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true /brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} @@ -1458,6 +1329,7 @@ packages: resolution: {integrity: sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==} dependencies: wcwidth: 1.0.1 + dev: true /browserslist@4.22.1: resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} @@ -1472,12 +1344,11 @@ packages: /buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - dev: true /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} - dev: true + dev: false /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} @@ -1490,6 +1361,7 @@ packages: function-bind: 1.1.2 get-intrinsic: 1.2.2 set-function-length: 1.1.1 + dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -1508,10 +1380,12 @@ packages: camelcase: 5.3.1 map-obj: 4.3.0 quick-lru: 4.0.1 + dev: true /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} + dev: true /caniuse-lite@1.0.30001561: resolution: {integrity: sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw==} @@ -1537,6 +1411,7 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 + dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1544,9 +1419,11 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 + dev: true /chardet@0.7.0: resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: true /check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} @@ -1572,6 +1449,7 @@ packages: /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + dev: true /cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -1579,6 +1457,7 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 6.2.0 + dev: true /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -1587,13 +1466,15 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + dev: true /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + dev: true - /clsx@2.0.0: - resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + /clsx@2.1.0: + resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} engines: {node: '>=6'} dev: false @@ -1605,24 +1486,27 @@ packages: acorn: 8.11.2 estree-walker: 3.0.3 periscopic: 3.1.0 - dev: true /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 + dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 + dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} @@ -1640,10 +1524,13 @@ packages: /comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} - dev: true + dev: false /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} dev: true /cookie@0.5.0: @@ -1657,6 +1544,7 @@ packages: lru-cache: 4.1.5 shebang-command: 1.2.0 which: 1.3.1 + dev: true /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} @@ -1667,13 +1555,19 @@ packages: which: 2.0.2 dev: true + /css-selector-tokenizer@0.8.0: + resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} + dependencies: + cssesc: 3.0.0 + fastparse: 1.1.2 + dev: true + /css-tree@2.3.1: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} dependencies: mdn-data: 2.0.30 source-map-js: 1.0.2 - dev: true /cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} @@ -1683,12 +1577,15 @@ packages: /csv-generate@3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} + dev: true /csv-parse@4.16.3: resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==} + dev: true /csv-stringify@5.6.5: resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==} + dev: true /csv@5.5.3: resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} @@ -1698,6 +1595,11 @@ packages: csv-parse: 4.16.3 csv-stringify: 5.6.5 stream-transform: 2.1.3 + dev: true + + /culori@3.3.0: + resolution: {integrity: sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} /d3-array@3.2.4: resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} @@ -1748,15 +1650,24 @@ packages: d3-array: 3.2.4 dev: false + /daisyui@4.5.0(postcss@8.4.31): + resolution: {integrity: sha512-RWQCPQ0vBUaxGy768O7Ku8SRQgwdoto1lDzuKeVOcMtYghuSbUY7NoPoMK+k8JH4s1J02OvpNAgtB9MeKpZIwg==} + engines: {node: '>=16.9.0'} + dependencies: + css-selector-tokenizer: 0.8.0 + culori: 3.3.0 + picocolors: 1.0.0 + postcss-js: 4.0.1(postcss@8.4.31) + transitivePeerDependencies: + - postcss + dev: true + /dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} dev: true - /date-fns@2.30.0: - resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} - engines: {node: '>=0.11'} - dependencies: - '@babel/runtime': 7.23.2 + /date-fns@3.0.6: + resolution: {integrity: sha512-W+G99rycpKMMF2/YD064b2lE7jJGUe+EjOES7Q8BIGY8sbNdbgcs9XFTZwvzc9Jx1f3k7LB7gZaZa7f8Agzljg==} dev: false /debug@4.3.4: @@ -1777,10 +1688,12 @@ packages: dependencies: decamelize: 1.2.0 map-obj: 1.0.1 + dev: true /decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + dev: true /dedent-js@1.0.1: resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==} @@ -1796,12 +1709,12 @@ packages: /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - dev: true /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 + dev: true /define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} @@ -1810,6 +1723,7 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.1 + dev: true /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} @@ -1818,11 +1732,11 @@ packages: define-data-property: 1.1.1 has-property-descriptors: 1.0.1 object-keys: 1.1.1 + dev: true /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: true /detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} @@ -1846,6 +1760,7 @@ packages: engines: {node: '>=8'} dependencies: path-type: 4.0.0 + dev: true /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -1866,6 +1781,7 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} @@ -1877,11 +1793,13 @@ packages: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + dev: true /error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: is-arrayish: 0.2.1 + dev: true /es-abstract@1.22.3: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} @@ -1926,6 +1844,7 @@ packages: typed-array-length: 1.0.4 unbox-primitive: 1.0.2 which-typed-array: 1.1.13 + dev: true /es-set-tostringtag@2.0.2: resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} @@ -1934,11 +1853,13 @@ packages: get-intrinsic: 1.2.2 has-tostringtag: 1.0.0 hasown: 2.0.0 + dev: true /es-shim-unscopables@1.0.2: resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} dependencies: hasown: 2.0.0 + dev: true /es-to-primitive@1.2.1: resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} @@ -1947,10 +1868,10 @@ packages: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 + dev: true /es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} - dev: true /esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} @@ -1985,10 +1906,12 @@ packages: /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + dev: true /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} + dev: true /esm-env@1.0.0: resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} @@ -1998,20 +1921,20 @@ packages: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + dev: true /estree-walker@1.0.1: resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - dev: true + dev: false /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true + dev: false /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} dependencies: '@types/estree': 1.0.5 - dev: true /execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} @@ -2030,6 +1953,7 @@ packages: /extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + dev: true /external-editor@3.1.0: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} @@ -2038,6 +1962,7 @@ packages: chardet: 0.7.0 iconv-lite: 0.4.24 tmp: 0.0.33 + dev: true /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} @@ -2049,6 +1974,10 @@ packages: merge2: 1.4.1 micromatch: 4.0.5 + /fastparse@1.1.2: + resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} + dev: true + /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: @@ -2070,6 +1999,7 @@ packages: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 + dev: true /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -2077,17 +2007,20 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 + dev: true /find-yarn-workspace-root2@1.2.16: resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} dependencies: micromatch: 4.0.5 pkg-dir: 4.2.0 + dev: true /for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 + dev: true /foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} @@ -2108,6 +2041,7 @@ packages: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 + dev: true /fs-extra@8.1.0: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} @@ -2116,17 +2050,16 @@ packages: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 + dev: true /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true /fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: true optional: true /function-bind@1.1.2: @@ -2140,13 +2073,16 @@ packages: define-properties: 1.2.1 es-abstract: 1.22.3 functions-have-names: 1.2.3 + dev: true /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: true /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + dev: true /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} @@ -2159,6 +2095,7 @@ packages: has-proto: 1.0.1 has-symbols: 1.0.3 hasown: 2.0.0 + dev: true /get-stream@8.0.1: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} @@ -2171,10 +2108,11 @@ packages: dependencies: call-bind: 1.0.5 get-intrinsic: 1.2.2 + dev: true /github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} - dev: false + dev: true /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -2221,13 +2159,13 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /globalthis@1.0.3: resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 + dev: true /globalyzer@0.1.0: resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} @@ -2243,6 +2181,7 @@ packages: ignore: 5.3.0 merge2: 1.4.1 slash: 3.0.0 + dev: true /globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -2252,46 +2191,56 @@ packages: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.2 + dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} /grapheme-splitter@1.0.4: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + dev: true /hard-rejection@2.1.0: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} + dev: true /has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: true /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} + dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + dev: true /has-property-descriptors@1.0.1: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} dependencies: get-intrinsic: 1.2.2 + dev: true /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} + dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + dev: true /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 + dev: true /hasown@2.0.0: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} @@ -2303,19 +2252,25 @@ packages: resolution: {integrity: sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==} dependencies: '@types/hast': 3.0.3 - dev: false + dev: true /hast-util-to-string@3.0.0: resolution: {integrity: sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==} dependencies: '@types/hast': 3.0.3 - dev: false + dev: true /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + + /html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} + dev: true /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} @@ -2327,10 +2282,12 @@ packages: engines: {node: '>=0.10.0'} dependencies: safer-buffer: 2.1.2 + dev: true /ignore@5.3.0: resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} engines: {node: '>= 4'} + dev: true /immer@10.0.3: resolution: {integrity: sha512-pwupu3eWfouuaowscykeckFmVTpqbzW+rXFCX8rQLkZzM9ftBmU/++Ra+o+L27mz03zJTlyV4UUr+fdKNffo4A==} @@ -2351,17 +2308,16 @@ packages: /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + dev: true /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true /internal-slot@1.0.6: resolution: {integrity: sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==} @@ -2370,6 +2326,7 @@ packages: get-intrinsic: 1.2.2 hasown: 2.0.0 side-channel: 1.0.4 + dev: true /internmap@2.0.3: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} @@ -2382,14 +2339,17 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 is-typed-array: 1.1.12 + dev: true /is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: has-bigints: 1.0.2 + dev: true /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} @@ -2404,24 +2364,19 @@ packages: dependencies: call-bind: 1.0.5 has-tostringtag: 1.0.0 + dev: true /is-builtin-module@3.2.1: resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} engines: {node: '>=6'} dependencies: builtin-modules: 3.3.0 - dev: true + dev: false /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - - /is-ci@3.0.1: - resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} - hasBin: true - dependencies: - ci-info: 3.9.0 - dev: false + dev: true /is-core-module@2.13.1: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} @@ -2433,6 +2388,7 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 + dev: true /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} @@ -2441,6 +2397,7 @@ packages: /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + dev: true /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} @@ -2450,17 +2407,19 @@ packages: /is-module@1.0.0: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - dev: true + dev: false /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} + dev: true /is-number-object@1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 + dev: true /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} @@ -2469,12 +2428,12 @@ packages: /is-plain-obj@1.1.0: resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} engines: {node: '>=0.10.0'} + dev: true /is-reference@3.0.2: resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} dependencies: '@types/estree': 1.0.5 - dev: true /is-regex@1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} @@ -2482,11 +2441,13 @@ packages: dependencies: call-bind: 1.0.5 has-tostringtag: 1.0.0 + dev: true /is-shared-array-buffer@1.0.2: resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} dependencies: call-bind: 1.0.5 + dev: true /is-stream@3.0.0: resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} @@ -2498,39 +2459,80 @@ packages: engines: {node: '>= 0.4'} dependencies: has-tostringtag: 1.0.0 + dev: true /is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} dependencies: better-path-resolve: 1.0.0 + dev: true /is-symbol@1.0.4: resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 + dev: true /is-typed-array@1.1.12: resolution: {integrity: sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==} engines: {node: '>= 0.4'} dependencies: which-typed-array: 1.1.13 + dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.5 + dev: true /is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} + dev: true /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: true /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + dev: true /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} @@ -2548,6 +2550,7 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -2555,6 +2558,7 @@ packages: dependencies: argparse: 1.0.10 esprima: 4.0.1 + dev: true /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -2565,6 +2569,7 @@ packages: /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} @@ -2574,14 +2579,17 @@ packages: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: graceful-fs: 4.2.11 + dev: true /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} + dev: true /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} + dev: true /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} @@ -2590,6 +2598,7 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true /load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} @@ -2599,6 +2608,7 @@ packages: js-yaml: 3.14.1 pify: 4.0.1 strip-bom: 3.0.0 + dev: true /local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} @@ -2607,19 +2617,20 @@ packages: /locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} - dev: true /locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} dependencies: p-locate: 4.1.0 + dev: true /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} dependencies: p-locate: 5.0.0 + dev: true /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} @@ -2639,6 +2650,7 @@ packages: /lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + dev: true /loupe@2.3.7: resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} @@ -2662,6 +2674,7 @@ packages: dependencies: pseudomap: 1.0.2 yallist: 2.1.2 + dev: true /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} @@ -2673,27 +2686,29 @@ packages: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} dev: true - /magic-string@0.27.0: - resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /magic-string@0.30.5: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + semver: 7.5.4 + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 dev: true /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} + dev: true /map-obj@4.3.0: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} + dev: true /marked@10.0.0: resolution: {integrity: sha512-YiGcYcWj50YrwBgNzFoYhQ1hT6GmQbFG8SksnYJX1z4BXTHSOrz1GB5/Jm2yQvMg4nN1FHP4M6r03R10KrVUiA==} @@ -2709,9 +2724,8 @@ packages: /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - dev: true - /mdsvex@0.11.0(svelte@4.2.7): + /mdsvex@0.11.0(svelte@4.2.8): resolution: {integrity: sha512-gJF1s0N2nCmdxcKn8HDn0LKrN8poStqAicp6bBcsKFd/zkUBGLP5e7vnxu+g0pjBbDFOscUyI1mtHz+YK2TCDw==} peerDependencies: svelte: '>=3 <5' @@ -2719,7 +2733,7 @@ packages: '@types/unist': 2.0.10 prism-svelte: 0.4.7 prismjs: 1.29.0 - svelte: 4.2.7 + svelte: 4.2.8 vfile-message: 2.0.4 dev: true @@ -2738,6 +2752,7 @@ packages: trim-newlines: 3.0.1 type-fest: 0.13.1 yargs-parser: 18.1.3 + dev: true /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -2767,7 +2782,6 @@ packages: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 - dev: true /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} @@ -2783,10 +2797,10 @@ packages: arrify: 1.0.1 is-plain-obj: 1.1.0 kind-of: 6.0.3 + dev: true /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} @@ -2796,13 +2810,13 @@ packages: /mixme@0.5.10: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} + dev: true /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true dependencies: minimist: 1.2.8 - dev: true /mlly@1.4.2: resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} @@ -2839,7 +2853,6 @@ packages: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: true /no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -2871,6 +2884,7 @@ packages: resolve: 1.22.8 semver: 5.7.2 validate-npm-package-license: 3.0.4 + dev: true /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -2901,10 +2915,12 @@ packages: /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} + dev: true /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} @@ -2914,12 +2930,12 @@ packages: define-properties: 1.2.1 has-symbols: 1.0.3 object-keys: 1.1.1 + dev: true /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} @@ -2931,27 +2947,32 @@ packages: /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + dev: true /outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} + dev: true /p-filter@2.1.0: resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} engines: {node: '>=8'} dependencies: p-map: 2.1.0 + dev: true /p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} dependencies: p-try: 2.2.0 + dev: true /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 + dev: true /p-limit@4.0.0: resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} @@ -2965,20 +2986,24 @@ packages: engines: {node: '>=8'} dependencies: p-limit: 2.3.0 + dev: true /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: p-limit: 3.1.0 + dev: true /p-map@2.1.0: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} + dev: true /p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + dev: true /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -2995,6 +3020,7 @@ packages: error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + dev: true /pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} @@ -3006,11 +3032,11 @@ packages: /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + dev: true /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - dev: true /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} @@ -3036,6 +3062,7 @@ packages: /path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + dev: true /pathe@1.1.1: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} @@ -3051,7 +3078,6 @@ packages: '@types/estree': 1.0.5 estree-walker: 3.0.3 is-reference: 3.0.2 - dev: true /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} @@ -3068,6 +3094,7 @@ packages: /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + dev: true /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} @@ -3079,6 +3106,7 @@ packages: engines: {node: '>=8'} dependencies: find-up: 4.1.0 + dev: true /pkg-types@1.0.3: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} @@ -3164,10 +3192,9 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true - /posthog-js@1.95.1: - resolution: {integrity: sha512-79HPLoBqENBEEGFhn+hueKliYH66Qbu4WcRTEd8WaqtvqHrK9qAQkcrShZNkg1V5vM4kHp0iMIkJYBXg1sq06Q==} + /posthog-js@1.96.1: + resolution: {integrity: sha512-kv1vQqYMt2BV3YHS+wxsbGuP+tz+M3y1AzNhz8TfkpY1HT8W/ONT0i0eQpeRr9Y+d4x/fZ6M4cXG5GMvi9lRCA==} dependencies: fflate: 0.4.8 dev: false @@ -3180,15 +3207,16 @@ packages: find-yarn-workspace-root2: 1.2.16 path-exists: 4.0.0 which-pm: 2.0.0 + dev: true - /prettier-plugin-svelte@3.1.0(prettier@3.1.0)(svelte@4.2.7): - resolution: {integrity: sha512-96+AZxs2ESqIFA9j+o+DHqY+BsUglezfl553LQd6VOtTyJq5GPuBEb3ElxF2cerFzKlYKttlH/VcVmRNj5oc3A==} + /prettier-plugin-svelte@3.1.2(prettier@3.1.1)(svelte@4.2.8): + resolution: {integrity: sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==} peerDependencies: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 dependencies: - prettier: 3.1.0 - svelte: 4.2.7 + prettier: 3.1.1 + svelte: 4.2.8 dev: true /prettier@2.8.8: @@ -3196,8 +3224,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - /prettier@3.1.0: - resolution: {integrity: sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==} + /prettier@3.1.1: + resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} engines: {node: '>=14'} hasBin: true dev: true @@ -3229,6 +3257,7 @@ packages: /pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} + dev: true /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -3236,6 +3265,7 @@ packages: /quick-lru@4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} + dev: true /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} @@ -3254,6 +3284,7 @@ packages: find-up: 4.1.0 read-pkg: 5.2.0 type-fest: 0.8.1 + dev: true /read-pkg@5.2.0: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} @@ -3263,6 +3294,7 @@ packages: normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 + dev: true /read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} @@ -3272,6 +3304,7 @@ packages: js-yaml: 3.14.1 pify: 4.0.1 strip-bom: 3.0.0 + dev: true /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} @@ -3286,6 +3319,7 @@ packages: dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 + dev: true /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} @@ -3297,6 +3331,7 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 set-function-name: 2.0.1 + dev: true /rehype-slug@6.0.0: resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} @@ -3306,14 +3341,16 @@ packages: hast-util-heading-rank: 3.0.0 hast-util-to-string: 3.0.0 unist-util-visit: 5.0.0 - dev: false + dev: true /require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + dev: true /require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: true /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -3323,11 +3360,12 @@ packages: /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + dev: true /resolve.exports@2.0.2: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} - dev: true + dev: false /resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} @@ -3346,7 +3384,6 @@ packages: hasBin: true dependencies: glob: 7.2.3 - dev: true /rimraf@5.0.5: resolution: {integrity: sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==} @@ -3356,7 +3393,7 @@ packages: glob: 10.3.10 dev: true - /rollup-plugin-svelte@7.1.6(rollup@2.79.1)(svelte@4.2.7): + /rollup-plugin-svelte@7.1.6(rollup@2.79.1)(svelte@4.2.8): resolution: {integrity: sha512-nVFRBpGWI2qUY1OcSiEEA/kjCY2+vAjO9BI8SzA7NRrh2GTunLd6w2EYmnMt/atgdg8GvcNjLsmZmbQs/u4SQA==} engines: {node: '>=10'} peerDependencies: @@ -3366,8 +3403,8 @@ packages: '@rollup/pluginutils': 4.2.1 resolve.exports: 2.0.2 rollup: 2.79.1 - svelte: 4.2.7 - dev: true + svelte: 4.2.8 + dev: false /rollup@2.79.1: resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} @@ -3375,7 +3412,7 @@ packages: hasBin: true optionalDependencies: fsevents: 2.3.3 - dev: true + dev: false /rollup@3.29.4: resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} @@ -3405,6 +3442,7 @@ packages: get-intrinsic: 1.2.2 has-symbols: 1.0.3 isarray: 2.0.5 + dev: true /safe-regex-test@1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} @@ -3412,9 +3450,11 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 is-regex: 1.1.4 + dev: true /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true /sander@0.5.1: resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} @@ -3423,11 +3463,11 @@ packages: graceful-fs: 4.2.11 mkdirp: 0.5.6 rimraf: 2.7.1 - dev: true /semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true + dev: true /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} @@ -3438,6 +3478,7 @@ packages: /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: true /set-cookie-parser@2.6.0: resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} @@ -3451,6 +3492,7 @@ packages: get-intrinsic: 1.2.2 gopd: 1.0.1 has-property-descriptors: 1.0.1 + dev: true /set-function-name@2.0.1: resolution: {integrity: sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==} @@ -3459,12 +3501,14 @@ packages: define-data-property: 1.1.1 functions-have-names: 1.2.3 has-property-descriptors: 1.0.1 + dev: true /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} dependencies: shebang-regex: 1.0.0 + dev: true /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -3476,6 +3520,7 @@ packages: /shebang-regex@1.0.0: resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} engines: {node: '>=0.10.0'} + dev: true /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} @@ -3497,6 +3542,7 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 object-inspect: 1.13.1 + dev: true /siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -3504,6 +3550,7 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} @@ -3526,6 +3573,7 @@ packages: /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + dev: true /smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} @@ -3538,6 +3586,7 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 yargs: 15.4.1 + dev: true /sorcery@0.11.0: resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} @@ -3547,11 +3596,14 @@ packages: buffer-crc32: 0.2.13 minimist: 1.2.8 sander: 0.5.1 - dev: true /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} dev: true /spawndamnit@2.0.0: @@ -3559,27 +3611,33 @@ packages: dependencies: cross-spawn: 5.1.0 signal-exit: 3.0.7 + dev: true /spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 spdx-license-ids: 3.0.16 + dev: true /spdx-exceptions@2.3.0: resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true /spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} dependencies: spdx-exceptions: 2.3.0 spdx-license-ids: 3.0.16 + dev: true /spdx-license-ids@3.0.16: resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} + dev: true /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true /stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -3593,6 +3651,7 @@ packages: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: mixme: 0.5.10 + dev: true /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} @@ -3601,6 +3660,7 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + dev: true /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -3618,6 +3678,7 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 + dev: true /string.prototype.trimend@1.0.7: resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} @@ -3625,6 +3686,7 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 + dev: true /string.prototype.trimstart@1.0.7: resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} @@ -3632,12 +3694,14 @@ packages: call-bind: 1.0.5 define-properties: 1.2.1 es-abstract: 1.22.3 + dev: true /strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 + dev: true /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} @@ -3649,6 +3713,7 @@ packages: /strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} + dev: true /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} @@ -3686,12 +3751,14 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 + dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} dependencies: has-flag: 4.0.0 + dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -3707,10 +3774,10 @@ packages: fast-glob: 3.3.2 prettier: 2.8.8 rollup: 2.79.1 - rollup-plugin-svelte: 7.1.6(rollup@2.79.1)(svelte@4.2.7) - svelte: 4.2.7 - svelte-preprocess: 5.1.0(postcss@8.4.31)(svelte@4.2.7)(typescript@5.2.2) - typescript: 5.2.2 + rollup-plugin-svelte: 7.1.6(rollup@2.79.1)(svelte@4.2.8) + svelte: 4.2.8 + svelte-preprocess: 5.1.3(postcss@8.4.31)(svelte@4.2.8)(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - '@babel/core' - coffeescript @@ -3721,10 +3788,10 @@ packages: - sass - stylus - sugarss - dev: true + dev: false - /svelte-check@3.6.0(postcss@8.4.31)(svelte@4.2.7): - resolution: {integrity: sha512-8VfqhfuRJ1sKW+o8isH2kPi0RhjXH1nNsIbCFGyoUHG+ZxVxHYRKcb+S8eaL/1tyj3VGvWYx3Y5+oCUsJgnzcw==} + /svelte-check@3.6.2(postcss@8.4.31)(svelte@4.2.8): + resolution: {integrity: sha512-E6iFh4aUCGJLRz6QZXH3gcN/VFfkzwtruWSRmlKrLWQTiO6VzLsivR6q02WYLGNAGecV3EocqZuCDrC2uttZ0g==} hasBin: true peerDependencies: svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 @@ -3735,9 +3802,9 @@ packages: import-fresh: 3.3.0 picocolors: 1.0.0 sade: 1.8.1 - svelte: 4.2.7 - svelte-preprocess: 5.1.0(postcss@8.4.31)(svelte@4.2.7)(typescript@5.2.2) - typescript: 5.2.2 + svelte: 4.2.8 + svelte-preprocess: 5.1.3(postcss@8.4.31)(svelte@4.2.8)(typescript@5.3.3) + typescript: 5.3.3 transitivePeerDependencies: - '@babel/core' - coffeescript @@ -3750,25 +3817,25 @@ packages: - sugarss dev: true - /svelte-hmr@0.15.3(svelte@4.2.7): + /svelte-hmr@0.15.3(svelte@4.2.8): resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} engines: {node: ^12.20 || ^14.13.1 || >= 16} peerDependencies: svelte: ^3.19.0 || ^4.0.0 dependencies: - svelte: 4.2.7 + svelte: 4.2.8 dev: true - /svelte-preprocess@5.1.0(postcss@8.4.31)(svelte@4.2.7)(typescript@5.2.2): - resolution: {integrity: sha512-EkErPiDzHAc0k2MF5m6vBNmRUh338h2myhinUw/xaqsLs7/ZvsgREiLGj03VrSzbY/TB5ZXgBOsKraFee5yceA==} - engines: {node: '>= 14.10.0'} + /svelte-preprocess@5.1.3(postcss@8.4.31)(svelte@4.2.8)(typescript@5.3.3): + resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==} + engines: {node: '>= 16.0.0', pnpm: ^8.0.0} requiresBuild: true peerDependencies: '@babel/core': ^7.10.2 coffeescript: ^2.5.1 less: ^3.11.3 || ^4.0.0 postcss: ^7 || ^8 - postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 + postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 pug: ^3.0.0 sass: ^1.26.8 stylus: ^0.55.0 @@ -3799,28 +3866,27 @@ packages: dependencies: '@types/pug': 2.0.9 detect-indent: 6.1.0 - magic-string: 0.27.0 + magic-string: 0.30.5 postcss: 8.4.31 sorcery: 0.11.0 strip-indent: 3.0.0 - svelte: 4.2.7 - typescript: 5.2.2 - dev: true + svelte: 4.2.8 + typescript: 5.3.3 - /svelte2tsx@0.6.25(svelte@4.2.7)(typescript@5.2.2): - resolution: {integrity: sha512-hhBKL5X9gGvKQAZ9xLoHnbE9Yb00HxEZJlxcj2drxWK+Tpqcs/bnodjSfCGbqEhvNaUXYNbVL7s4dEXT+o0f6w==} + /svelte2tsx@0.6.27(svelte@4.2.8)(typescript@5.3.3): + resolution: {integrity: sha512-E1uPW1o6VsbRz+nUk3fznZ2lSmCITAJoNu8AYefWSvIwE2pSB01i5sId4RMbWNzfcwCQl1DcgGShCPcldl4rvg==} peerDependencies: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 dependencies: dedent-js: 1.0.1 pascal-case: 3.1.2 - svelte: 4.2.7 - typescript: 5.2.2 + svelte: 4.2.8 + typescript: 5.3.3 dev: true - /svelte@4.2.7: - resolution: {integrity: sha512-UExR1KS7raTdycsUrKLtStayu4hpdV3VZQgM0akX8XbXgLBlosdE/Sf3crOgyh9xIjqSYB3UEBuUlIQKRQX2hg==} + /svelte@4.2.8: + resolution: {integrity: sha512-hU6dh1MPl8gh6klQZwK/n73GiAHiR95IkFsesLPbMeEZi36ydaXL/ZAb4g9sayT0MXzpxyZjR28yderJHxcmYA==} engines: {node: '>=16'} dependencies: '@ampproject/remapping': 2.2.1 @@ -3836,16 +3902,15 @@ packages: locate-character: 3.0.0 magic-string: 0.30.5 periscopic: 3.1.0 - dev: true - /tailwind-merge@2.0.0: - resolution: {integrity: sha512-WO8qghn9yhsldLSg80au+3/gY9E4hFxIvQ3qOmlpXnqpDKoMruKfi/56BbbMg6fHTQJ9QD3cc79PoWqlaQE4rw==} + /tailwind-merge@2.2.0: + resolution: {integrity: sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==} dependencies: - '@babel/runtime': 7.23.2 + '@babel/runtime': 7.23.7 dev: false - /tailwindcss@3.3.5: - resolution: {integrity: sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==} + /tailwindcss@3.4.0: + resolution: {integrity: sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==} engines: {node: '>=14.0.0'} hasBin: true dependencies: @@ -3878,6 +3943,16 @@ packages: /term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + dev: true + + /test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + dev: true /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -3918,6 +3993,7 @@ packages: engines: {node: '>=0.6.0'} dependencies: os-tmpdir: 1.0.2 + dev: true /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -3937,6 +4013,7 @@ packages: /trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} + dev: true /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -3958,6 +4035,7 @@ packages: strip-ansi: 6.0.1 wcwidth: 1.0.1 yargs: 17.7.2 + dev: true /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} @@ -3967,14 +4045,17 @@ packages: /type-fest@0.13.1: resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} engines: {node: '>=10'} + dev: true /type-fest@0.6.0: resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} engines: {node: '>=8'} + dev: true /type-fest@0.8.1: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + dev: true /typed-array-buffer@1.0.0: resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} @@ -3983,6 +4064,7 @@ packages: call-bind: 1.0.5 get-intrinsic: 1.2.2 is-typed-array: 1.1.12 + dev: true /typed-array-byte-length@1.0.0: resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} @@ -3992,6 +4074,7 @@ packages: for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.12 + dev: true /typed-array-byte-offset@1.0.0: resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} @@ -4002,6 +4085,7 @@ packages: for-each: 0.3.3 has-proto: 1.0.1 is-typed-array: 1.1.12 + dev: true /typed-array-length@1.0.4: resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} @@ -4009,6 +4093,7 @@ packages: call-bind: 1.0.5 for-each: 0.3.3 is-typed-array: 1.1.12 + dev: true /typedoc-json-parser@9.0.1: resolution: {integrity: sha512-hvoISd8CMLn4iDXVebaUq32urRjoVtXMsZ1X2bmW1kaQolvVYZRw6NKXOdB1cLKzAxVWN9eHlg6HRduCCsfP7g==} @@ -4021,11 +4106,11 @@ packages: commander: 11.1.0 js-yaml: 4.1.0 tslib: 2.6.2 - typedoc: 0.25.3(typescript@5.2.2) - typescript: 5.2.2 + typedoc: 0.25.3(typescript@5.3.3) + typescript: 5.3.3 dev: true - /typedoc@0.25.3(typescript@5.2.2): + /typedoc@0.25.3(typescript@5.3.3): resolution: {integrity: sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw==} engines: {node: '>= 16'} hasBin: true @@ -4036,14 +4121,13 @@ packages: marked: 4.3.0 minimatch: 9.0.3 shiki: 0.14.5 - typescript: 5.2.2 + typescript: 5.3.3 dev: true - /typescript@5.2.2: - resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + /typescript@5.3.3: + resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} hasBin: true - dev: true /ufo@1.3.1: resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} @@ -4056,10 +4140,10 @@ packages: has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + dev: true /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true /undici@5.26.5: resolution: {integrity: sha512-cSb4bPFd5qgR7qr2jYAi0hlX9n5YKK2ONKkLFkxl+v/9BvC0sOpZjBHDBSXc5lWAf5ty9oZdRXytBIHzgUcerw==} @@ -4072,6 +4156,7 @@ packages: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} dependencies: '@types/unist': 3.0.2 + dev: true /unist-util-stringify-position@2.0.3: resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} @@ -4084,6 +4169,7 @@ packages: dependencies: '@types/unist': 3.0.2 unist-util-is: 6.0.0 + dev: true /unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} @@ -4091,10 +4177,12 @@ packages: '@types/unist': 3.0.2 unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + dev: true /universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + dev: true /update-browserslist-db@1.0.13(browserslist@4.22.1): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} @@ -4111,11 +4199,21 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true + /v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.20 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + dev: true + /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + dev: true /vfile-message@2.0.4: resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} @@ -4124,7 +4222,7 @@ packages: unist-util-stringify-position: 2.0.3 dev: true - /vite-node@0.33.0(@types/node@20.9.2): + /vite-node@0.33.0(@types/node@20.10.6): resolution: {integrity: sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==} engines: {node: '>=v14.18.0'} hasBin: true @@ -4134,7 +4232,7 @@ packages: mlly: 1.4.2 pathe: 1.1.1 picocolors: 1.0.0 - vite: 4.5.0(@types/node@20.9.2) + vite: 4.5.1(@types/node@20.10.6) transitivePeerDependencies: - '@types/node' - less @@ -4146,8 +4244,8 @@ packages: - terser dev: true - /vite@4.5.0(@types/node@20.9.2): - resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + /vite@4.5.1(@types/node@20.10.6): + resolution: {integrity: sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -4174,7 +4272,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.9.2 + '@types/node': 20.10.6 esbuild: 0.18.20 postcss: 8.4.31 rollup: 3.29.4 @@ -4182,7 +4280,7 @@ packages: fsevents: 2.3.3 dev: true - /vitefu@0.2.5(vite@4.5.0): + /vitefu@0.2.5(vite@4.5.1): resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -4190,7 +4288,7 @@ packages: vite: optional: true dependencies: - vite: 4.5.0(@types/node@20.9.2) + vite: 4.5.1(@types/node@20.10.6) dev: true /vitest@0.33.0: @@ -4226,7 +4324,7 @@ packages: dependencies: '@types/chai': 4.3.10 '@types/chai-subset': 1.3.5 - '@types/node': 20.9.2 + '@types/node': 20.10.6 '@vitest/expect': 0.33.0 '@vitest/runner': 0.33.0 '@vitest/snapshot': 0.33.0 @@ -4245,8 +4343,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.6.0 - vite: 4.5.0(@types/node@20.9.2) - vite-node: 0.33.0(@types/node@20.9.2) + vite: 4.5.1(@types/node@20.10.6) + vite-node: 0.33.0(@types/node@20.10.6) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -4270,6 +4368,7 @@ packages: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 + dev: true /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -4290,9 +4389,11 @@ packages: is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 + dev: true /which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: true /which-pm@2.0.0: resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} @@ -4300,6 +4401,7 @@ packages: dependencies: load-yaml-file: 0.2.0 path-exists: 4.0.0 + dev: true /which-typed-array@1.1.13: resolution: {integrity: sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==} @@ -4310,12 +4412,14 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 + dev: true /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true dependencies: isexe: 2.0.0 + dev: true /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} @@ -4341,6 +4445,7 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: true /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -4349,6 +4454,7 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 + dev: true /wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} @@ -4361,17 +4467,19 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: true /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + dev: true /yallist@2.1.2: resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} + dev: true /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -4387,10 +4495,12 @@ packages: dependencies: camelcase: 5.3.1 decamelize: 1.2.0 + dev: true /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + dev: true /yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} @@ -4407,6 +4517,7 @@ packages: which-module: 2.0.1 y18n: 4.0.3 yargs-parser: 18.1.3 + dev: true /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} @@ -4419,10 +4530,12 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 + dev: true /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + dev: true /yocto-queue@1.0.0: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==}