fuz
design system for CSS, Svelte, and SvelteKit
npm i -D @fuz.dev/fuz

theme

Themed adds global support for both the browser's color-scheme and custom themes based on CSS variables. Themed is a singleton component that's mounted at the top-level of the page:

import Themed from
	'@fuz.dev/fuz/Themed.svelte';
<!-- +layout.svelte -->
<Themed>
	<slot />
</Themed>
why the singleton?
why nest the slot?

color scheme

Themed defaults to automatic color-scheme detection with prefers-color-scheme, and users can also set it directly:

import Color_Scheme_Input from
	'@fuz.dev/fuz/Color_Scheme_Input.svelte';
<Color_Scheme_Input />

Pass a prop to override the default:

<Color_Scheme_Input
	selected_color_scheme={writable(null)}
/>

The builtin themes support both dark and light color schemes. Custom themes may support one or both color schemes.

more about Color_Scheme_Input

themes

A theme is a simple JSON collection of variables that can be transformed into CSS that set CSS variables. Each variable can have values for light and/or dark color schemes.

  • scoped themes

    โš ๏ธ scoped themes are a work in progress

    Scope a theme to one branch of the DOM tree with Themed_Scope:

    import Themed_Scope from
    	'@fuz.dev/fuz/Themed_Scope.svelte';
    <Themed_Scope {selected_theme}>
    		...
    </Themed_Scope>
    the base theme
    the low contrast theme
    the high contrast theme
    the base theme
    the low contrast theme
    the high contrast theme

    theme usage

    Themes are plain CSS that can be sourced in a variety of ways.

    To use fuz's base theme:

    <!-- +layout.svelte -->
    <script>
    	import '@fuz.dev/fuz/style.css';
    	import '@fuz.dev/fuz/theme.css';
    	import Themed from '@fuz.dev/fuz/Themed.svelte';
    <script>
    
    <!-- enable theme and color-scheme support -->
    <Themed>
    	<slot />
    </Themed>

    Themed can be customized with the nonreactive, bindable, writable store props selected_theme and selected_color_scheme:

    <Themed {selected_theme} {selected_color_scheme}>
    	<slot />
    </Themed>

    Themed sets the writable stores selected_theme and selected_color_scheme in the Svelte context:

    // get values from the Svelte context provided by
    // the nearest `Themed` or `Themed_Scope` ancestor:
    
    import {get_theme} from '@fuz.dev/fuz/theme.js';
    const selected_theme = get_theme();
    $selected_theme.name; // 'base'
    
    import {get_color_scheme} from '@fuz.dev/fuz/theme.js';
    const selected_color_scheme = get_color_scheme();
    $selected_color_scheme; // 'null'

    more about Themed

    theme: base

    this is an h2 inside .prose

    blockquote
    • a
    • b
    • c

    p and code with links

    another p with .width_sm so it will wrap any moment now and there we have multiple lines of text

    another p with .width_sm so it will wrap any moment now and there we have multiple lines of text

    another p with .width_sm so it will wrap any moment now and there we have multiple lines of text

    summary and details details content

    form

    a legend in a fieldset
    .buttonlike with .selected
    .buttonlike with .selected and .deselectable

    elements

    styles for HTML elements

    ๐Ÿ‘† blockquote

    ๐Ÿ‘‡ hr ๐Ÿ‘ˆ code


    Click me, a summary, to see the rest of the details

    so many details

    <details>
    	<summary>
    		Click me, a <code>summary</code>,
    		to see the rest of the <code>details</code>
    	</summary>
    	<Code code={'...'} />
    </details>

    table

    this is unfinished and will change
    <table>
    	<thead>
    		<th>th</th>
    		<th>th</th>
    		<th>th</th>
    	</thead>
    	<tbody>
    		<tr><td>td</td><td>td</td><td>td</td></tr>
    		<tr><td>td</td><td>td</td><td>td</td></tr>
    		<tr><td>td</td><td>td</td><td>td</td></tr>
    	</tbody>
    </table>
    th th th
    tdtdtd
    tdtdtd
    tdtdtd
    <table class="width_full">
    	...
    </table>
    th th th
    tdtdtd
    tdtdtd
    tdtdtd

    forms

    <form>
    	<fieldset>
    		<legend>
    			a <code>legend</code>
    			in a <code>fieldset</code>
    		</legend>
    		<label>
    			<div class="title">
    				username
    			</div>
    			<input
    				bind:value={username}
    				placeholder=">"
    			/>
    		</label>
    		...
    	</fieldset>
    	...
    </form>

    a legend in a fieldset

    More info can be included in <p> tags like this one. Here we could include info about passwords.


    form with range input

    <input type="range" />
    <input type="range" disabled />

    form with checkboxes


    form with radio buttons


    disabled button

    <button disabled>
    	:|
    </button>
    <button disabled>
    	a bigger disabled button
    </button>

    button with CSS class .selected

    <button class="selected">...</button>

    .selected buttons with the .deselectable class continue to be clickable when selected:

    <button class="selected deselectable">
    	...
    </button>

    .plain and .icon_button


    <button class="plain">
    	+
    </button>

    <button class="icon_button">
    	+
    </button>

    <button class="plain icon_button">
    	+
    </button>

    disabled variants


    <button class="plain" disabled>
    	+
    </button>

    <button class="icon_button" disabled>
    	+
    </button>

    <button class="plain icon_button" disabled>
    	+
    </button>

    .selected variants


    <button class="plain selected">
    	+
    </button>

    <button class="icon_button selected">
    	+
    </button>

    <button class="plain icon_button selected">
    	+
    </button>

    .selected and .deselectable variants


    <button class="plain selected deselectable">
    	+
    </button>

    <button class="icon_button selected deselectable">
    	+
    </button>

    <button class="plain icon_button selected deselectable">
    	+
    </button>


    .buttonlike CSS class

    the .buttonlike class is useful when you want interactive builtin elements to be wrapped in a larger clickable area:

    <label class="buttonlike">
    	<input type="checkbox" />...
    </label>
    <label class="buttonlike disabled">...</label>
    <div class="buttonlike selected padded_md">...</div>
    .buttonlike with .selected
    <div class="buttonlike deselectable selected padded_md">...</div>
    .buttonlike with .selected and .deselectable
    TODO: add more deselectable signifiers?

    icon sizes

    the --icon_size variable's variants

    unlike --size_ variables, --icon_ variables are in px not rem, so they're insensitive to browser font size
    --icon_size_xs: 18px
    ๐Ÿข
    --icon_size_sm: 32px
    ๐Ÿข
    --icon_size_md: 48px
    ๐Ÿข
    --icon_size_lg: 80px
    ๐Ÿข
    --icon_size_1: 128px
    ๐Ÿข
    --icon_size_2: 196px
    ๐Ÿข
    --icon_size_3: 316px
    ๐Ÿข
    --icon_size_4: 512px
    ๐Ÿข

    prose

    the .prose CSS class styles HTML elements for document-like presentation

    ul inside .prose

    • a
    • b
    • see

    ul without a .prose ancestor

    • a
    • b
    • see

    a links are inline inside .prose

    this link is inline

    a without a .prose ancestor

    outside of .prose links are normally blocks

    headings and other elements have no margin by default:

    h1

    h2

    h3

    h4

    h5
    h6

    p

    small

    p sub p sup p

    blockquote
    footer

    but they do inside .prose:

    h1

    h2

    h3

    h4

    h5
    h6

    p

    small

    p sub p sup p

    blockquote
    footer

    typography

    h1

    h2

    h3

    h4

    h5
    h6

    p

    small

    p sub p sup p

    --size_xs

    --size_sm

    --size_md

    --size_lg

    --size_1

    --size_2

    --size_3

    --size_4

    --size_5

    --size_6

    --size_7

    --size_8

    --size_9

    font-weight

    100
    200
    300
    400
    500
    600
    700
    800
    900
    950
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_xs
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_sm
    --size_md
    --size_md
    --size_md
    --size_md
    --size_md
    --size_md
    --size_md
    --size_md
    --size_md
    --size_md
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_lg
    --size_1
    --size_1
    --size_1
    --size_1
    --size_1
    --size_1
    --size_1
    --size_1
    --size_1
    --size_1
    --size_2
    --size_2
    --size_2
    --size_2
    --size_2
    --size_2
    --size_2
    --size_2
    --size_2
    --size_2
    --size_3
    --size_3
    --size_3
    --size_3
    --size_3
    --size_3
    --size_3
    --size_3
    --size_3
    --size_3
    --size_4
    --size_4
    --size_4
    --size_4
    --size_4
    --size_4
    --size_4
    --size_4
    --size_4
    --size_4
    --size_5
    --size_5
    --size_5
    --size_5
    --size_5
    --size_5
    --size_5
    --size_5
    --size_5
    --size_5
    --size_6
    --size_6
    --size_6
    --size_6
    --size_6
    --size_6
    --size_6
    --size_6
    --size_6
    --size_6
    --size_7
    --size_7
    --size_7
    --size_7
    --size_7
    --size_7
    --size_7
    --size_7
    --size_7
    --size_7
    --size_8
    --size_8
    --size_8
    --size_8
    --size_8
    --size_8
    --size_8
    --size_8
    --size_8
    --size_8
    --size_9
    --size_9
    --size_9
    --size_9
    --size_9
    --size_9
    --size_9
    --size_9
    --size_9
    --size_9

    variables

    170 theme variables
    export interface Theme {
    	// TODO probably need an `id`
    	// id: string;
    	name: string;
    	items: Theme_Variable[];
    }
    
    export interface Theme_Variable {
    	name: string;
    	light?: string;
    	dark?: string;
    	summary?: string;
    }
    ๐Ÿ•ธ

    variables are snake_case so they're also valid js identifiers