Skip to content

Commit

Permalink
Theme generator (#192)
Browse files Browse the repository at this point in the history
* Rename `cssVars` action to `styleVars` and do not prefix properties with `--` by default (more flexible)

* [SelectField] Fix toggling display of options menu using toggleIcon. Ignore toggling when clicking on SelectField border.  Support hiding toggleIcon (`<SelectField toggleIcon={null} />

* [SelectField] Add `stepper` prop to iterate through options (like `MenuField`)

* [MenuField] Expose `selected` option via prop (similar to `SelectField`)

* [SelectField Add stepper example

* Move `processThemeColors()` from tailwind plugin to $lib/styles/theme to allow calling at runtime (theme generator frontend).  Add types

* Update skeleton.ts to match skeleton.cjs (to be removed)

* Beginning work of theme generator

* Read themes from `themes.json` file for both tailwind config and theme selector.  Remove daisy/skeleton commonjs modules.  Add `getThemeNames` to split based on `color-scheme`.  Ultimately simplifies a lot

* Add "Copy all" daisy and skeleton options

* Use <ThemeSelect> or <ThemeSwitch> based on more than 1 light/dark theme

* Fix skeleton dark themes after refactor

* Add explicit daisy themeName list to hopefully fix build (similar to skeleton)

* Set initial theme selections (fix reactivity infinite loop)

* [SelectField] Use `selectValue(...)` instead of `value = ...` so `change` is dispatched (and other consistent updating)

* Change light/dark preview based on which input was last changed

* Support overriding doc themes wtih generator (custom) themes

* Fix setting `prefers-color-scheme: dark` override

* Use a local copy of Skeleton themes to fix Cloudflare build (work around Node.js runtime issue)

* Improve handling of `-50` shade when `-100` exists (ex. Skeleton)

* Update site dark/light mode with preview for better experience (previewing and applying)

* Support custom Ior exisitng) theme editing

* Add state colors and support showing/hiding optoinal colors

* Add "Copy all themes" menu item

* [ColorField] Support `hex` entry

* Register all themes (daisy + skeleton)

* Format files (fix lint error)

* Add changeset
  • Loading branch information
techniq authored Jan 10, 2024
1 parent 44f07aa commit 7dfc008
Show file tree
Hide file tree
Showing 43 changed files with 4,286 additions and 592 deletions.
5 changes: 5 additions & 0 deletions .changeset/cool-hotels-own.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-ux": patch
---

[SelectField] Add `stepper` prop to iterate through options (like `MenuField`)
5 changes: 5 additions & 0 deletions .changeset/fair-trees-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-ux": patch
---

[MenuField] Expose `selected` option via prop (similar to `SelectField`)
5 changes: 5 additions & 0 deletions .changeset/quick-carrots-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-ux": minor
---

Add theme selection/creation page and simplify loading themes
5 changes: 5 additions & 0 deletions .changeset/selfish-hounds-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-ux": patch
---

[SelectField] Fix toggling display of options menu using toggleIcon. Support hiding toggleIcon (`<SelectField toggleIcon={null} />
5 changes: 5 additions & 0 deletions .changeset/yellow-nails-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-ux': minor
---

Rename `cssVars` action to `styleVars` and do not prefix properties with `--` by default (more flexible)
1 change: 1 addition & 0 deletions packages/svelte-ux/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@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.12",
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte-ux/src/lib/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './cssVars';
export * from './dataBackground';
export * from './input';
export * from './layout';
Expand All @@ -9,4 +8,5 @@ export * from './portal';
export * from './scroll';
export * from './spotlight';
export * from './sticky';
export * from './styleProps';
export * from './table';
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
}
});

Expand All @@ -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];
Expand Down
27 changes: 10 additions & 17 deletions packages/svelte-ux/src/lib/components/Grid.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
<script lang="ts">
import { cssVars } from '../actions/cssVars';
export let columns = 0;
export let gap = 0;
export let columnGap = gap;
Expand Down Expand Up @@ -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}
>
Expand Down
1 change: 1 addition & 0 deletions packages/svelte-ux/src/lib/components/MenuField.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
const settingsClasses = getComponentClasses('MenuField');
let open = false;
export let selected: any = undefined;
$: selected = options?.find((x) => x.value === value);
$: previous = () => {
Expand Down
72 changes: 65 additions & 7 deletions packages/svelte-ux/src/lib/components/SelectField.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
Expand All @@ -53,6 +54,9 @@
]
: undefined;
/** If true, show left/right buttons to step through options */
export let stepper = false;
let originalIcon = icon;
export let scrollIntoView: Partial<ScrollIntoViewOptions> = {};
Expand All @@ -78,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 = '';
Expand Down Expand Up @@ -157,6 +160,7 @@
// Elements
let inputEl: HTMLInputElement | null = null;
let menuOptionsEl: HTMLDivElement;
let selectFieldEl: HTMLButtonElement;
// UI state
export let open = false;
Expand Down Expand Up @@ -219,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 {
Expand Down Expand Up @@ -358,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);
Expand All @@ -374,6 +402,7 @@
classes.root,
$$props.class
)}
bind:this={selectFieldEl}
on:click={onClick}
>
<TextField
Expand Down Expand Up @@ -403,7 +432,21 @@
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" />
Expand All @@ -424,14 +467,29 @@
clear();
}}
/>
{:else if !inlineOptions}
{:else if toggleIcon}
<Button
icon={toggleIcon}
class="text-surface-content/50 p-1 transform {open ? 'rotate-180' : ''}"
tabindex="-1"
on:click={() => {
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>
Expand Down
17 changes: 6 additions & 11 deletions packages/svelte-ux/src/lib/components/Steps.svelte
Original file line number Diff line number Diff line change
@@ -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}>
Expand Down
Loading

0 comments on commit 7dfc008

Please sign in to comment.