Using only headless ui.

This commit is contained in:
Bradley Shellnut 2022-05-15 23:42:50 -07:00
parent 36d829c1a6
commit 94b932284d
18 changed files with 757 additions and 2409 deletions

View file

@ -12,14 +12,14 @@
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
},
"devDependencies": {
"@playwright/test": "^1.21.1",
"@playwright/test": "^1.22.0",
"@rgossiaux/svelte-headlessui": "1.0.0-beta.12",
"@sveltejs/adapter-auto": "next",
"@sveltejs/adapter-auto": "1.0.0-next.42",
"@sveltejs/kit": "1.0.0-next.326",
"@types/cookie": "^0.5.1",
"@types/node": "^17.0.31",
"@typescript-eslint/eslint-plugin": "^5.22.0",
"@typescript-eslint/parser": "^5.22.0",
"@types/node": "^17.0.33",
"@typescript-eslint/eslint-plugin": "^5.23.0",
"@typescript-eslint/parser": "^5.23.0",
"carbon-components-svelte": "^0.63.8",
"carbon-icons-svelte": "^11.0.1",
"eslint": "^8.15.0",
@ -27,6 +27,7 @@
"eslint-plugin-svelte3": "^3.4.1",
"prettier": "^2.6.2",
"prettier-plugin-svelte": "^2.7.0",
"sass": "^1.51.0",
"svelte": "^3.48.0",
"svelte-check": "^2.7.0",
"svelte-preprocess": "^4.10.6",
@ -38,7 +39,6 @@
"@fontsource/fira-mono": "^4.5.8",
"@lukeed/uuid": "^2.0.0",
"cookie": "^0.5.0",
"node-sass": "^7.0.1",
"zod": "^3.15.1"
"zod": "^3.16.0"
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="Svelte demo app" />
<link rel="icon" href="%svelte.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%svelte.head%
</head>
<body>
<div id="svelte">%svelte.body%</div>
</body>
</html>
<head>
<meta charset="utf-8" />
<meta name="description" content="Svelte demo app" />
<link rel="icon" href="%svelte.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
const htmlElement = document.documentElement
const userTheme = localStorage.theme
const userFont = localStorage.font
// check if the user set a theme
if (userTheme) {
htmlElement.dataset.theme = userTheme
}
// otherwise check for user preference
if (!userTheme && prefersDarkMode) {
htmlElement.dataset.theme = '🌛 Night'
localStorage.theme = '🌛 Night'
}
if (!userTheme && prefersLightMode) {
htmlElement.dataset.theme = '☀️ Daylight'
localStorage.theme = '☀️ Daylight'
}
// if nothing is set default to dark mode
if (!userTheme && !prefersDarkMode && !prefersLightMode) {
htmlElement.dataset.theme = '🌛 Night'
localStorage.theme = '🌛 Night'
}
</script>
%svelte.head%
</head>
<body>
<div id="svelte">%svelte.body%</div>
</body>
</html>

View file

@ -0,0 +1,147 @@
<script lang="ts">
import { fade } from 'svelte/transition';
import { browser } from '$app/env';
import {
Listbox,
ListboxButton,
ListboxOption,
ListboxOptions
} from '@rgossiaux/svelte-headlessui';
const themes = {
'🌛 Night': { name: '🌛 Night' },
'☀️ Daylight': { name: '☀️ Daylight' },
'😎 Synthwave': { name: '😎 Synthwave' }
};
let selectedTheme = getTheme() ?? themes['🌛 Night'];
function getTheme() {
if (!browser) return;
const htmlElement = document.documentElement;
const userTheme = localStorage.theme;
const prefersDarkMode = window.matchMedia('prefers-color-scheme: dark').matches;
const prefersLightMode = window.matchMedia('prefers-color-scheme: light').matches;
// check if the user set a theme
if (userTheme) {
htmlElement.dataset.theme = userTheme;
return themes[userTheme];
}
// otherwise check for user preference
if (!userTheme && prefersDarkMode) {
htmlElement.dataset.theme = '🌛 Night';
localStorage.theme = '🌛 Night';
}
if (!userTheme && prefersLightMode) {
htmlElement.dataset.theme = '☀️ Daylight';
localStorage.theme = '☀️ Daylight';
}
// if nothing is set default to dark mode
if (!userTheme && !prefersDarkMode && !prefersLightMode) {
htmlElement.dataset.theme = '🌛 Night';
localStorage.theme = '🌛 Night';
}
return themes[userTheme];
}
function handleChange(event: CustomEvent) {
selectedTheme = themes[event.detail.name];
const htmlElement = document.documentElement;
htmlElement.dataset.theme = selectedTheme.name;
localStorage.theme = selectedTheme.name;
}
</script>
<div class="theme">
<span>Theme</span>
<div class="listbox">
<Listbox value={selectedTheme} on:change={handleChange} let:open>
<ListboxButton class="button">
<span>{selectedTheme.name}</span>
<span>
<svg
width="20"
height="20"
class="arrows"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</span>
</ListboxButton>
{#if open}
<div transition:fade={{ duration: 100 }}>
<ListboxOptions class="options" static>
{#each Object.entries(themes) as [key, theme] (key)}
<ListboxOption value={theme} let:active let:selected>
<span class="option" class:active class:selected>
{theme.name}
</span>
</ListboxOption>
{/each}
</ListboxOptions>
</div>
{/if}
</Listbox>
</div>
</div>
<style>
.listbox {
--width: 184px;
}
.listbox :global(.button) {
width: var(--width);
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-16) var(--spacing-24);
font-weight: 700;
background-color: var(--clr-primary);
color: var(--clr-theme-txt);
border-radius: var(--rounded-20);
box-shadow: var(--shadow-sm);
}
.listbox :global(.arrows) {
width: 20px;
height: 20px;
display: block;
}
.listbox :global(.options) {
width: var(--width);
position: absolute;
margin-top: 0.4rem;
font-weight: 700;
color: var(--clr-theme-txt);
background-color: var(--clr-primary);
border-radius: var(--rounded-20);
box-shadow: var(--shadow-sm);
list-style: none;
}
.listbox :global(.option) {
display: block;
padding: var(--spacing-16) var(--spacing-24);
border-radius: var(--rounded-20);
cursor: pointer;
}
.listbox :global(.active) {
background-color: var(--clr-theme-active);
}
</style>

View file

@ -6,7 +6,8 @@
// } from "carbon-components-svelte";
// import type { CarbonTheme } from "carbon-components-svelte/types/Theme/Theme.svelte";
import { page } from '$app/stores';
import Toggle from '$root/components/toggle.svelte';
import Themes from '$lib/components/preferences/themes.svelte';
import Toggle from '$lib/components/toggle.svelte';
import logo from './svelte-logo.svg';
// let theme: CarbonTheme = "white";
@ -34,6 +35,7 @@
<div>
<Toggle />
</div>
<div><Themes /></div>
<ul>
<li class:active={$page.url.pathname === '/'}><a sveltekit:prefetch href="/">Home</a></li>
<li class:active={$page.url.pathname === '/about'}>

View file

@ -1,21 +1,32 @@
<script lang="ts">
import Header from '$lib/header/Header.svelte';
import '$root/styles/global.css';
import 'carbon-components-svelte/css/all.css';
import '../app.css';
// import 'carbon-components-svelte/css/all.css';
import '$root/styles/styles.scss';
</script>
<Header />
<main>
<slot />
</main>
<footer>
<p>Built by <a target="__blank" href="https://bradleyshellnut.com">Bradley Shellnut</a></p>
</footer>
<div class="fade" style:animation-duration="250ms" style:animation-delay="250ms">
<Header />
<main>
<slot />
</main>
<footer>
<p>Built by <a target="__blank" href="https://bradleyshellnut.com">Bradley Shellnut</a></p>
</footer>
</div>
<style>
.fade {
animation-name: fadeIn;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
main {
flex: 1;
display: flex;

View file

@ -1,5 +1,5 @@
<script lang="ts">
import Listbox from '$root/components/listbox.svelte';
import Listbox from '$lib/components/listbox.svelte';
</script>
<Listbox />

View file

@ -3,10 +3,10 @@
</script>
<script lang="ts">
import { Checkbox, NumberInput } from 'carbon-components-svelte';
import Game from '$root/components/game.svelte';
// import { Checkbox, NumberInput } from 'carbon-components-svelte';
import Game from '$lib/components/game.svelte';
import type { GameType } from '$lib/types';
import Listbox from '$root/components/listbox.svelte';
import Listbox from '$lib/components/listbox.svelte';
// import { enhance } from "$lib/form";
let games: GameType[] = [];
@ -44,23 +44,38 @@
<form on:submit|preventDefault={handleSubmit} method="post">
<fieldset aria-busy={submitting} disabled={submitting}>
<div>
<NumberInput
<label htmlfor="minAge">
<input id="minAge" name="minAge" bind:value={minAge} type="number" min={0} max={120} />
Min Age
</label>
<!-- <NumberInput
name="minAge"
min={0}
max={120}
bind:value={minAge}
invalidText="Number must be between 0 and 120"
label="Min Age"
/>
<Checkbox
/> -->
<!-- <Checkbox
name="exactMinAge"
bind:checked={exactMinAge}
bind:value={exactMinAge}
labelText="Search exact?"
/>
/> -->
</div>
<div>
<NumberInput
<label htmlfor="maxPlayers">
<input
id="maxPlayers"
name="maxPlayers"
bind:value={maxPlayers}
type="number"
min={0}
max={50}
/>
Min Age
</label>
<!-- <NumberInput
name="minPlayers"
min={1}
max={50}
@ -68,10 +83,21 @@
invalidText="Number must be between 1 and 50"
label="Min Players"
/>
<Checkbox name="exactMinPlayers" labelText="Search exact?" bind:checked={exactMinPlayers} />
<Checkbox name="exactMinPlayers" labelText="Search exact?" bind:checked={exactMinPlayers} /> -->
</div>
<div>
<NumberInput
<label htmlfor="maxPlayers">
<input
id="maxPlayers"
name="maxPlayers"
bind:value={maxPlayers}
type="number"
min={0}
max={50}
/>
Min Age
</label>
<!-- <NumberInput
name="maxPlayers"
min={1}
max={50}
@ -79,7 +105,7 @@
invalidText="Number must be between 1 and 50"
label="Max Players"
/>
<Checkbox name="exactMaxPlayers" labelText="Search exact?" bind:checked={exactMaxPlayers} />
<Checkbox name="exactMaxPlayers" labelText="Search exact?" bind:checked={exactMaxPlayers} /> -->
</div>
</fieldset>
<button type="submit" disabled={submitting}>Submit</button>

View file

@ -2,14 +2,6 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
:root {
--color-brand: hsl(204 88% 53%);
--color-text-primary: hsl(0 0% 98%);
@ -103,6 +95,40 @@
--borderRadiusLarge: 10px;
--maxWidth: 1200px;
/* Font */
--font-sans: 'Poppins', sans-serif;
--font-serif: 'Arsenica', serif;
--font-mono: Source Code Pro, monospace;
--font-dyslexic: OpenDyslexic, sans-serif;
--font-dyslexic-mono: OpenDyslexic Mono, monospace;
--font-16: 1.6rem;
--font-24: 2.4rem;
--font-32: 3.2rem;
--font-48: 4.8rem;
--font-96: 9.6rem;
/* Spacing */
--spacing-4: 0.4rem;
--spacing-8: 0.8rem;
--spacing-16: 1.6rem;
--spacing-24: 2.4rem;
--spacing-32: 3.2rem;
--spacing-64: 6.4rem;
--spacing-128: 12.8rem;
/* Scrollbar */
--clr-scrollbar-thumb: hsl(173 10% 20%);
/* Shadows */
--shadow-sm: 0px 0px 4px 4px hsl(0 0% 0% / 4%);
--shadow-md: 0px 0px 10px 4px hsl(0 0% 0% / 10%);
--shadow-lg: 0px 0px 20px 8px hsl(0 0% 0% / 20%);
/* Border radius */
--rounded-4: 4px;
--rounded-20: 20px;
/* Media Queryies - Not yet supported in CSS */
/*
--xsmall: 340px;
@ -167,8 +193,8 @@ label {
}
input {
padding: var(--spacing-16);
font-size: var(--font-24);
padding: var(--spacing-8);
font-size: var(--font-16);
border-radius: var(--radius-base);
border: none;
}

58
src/styles/reset.scss Normal file
View file

@ -0,0 +1,58 @@
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
iframe,
video {
width: 100%;
border: none;
aspect-ratio: 16 / 9;
}
input,
button,
textarea,
select {
font: inherit;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
button,
input {
font: inherit;
color: inherit;
border: none;
}
button {
font: inherit;
background: none;
cursor: pointer;
}
ul,
ol {
list-style: none;
}

3
src/styles/styles.scss Normal file
View file

@ -0,0 +1,3 @@
@use 'reset.scss';
@use 'global.scss';
@use 'theme.scss';

67
src/styles/theme.scss Normal file
View file

@ -0,0 +1,67 @@
html[data-theme='🌛 Night'] {
/* Global */
--clr-primary: hsl(173 100% 66%);
--clr-txt: hsl(0 0% 98%);
--clr-bg: hsl(210 7% 11%);
--bg: radial-gradient(hsl(173 100% 4%), var(--clr-bg));
--bg-opacity: 0.7;
/* Menu */
--clr-menu-text: hsl(0 0% 78%);
--clr-menu-bg: linear-gradient(180deg,
hsl(180 7% 14%) 0%,
hsl(216 7% 14%) 100%);
--clr-menu-arrow-bg: hsl(180 7% 14%);
--clr-menu-border: hsl(0 0% 19%);
--clr-theme-txt: hsl(177 100% 15%);
--clr-theme-active: hsl(177 100% 80%);
--clr-switch-on-bg: hsl(0 0% 24%);
--clr-switch-off-bg: hsl(0 0% 10%);
/* Hero */
--clr-hero-txt: hsl(174 27% 73%);
--clr-hero-bg: linear-gradient(270deg,
hsl(210 15% 13%) 43%,
hsl(176 19% 15%) 66%);
--clr-hero-divider-bg: hsl(0 0% 21%);
--clr-input-txt: hsl(177 100% 15%);
--clr-input-bg: hsl(210 13% 24%);
--clr-input-placeholder-txt: hsl(210 13% 50%);
--clr-input-border: hsl(0 0% 21%);
/* Card */
--clr-card-bg: linear-gradient(180deg,
hsl(180 7% 14%) 0%,
hsl(216 7% 14%) 100%);
--clr-card-txt: hsl(0 0% 78%);
/* Link */
--clr-link-txt: hsl(0 100% 98%);
--clr-link-background: hsl(0 0% 4%);
/* Footer */
--clr-footer-txt: hsl(0 0% 78%);
--clr-footer-bg: hsl(210 5% 7%);
/* Post */
--post-overlay-bg: radial-gradient(hsl(173 100% 4% / 80%), var(--clr-bg));
--post-blockquote-txt: hsl(173 100% 94%);
--post-blockquote-bg: hsl(173 60% 4%);
--post-blockquote-border: hsl(173 10% 10%);
--clr-code-bg: hsl(173 60% 4%);
--clr-code-title: hsl(173 100% 94%);
--clr-code-border: hsl(173 10% 10%);
--clr-code-line-number: hsl(173 20% 20%);
--clr-code-line-highlight: hsl(173 40% 8%);
--clr-code-inline-txt: hsl(173 100% 94%);
--clr-code-inline-bg: hsl(173 60% 4%);
--clr-token-1: hsl(173 100% 66%);
--clr-token-2: hsl(180 60% 80%);
--clr-token-3: hsl(173 100% 66%);
--clr-token-4: hsl(0 0% 98%);
--clr-token-5: hsl(173 10% 60%);
}

View file

@ -6,10 +6,7 @@ import path from 'path';
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess({
scss: {},
}),
preprocess: preprocess(),
kit: {
adapter: adapter(),
vite: {