From 1a1a2d30cba9e37da47aa179bd5ea37263e47f82 Mon Sep 17 00:00:00 2001 From: Quentin Deroubaix Date: Mon, 6 Jan 2025 15:16:57 +0100 Subject: [PATCH] feat: use /state instead of deprecated /stores --- demo/scripts/includeSamples.plugin.ts | 2 +- demo/src/lib/docsearch/Search.svelte | 23 ++- demo/src/lib/layout/ComponentTypeAlert.svelte | 4 +- demo/src/lib/layout/Header.svelte | 24 +-- demo/src/lib/layout/Published.svelte | 6 +- demo/src/lib/layout/Sample.svelte | 23 +-- demo/src/lib/layout/StatusAlert.svelte | 4 +- demo/src/lib/layout/sample.ts | 2 +- demo/src/lib/layout/toc.svelte.ts | 6 +- demo/src/lib/markdown/renderers/MdCode.svelte | 4 +- demo/src/lib/markdown/renderers/MdLink.svelte | 9 +- demo/src/lib/routing.svelte.ts | 152 ++++++++++++++++++ demo/src/lib/stackblitz/index.ts | 2 +- demo/src/lib/stackblitz/prepareProject.ts | 2 +- demo/src/lib/stackblitz/utils.ts | 2 +- demo/src/lib/stores.ts | 83 ---------- demo/src/routes/+layout.svelte | 52 +++--- .../[framework]/[type]/[...slug]/+page.svelte | 4 +- .../routes/docs/[framework]/+layout.svelte | 16 +- .../[framework]/components/+layout.svelte | 20 +-- .../docs/[framework]/daisyUI/+layout.svelte | 16 +- .../daisyUI/collapse/api/+page.svelte | 4 +- .../src/routes/menu/CollapsibleSection.svelte | 18 ++- demo/src/routes/menu/MobileMenu.svelte | 20 +-- demo/src/routes/menu/SideMenu.svelte | 36 ++--- demo/src/routes/menu/Versions.svelte | 12 +- 26 files changed, 309 insertions(+), 237 deletions(-) create mode 100644 demo/src/lib/routing.svelte.ts diff --git a/demo/scripts/includeSamples.plugin.ts b/demo/scripts/includeSamples.plugin.ts index fe532b7e94..b4a99f0110 100644 --- a/demo/scripts/includeSamples.plugin.ts +++ b/demo/scripts/includeSamples.plugin.ts @@ -1,6 +1,6 @@ import type {Plugin} from 'vite'; import path from 'path'; -import type {Frameworks} from '$lib/stores'; +import type {Frameworks} from '$lib/routing.svelte'; import {readFile} from 'fs/promises'; import {existsSync} from 'fs'; diff --git a/demo/src/lib/docsearch/Search.svelte b/demo/src/lib/docsearch/Search.svelte index b276b127d5..89c9fad57e 100644 --- a/demo/src/lib/docsearch/Search.svelte +++ b/demo/src/lib/docsearch/Search.svelte @@ -1,24 +1,21 @@ diff --git a/demo/src/lib/layout/ComponentTypeAlert.svelte b/demo/src/lib/layout/ComponentTypeAlert.svelte index 9a3d6dc27a..752a0d43bf 100644 --- a/demo/src/lib/layout/ComponentTypeAlert.svelte +++ b/demo/src/lib/layout/ComponentTypeAlert.svelte @@ -1,7 +1,7 @@ @@ -41,16 +41,16 @@ {#if status === 'inprogress'}In progress{/if} {#if status === 'beta'}Beta{/if} {#if includesFwk} - {#if $selectedApiFramework$ === 'typescript'}{/if} - {#if $selectedApiFramework$ === 'react'}{/if} - {#if $selectedApiFramework$ === 'angular'}{/if} - {#if $selectedApiFramework$ === 'svelte'}{/if} {/if} @@ -68,10 +68,10 @@ {#if tabs.length} {/if}
- import('./Code.svelte')} {code} fileName={selectedFileName} language={isPlaceholder ? $selectedFramework$ : undefined}> + import('./Code.svelte')} + {code} + fileName={selectedFileName} + language={isPlaceholder ? routing.selectedFramework : undefined} + >
Loading...
diff --git a/demo/src/lib/layout/StatusAlert.svelte b/demo/src/lib/layout/StatusAlert.svelte index e8382d4870..51d1977c5b 100644 --- a/demo/src/lib/layout/StatusAlert.svelte +++ b/demo/src/lib/layout/StatusAlert.svelte @@ -2,7 +2,7 @@ import {Alert, type AlertProps} from '@agnos-ui/svelte-bootstrap/components/alert'; import biInfoCircleFill from 'bootstrap-icons/icons/info-circle-fill.svg?raw'; import biExclamationTriangleFill from 'bootstrap-icons/icons/exclamation-triangle-fill.svg?raw'; - import {page} from '$app/stores'; + import {page} from '$app/state'; import Svg from './Svg.svelte'; import {untrack} from 'svelte'; @@ -22,7 +22,7 @@ ? 'This component is still under active development. More features will be added in the near future.' : 'This component has all the basic functionalities implemented. More polishing features might be added in the near future.', ); - let componentName = $derived($page.url.pathname.match(regex)?.[2]); + let componentName = $derived(page.url.pathname.match(regex)?.[2]); let issueUrl = $derived(`https://github.com/AmadeusITGroup/AgnosUI/issues?q=is%3Aopen+is%3Aissue+label%3A%22widget%3A+${componentName}%22`); $effect(() => { // eslint-disable-next-line @typescript-eslint/no-unused-expressions diff --git a/demo/src/lib/layout/sample.ts b/demo/src/lib/layout/sample.ts index 1a4ce4cf24..a1c7d32531 100644 --- a/demo/src/lib/layout/sample.ts +++ b/demo/src/lib/layout/sample.ts @@ -1,4 +1,4 @@ -import type {Frameworks} from '$lib/stores'; +import type {Frameworks} from '$lib/routing.svelte'; export type AsyncFilesSet = Record Promise>; diff --git a/demo/src/lib/layout/toc.svelte.ts b/demo/src/lib/layout/toc.svelte.ts index d05f15b352..77b2ef7a2a 100644 --- a/demo/src/lib/layout/toc.svelte.ts +++ b/demo/src/lib/layout/toc.svelte.ts @@ -1,6 +1,5 @@ import {intersectionApi} from '$lib/stores'; -import {navigating as appNavigating} from '$app/stores'; -import {fromStore} from 'svelte/store'; +import {navigating} from '$app/state'; /** * Create a directive to facilitate the interception usage in Svelte @@ -19,13 +18,12 @@ import {fromStore} from 'svelte/store'; */ export function createTOC(getElements: (node: HTMLElement) => HTMLElement[]) { let container = $state(); - const navigating = fromStore(appNavigating); function directive(node: HTMLElement) { container = node; } $effect(() => { - if (!navigating.current) { + if (!navigating.to) { intersectionApi.patch({ elements: container ? getElements(container) : [], }); diff --git a/demo/src/lib/markdown/renderers/MdCode.svelte b/demo/src/lib/markdown/renderers/MdCode.svelte index a20c5e0063..f8449df9cd 100644 --- a/demo/src/lib/markdown/renderers/MdCode.svelte +++ b/demo/src/lib/markdown/renderers/MdCode.svelte @@ -2,7 +2,7 @@ import Code from '$lib/layout/Code.svelte'; import Sample from '$lib/layout/Sample.svelte'; import type {SampleInfo} from '$lib/layout/sample'; - import {selectedFramework$} from '$lib/stores'; + import {routing} from '$lib/routing.svelte'; import samples from '../samples'; interface Props { @@ -27,7 +27,7 @@ $effect(() => { if (lang !== 'sample' && text.trim().match(/^\{[a-z-]+\}$/) && extensions.has(lang)) { const codeKey = text.trim().slice(1, -1); - void import(`../../../../../docs/code/${codeKey}/${codeKey}-${$selectedFramework$}.${extensions.get(lang)}?raw`).then( + void import(`../../../../../docs/code/${codeKey}/${codeKey}-${routing.selectedFramework}.${extensions.get(lang)}?raw`).then( (val) => (code = val.default), ); } else { diff --git a/demo/src/lib/markdown/renderers/MdLink.svelte b/demo/src/lib/markdown/renderers/MdLink.svelte index 20c6eb43fd..f447059892 100644 --- a/demo/src/lib/markdown/renderers/MdLink.svelte +++ b/demo/src/lib/markdown/renderers/MdLink.svelte @@ -1,7 +1,8 @@
{@render children()} diff --git a/demo/src/lib/routing.svelte.ts b/demo/src/lib/routing.svelte.ts new file mode 100644 index 0000000000..0644807fac --- /dev/null +++ b/demo/src/lib/routing.svelte.ts @@ -0,0 +1,152 @@ +/* eslint-disable @typescript-eslint/prefer-readonly */ +import {page} from '$app/state'; +import {BROWSER} from 'esm-env'; + +export type Frameworks = 'angular' | 'react' | 'svelte'; +export type ApiFrameworks = 'typescript' | Frameworks; +export type PackageType = 'headless' | 'bootstrap'; + +const baseCanonicalURL = 'https://www.agnosui.dev/latest/'; +const tabRegExp = /^\/docs\/\[framework\]\/(components|daisyUI)\/[^/]*\/([^/]*)/; + +export const routing: { + /** + * How deep the current route is compared to base + */ + routeLevel: number; + /** + * Absolute path to root + */ + pathToRoot: string; + /** + * Canonical URL + */ + canonicalURL: string; + /** + * Current non-typescript selected framework + */ + selectedFramework: Frameworks; + /** + * Current selected framework (including typescript for api) + */ + selectedApiFramework: ApiFrameworks; + /** + * Current package type + */ + selectedPackageType: PackageType | undefined; + /** + * Current selected tab + */ + selectedTabName: string | undefined; +} = BROWSER + ? new (class Routing { + #routeLevel = $derived( + page.route.id ? page.route.id.split('/').length - 2 + Object.values(page.params).reduce((pV, cur) => pV + cur.split('/').length - 1, 0) : -1, + ); + + // Return the url relative path to root, ex './', '../' or '../..' + #relativePathToRoot = $derived(this.#routeLevel > 0 ? '../'.repeat(this.#routeLevel) : './'); + + #pathToRoot = $derived(new URL(this.#relativePathToRoot, page.url.href).href); + + #canonicalURL = $derived(page.url.href.replace(new URL(this.#relativePathToRoot, page.url.href).href, baseCanonicalURL)); + + #previousFwk: Frameworks = 'angular'; + #selectedFramework = $derived.by(() => { + if (page.params.framework && page.params.framework !== 'typescript') { + this.#previousFwk = page.params.framework as Frameworks; + } + return this.#previousFwk; + }); + + #previousApiFwk: ApiFrameworks = 'angular'; + #selectedApiFramework = $derived.by(() => { + if (page.params.framework) { + this.#previousApiFwk = page.params.framework as Frameworks; + } + return this.#previousApiFwk; + }); + + #selectedPackageType = $derived.by(() => { + if (page.params.type) { + return page.params.type as PackageType; + } + if (page.url.pathname.match(/\/daisyUI\//)) { + return 'headless'; + } + if (page.url.pathname.match(/\/docs\/[^/]*\/components\//)) { + return 'bootstrap'; + } + return undefined; + }); + + #selectedTabName = $derived(tabRegExp.exec(page.route.id || '')?.[2]); + + get routeLevel() { + return this.#routeLevel; + } + get pathToRoot() { + return this.#pathToRoot; + } + get canonicalURL() { + return this.#canonicalURL; + } + get selectedFramework() { + return this.#selectedFramework; + } + get selectedApiFramework() { + return this.#selectedApiFramework; + } + get selectedPackageType() { + return this.#selectedPackageType; + } + get selectedTabName() { + return this.#selectedTabName; + } + })() + : new (class Routing { + get routeLevel() { + return page.route.id + ? page.route.id.split('/').length - 2 + Object.values(page.params).reduce((pV, cur) => pV + cur.split('/').length - 1, 0) + : -1; + } + get pathToRoot() { + return this.routeLevel > 0 ? '../'.repeat(this.routeLevel) : './'; + } + // Return the url relative path to root, ex './', '../' or '../..' + get #relativePathToRoot() { + return this.routeLevel > 0 ? '../'.repeat(this.routeLevel) : './'; + } + get canonicalURL() { + return page.url.href.replace(new URL(this.#relativePathToRoot, page.url.href).href, baseCanonicalURL); + } + #previousFwk: Frameworks = 'angular'; + get selectedFramework() { + if (page.params.framework && page.params.framework !== 'typescript') { + this.#previousFwk = page.params.framework as Frameworks; + } + return this.#previousFwk; + } + #previousApiFwk: ApiFrameworks = 'angular'; + get selectedApiFramework() { + if (page.params.framework) { + this.#previousApiFwk = page.params.framework as Frameworks; + } + return this.#previousApiFwk; + } + get selectedPackageType() { + if (page.params.type) { + return page.params.type as PackageType; + } + if (page.url.pathname.match(/\/daisyUI\//)) { + return 'headless'; + } + if (page.url.pathname.match(/\/docs\/[^/]*\/components\//)) { + return 'bootstrap'; + } + return undefined; + } + get selectedTabName() { + return tabRegExp.exec(page.route.id || '')?.[2]; + } + })(); diff --git a/demo/src/lib/stackblitz/index.ts b/demo/src/lib/stackblitz/index.ts index 083204c715..4fe897010c 100644 --- a/demo/src/lib/stackblitz/index.ts +++ b/demo/src/lib/stackblitz/index.ts @@ -1,4 +1,4 @@ -import type {Frameworks} from '$lib/stores'; +import type {Frameworks} from '$lib/routing.svelte'; import stackblitz from '@stackblitz/sdk'; import type {SampleInfo} from '../layout/sample'; import {prepareStackblitzProject} from './prepareProject'; diff --git a/demo/src/lib/stackblitz/prepareProject.ts b/demo/src/lib/stackblitz/prepareProject.ts index e21cf8bb99..fbc16054c9 100644 --- a/demo/src/lib/stackblitz/prepareProject.ts +++ b/demo/src/lib/stackblitz/prepareProject.ts @@ -1,5 +1,5 @@ import type {SampleInfo} from '$lib/layout/sample'; -import type {Frameworks} from '$lib/stores'; +import type {Frameworks} from '$lib/routing.svelte'; import type {Project} from '@stackblitz/sdk'; import type {StackblitzProcessor} from './utils'; import {addAsyncFiles, isBootstrapCondition, isDaisyuiCondition} from './utils'; diff --git a/demo/src/lib/stackblitz/utils.ts b/demo/src/lib/stackblitz/utils.ts index 1524c00cad..8278455370 100644 --- a/demo/src/lib/stackblitz/utils.ts +++ b/demo/src/lib/stackblitz/utils.ts @@ -1,5 +1,5 @@ import type {SampleInfo} from '$lib/layout/sample'; -import type {Frameworks} from '$lib/stores'; +import type {Frameworks} from '$lib/routing.svelte'; import type {Project} from '@stackblitz/sdk'; import type {AsyncFilesSet} from '../layout/sample'; diff --git a/demo/src/lib/stores.ts b/demo/src/lib/stores.ts index a9af745f86..726b552d40 100644 --- a/demo/src/lib/stores.ts +++ b/demo/src/lib/stores.ts @@ -1,86 +1,3 @@ -import {computed, derived, get} from '@amadeus-it-group/tansu'; -import {browser} from '$app/environment'; -import {page} from '$app/stores'; import {createIntersection} from '@agnos-ui/svelte-bootstrap/services/intersection'; -// Return how deep the current route is compared to base -export const routeLevel$ = computed(() => { - const $page = get(page); - if (!$page.route.id) { - throw new Error('Page error'); - } - return $page.route.id.split('/').length - 2 + Object.values($page.params).reduce((pV, cur) => pV + cur.split('/').length - 1, 0); -}); - -// Return the url relative path to root, ex './', '../' or '../..' -export const relativePathToRoot$ = computed(() => { - const routeLevel = routeLevel$(); - return routeLevel ? '../'.repeat(routeLevel) : './'; -}); - -export const pathToRoot$ = browser ? computed(() => new URL(relativePathToRoot$(), window.location.href).href) : relativePathToRoot$; - -const baseCanonicalURL = 'https://www.agnosui.dev/latest/'; -export const canonicalURL$ = computed(() => { - const pageURL = get(page).url.href; - const rootURL = new URL(relativePathToRoot$(), pageURL).href; - const canonicalURL = pageURL.replace(rootURL, baseCanonicalURL); - return canonicalURL; -}); - -export type Frameworks = 'angular' | 'react' | 'svelte'; -export type ApiFrameworks = 'typescript' | Frameworks; -export type PackageType = 'headless' | 'bootstrap'; - -/** - * Current selected framework - */ -export const selectedFramework$ = derived( - page, - (p, set) => { - if (p.params.framework && p.params.framework !== 'typescript') { - set(p.params.framework as Frameworks); - } - }, - 'angular' as Frameworks, -); -/** - * Current non-typescript selected framework - */ -export const selectedApiFramework$ = derived( - page, - (p, set) => { - if (p.params.framework) { - set(p.params.framework as ApiFrameworks); - } - }, - 'angular' as ApiFrameworks, -); - -/** - * Current package type - */ -export const selectedPackageType$ = computed(() => { - const p = get(page); - if (p.params.type) { - return p.params.type as PackageType; - } - if (p.url.pathname.match(/\/daisyUI\//)) { - return 'headless'; - } - if (p.url.pathname.match(/\/docs\/[^/]*\/components\//)) { - return 'bootstrap'; - } - return undefined; -}); - -const tabRegExp = /^\/docs\/\[framework\]\/(components|daisyUI)\/[^/]*\/([^/]*)/; -/** - * Current selected tab - */ -export const selectedTabName$ = computed(() => { - const match = tabRegExp.exec(get(page).route.id || ''); - return match?.[2]; -}); - export const intersectionApi = createIntersection(); diff --git a/demo/src/routes/+layout.svelte b/demo/src/routes/+layout.svelte index a882045115..e602cf650f 100644 --- a/demo/src/routes/+layout.svelte +++ b/demo/src/routes/+layout.svelte @@ -3,10 +3,10 @@ import github from 'bootstrap-icons/icons/github.svg?raw'; import bluesky from '$resources/bluesky.svg?raw'; import twitter from 'bootstrap-icons/icons/twitter-x.svg?raw'; - import {canonicalURL$, pathToRoot$, routeLevel$, selectedFramework$, selectedApiFramework$} from '$lib/stores'; + import {routing} from '$lib/routing.svelte'; import './styles.scss'; import {afterNavigate, beforeNavigate, onNavigate} from '$app/navigation'; - import {page, updated} from '$app/stores'; + import {page, updated} from '$app/state'; import MobileSubMenu from './menu/MobileSubMenu.svelte'; import MobileMenu from './menu/MobileMenu.svelte'; import MainSection from '$lib/layout/MainSection.svelte'; @@ -21,11 +21,11 @@ import viewTransition from './view-transition.css?raw'; import Search from '$lib/docsearch/Search.svelte'; - let isMainPage = $derived($routeLevel$ === 0); - let isApi = $derived($page.route.id?.startsWith('/api/')); + let isMainPage = $derived(routing.routeLevel === 0); + let isApi = $derived(page.route.id?.startsWith('/api/')); beforeNavigate(({willUnload, to}) => { - if ($updated && !willUnload && to?.url) { + if (updated.current && !willUnload && to?.url) { // force reload of the page on navigation when a new version of the site has been detected location.href = to.url.href; } @@ -74,33 +74,33 @@ - + - - - + + + - + - - - - + + + + - - - + + + - +