Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/site-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@
"@shikijs/twoslash": "^1.22.0",
"esm-env": "^1.0.0",
"json5": "^2.2.3",
"shiki": "^1.22.0",
"svelte-persisted-store": "^0.9.2"
"shiki": "^1.22.0"
},
"devDependencies": {
"@sveltejs/kit": "^2.12.1",
Expand Down
9 changes: 4 additions & 5 deletions packages/site-kit/src/lib/actions/legacy-details.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { page } from '$app/stores';
import { persisted } from 'svelte-persisted-store';
import { get } from 'svelte/store';
import { fix_position } from './utils';
import { Persisted } from '../state';

const show_legacy = persisted('svelte:show-legacy', true);
const show_legacy = new Persisted<'open' | 'closed'>('sv:show-legacy', 'open');

export function legacy_details(node: HTMLElement) {
function update() {
Expand All @@ -16,7 +15,7 @@ export function legacy_details(node: HTMLElement) {
}

const details = node.querySelectorAll('details.legacy') as NodeListOf<HTMLDetailsElement>;
const show = get(show_legacy);
const show = show_legacy.current === 'open';

/** Whether the toggle was initiated by user action or `element.open = !element.open` */
let secondary = false;
Expand All @@ -29,7 +28,7 @@ export function legacy_details(node: HTMLElement) {
if (secondary) return;
secondary = true;

show_legacy.set(detail.open);
show_legacy.current = detail.open ? 'open' : 'closed';

fix_position(detail, () => {
for (const other of details) {
Expand Down
12 changes: 8 additions & 4 deletions packages/site-kit/src/lib/components/Banner.svelte
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<script lang="ts">
import { quintOut } from 'svelte/easing';
import { fade } from 'svelte/transition';
import { persisted } from 'svelte-persisted-store';
import Icon from './Icon.svelte';
import type { BannerData } from '../types';
import { browser } from '$app/environment';
import { Persisted } from '../state';

let { banner }: { banner: BannerData } = $props();

const hidden = persisted<Record<string, boolean>>('svelte:hidden-banners', {});
const persisted = new Persisted<string>('sv:hidden-banners', '{}');
const hidden = $derived(JSON.parse(persisted.current));
const time = +new Date();

let visible = $derived(
browser && !$hidden[banner.id] && time > +banner.start && time < +banner.end
browser && !hidden[banner.id] && time > +banner.start && time < +banner.end
);

$effect(() => {
Expand Down Expand Up @@ -40,7 +41,10 @@
aria-label="Dismiss"
class="raised primary"
onclick={() => {
$hidden[banner.id] = true;
persisted.current = JSON.stringify({
...hidden,
[banner.id]: true
});
}}
>
<Icon name="close" />
Expand Down
6 changes: 3 additions & 3 deletions packages/site-kit/src/lib/components/Text.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { afterNavigate } from '$app/navigation';
import type { Snippet } from 'svelte';
import { prefers_ts } from '../stores/prefers_ts';
import { code_preference } from '../state/code_preference';
import { fix_position } from '../actions/utils';

let { children }: { children: Snippet } = $props();
Expand All @@ -14,14 +14,14 @@
const inputs = container.querySelectorAll('.ts-toggle') as NodeListOf<HTMLInputElement>;

for (const input of inputs) {
input.checked = $prefers_ts;
input.checked = code_preference.current === 'typescript';
}
}

function toggle(e: Event) {
if ((e.target as HTMLElement).classList.contains('ts-toggle')) {
const input = e.target as HTMLInputElement;
$prefers_ts = input.checked;
code_preference.current = input.checked ? 'typescript' : 'javascript';
fix_position(input, update);
}
}
Expand Down
7 changes: 4 additions & 3 deletions packages/site-kit/src/lib/nav/Nav.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ Top navigation bar for the application. It provides a slot for the left side, th
-->

<script lang="ts">
import { overlay_open, searching, on_this_page_open } from '../stores';
import { overlay_open, on_this_page_open } from '../stores';
import { search } from '../state/search.svelte';
import Icon from '../components/Icon.svelte';
import { page } from '$app/stores';
import ThemeToggle from '../components/ThemeToggle.svelte';
Expand Down Expand Up @@ -67,7 +68,7 @@ Top navigation bar for the application. It provides a slot for the left side, th

<nav
class:visible
style:z-index={$overlay_open && ($searching || $on_this_page_open) ? 80 : null}
style:z-index={$overlay_open && (search.active || $on_this_page_open) ? 80 : null}
aria-label="Primary"
>
<a class="home-link" href="/" title={home_title} aria-label="Svelte"></a>
Expand Down Expand Up @@ -145,7 +146,7 @@ Top navigation bar for the application. It provides a slot for the left side, th
aria-label="Search"
class="raised icon search"
onclick={() => {
$searching = true;
search.active = true;
}}
>
<Icon name="search" size={18} />
Expand Down
10 changes: 5 additions & 5 deletions packages/site-kit/src/lib/search/Search.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Renders a search widget which when clicked (or the corresponding keyboard shortc
-->
<script lang="ts">
import { BROWSER } from 'esm-env';
import { search_query, searching } from '../stores/search';
import { search } from '../state/search.svelte';

let { q = '', label = 'Search' }: { q?: string; label?: string } = $props();
</script>
Expand All @@ -12,20 +12,20 @@ Renders a search widget which when clicked (or the corresponding keyboard shortc
<input
value={q}
oninput={(e) => {
$search_query = e.currentTarget.value;
$searching = true;
search.query = e.currentTarget.value;
search.active = true;
e.currentTarget.value = '';
e.currentTarget.blur();
}}
onmousedown={(event) => {
event.preventDefault();
event.currentTarget.blur();
$searching = true;
search.active = true;
}}
ontouchend={(event) => {
event.preventDefault();
event.currentTarget.blur();
$searching = true;
search.active = true;
}}
type="search"
name="q"
Expand Down
55 changes: 28 additions & 27 deletions packages/site-kit/src/lib/search/SearchBox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ It appears when the user clicks on the `Search` component or presses the corresp
-->
<script lang="ts">
import { afterNavigate } from '$app/navigation';
import { overlay_open, search_query, search_recent, searching } from '../stores';
import { overlay_open } from '../stores';
import { search } from '../state/search.svelte';
import { onMount, type Snippet } from 'svelte';
import { focusable_children, forcefocus, trap } from '../actions/focus.js';
import Icon from '../components/Icon.svelte';
Expand All @@ -24,7 +25,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
let modal = $state() as HTMLElement;

// TODO proper types
let search: any = $state(null);
let searched: any = $state(null);
let recent_searches: any[] = $state([]);

let last_scroll_position: number | null = null;
Expand All @@ -46,7 +47,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
}

if (type === 'results') {
search = payload;
searched = payload;
}

if (type === 'recents') {
Expand All @@ -69,8 +70,8 @@ It appears when the user clicks on the `Search` component or presses the corresp
});

async function close() {
if ($searching) {
$searching = false;
if (search.active) {
search.active = false;
const scroll = last_scroll_position || 0;
last_scroll_position = null;
document.body.style.position = '';
Expand All @@ -79,14 +80,14 @@ It appears when the user clicks on the `Search` component or presses the corresp
document.body.removeAttribute('tabindex');
window.scrollTo(0, scroll);

$search_query = '';
search.query = '';
}

search = null;
searched = null;
}

function navigate(href: string) {
$search_recent = [href, ...$search_recent.filter((x) => x !== href)];
search.recent = [href, ...search.recent.filter((x) => x !== href)];
close();
}

Expand All @@ -99,7 +100,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
type: 'query',
id,
payload: {
query: $search_query,
query: search.query,
path: $page.url.pathname
}
});
Expand All @@ -108,16 +109,16 @@ It appears when the user clicks on the `Search` component or presses the corresp

$effect(() => {
if (ready) {
worker.postMessage({ type: 'recents', payload: $state.snapshot($search_recent) });
worker.postMessage({ type: 'recents', payload: search.recent });
}
});

$effect(() => {
$overlay_open = $searching;
$overlay_open = search.active;
});

$effect(() => {
if ($searching) {
if (search.active) {
last_scroll_position = window.scrollY;
}
});
Expand All @@ -127,12 +128,12 @@ It appears when the user clicks on the `Search` component or presses the corresp
onkeydown={(e) => {
if (e.key === 'k' && (navigator.platform === 'MacIntel' ? e.metaKey : e.ctrlKey)) {
e.preventDefault();
$search_query = '';
search.query = '';

if ($searching) {
if (search.active) {
close();
} else {
$searching = true;
search.active = true;
}
}

Expand All @@ -142,7 +143,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
}}
/>

{#if $searching && ready}
{#if search.active && ready}
<div class="pseudo-overlay" aria-hidden="true" onclick={close}></div>

<!-- svelte-ignore a11y_no_static_element_interactions -->
Expand Down Expand Up @@ -178,16 +179,16 @@ It appears when the user clicks on the `Search` component or presses the corresp
}
}}
oninput={(e) => {
$search_query = e.currentTarget.value;
search.query = e.currentTarget.value;
}}
value={$search_query}
value={search.query}
{placeholder}
aria-describedby="search-description"
aria-label={placeholder}
spellcheck="false"
/>

<button aria-label="Clear" onclick={() => ($search_query = '')}>
<button aria-label="Clear" onclick={() => (search.query = '')}>
<Icon name="close" />
</button>
</div>
Expand All @@ -207,11 +208,11 @@ It appears when the user clicks on the `Search` component or presses the corresp
</span>

<div class="results">
{#if search?.query}
{#if searched?.query}
<div class="results-container">
<SearchResults
results={search.results}
query={search.query}
results={searched.results}
query={searched.query}
onselect={(href) => {
navigate(href);
}}
Expand All @@ -229,17 +230,17 @@ It appears when the user clicks on the `Search` component or presses the corresp
{#if recent_searches.length}
<div class="results-container">
<ul class="recent">
{#each recent_searches as search}
{#each recent_searches as result}
<li>
<a onclick={() => navigate(search.href)} href={search.href}>
{search.breadcrumbs.at(-1)}
<a onclick={() => navigate(result.href)} href={result.href}>
{result.breadcrumbs.at(-1)}
</a>

<button
class="raised icon"
aria-label="Delete"
onclick={(e) => {
$search_recent = $search_recent.filter((href) => href !== search.href);
search.recent = search.recent.filter((href) => href !== result.href);
e.stopPropagation();
e.preventDefault();
}}
Expand All @@ -258,7 +259,7 @@ It appears when the user clicks on the `Search` component or presses the corresp
{/if}

<div aria-live="assertive" class="visually-hidden">
{#if $searching && search?.results.length === 0}
{#if search.active && searched?.results.length === 0}
<p>
{#if no_results}
{@render no_results()}
Expand Down
6 changes: 6 additions & 0 deletions packages/site-kit/src/lib/state/code_preference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Persisted } from './Persisted.svelte';

export const code_preference = new Persisted<'typescript' | 'javascript'>(
'sv:code_preference',
'typescript'
);
17 changes: 17 additions & 0 deletions packages/site-kit/src/lib/state/search.svelte.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Persisted } from './Persisted.svelte';

class SearchState {
#recent = new Persisted<string>('sv:recent-searches', '[]');
active = $state(false);
query = $state('');

get recent() {
return JSON.parse(this.#recent.current) as string[];
}

set recent(value) {
this.#recent.current = JSON.stringify(value);
}
}

export const search = new SearchState();
1 change: 0 additions & 1 deletion packages/site-kit/src/lib/stores/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export { mql } from './mql';
export { nav_open, on_this_page_open, overlay_open, should_nav_autohide } from './nav';
export { reduced_motion } from './reduced-motion';
export { search_query, search_recent, searching } from './search';
3 changes: 0 additions & 3 deletions packages/site-kit/src/lib/stores/prefers_ts.ts

This file was deleted.

6 changes: 0 additions & 6 deletions packages/site-kit/src/lib/stores/search.ts

This file was deleted.

Loading
Loading