svelte-spa-history-router 3.0.0-next.2 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +67 -83
  2. package/dist/Router.svelte.d.ts +26 -0
  3. package/dist/currentURL.d.ts +1 -0
  4. package/{src/currentURL.ts → dist/currentURL.js} +3 -6
  5. package/dist/index.d.ts +6 -0
  6. package/dist/index.js +5 -0
  7. package/dist/link.d.ts +12 -0
  8. package/dist/link.js +25 -0
  9. package/dist/push.d.ts +8 -0
  10. package/dist/push.js +12 -0
  11. package/dist/redirect.d.ts +6 -0
  12. package/dist/redirect.js +7 -0
  13. package/dist/spa-context.d.ts +3 -0
  14. package/dist/spa-context.js +8 -0
  15. package/dist/spa-event.d.ts +1 -0
  16. package/dist/spa-event.js +1 -0
  17. package/dist/types.d.ts +29 -0
  18. package/dist/types.js +8 -0
  19. package/package.json +15 -10
  20. package/.vscode/extensions.json +0 -3
  21. package/example/App.svelte +0 -117
  22. package/example/index.html +0 -13
  23. package/example/lib/getArticle.ts +0 -13
  24. package/example/lib/getArticles.ts +0 -43
  25. package/example/main.ts +0 -8
  26. package/example/pages/Admin.svelte +0 -7
  27. package/example/pages/Blog.svelte +0 -19
  28. package/example/pages/BlogPost.svelte +0 -23
  29. package/example/pages/IntParam.svelte +0 -14
  30. package/example/pages/Message.svelte +0 -9
  31. package/example/pages/NotFound.svelte +0 -4
  32. package/example/pages/Params.svelte +0 -13
  33. package/example/pages/Query.svelte +0 -14
  34. package/example/pages/Top.svelte +0 -7
  35. package/example/types.ts +0 -9
  36. package/example/vite-env.d.ts +0 -2
  37. package/playwright-report/index.html +0 -71
  38. package/playwright.config.js +0 -26
  39. package/src/index.ts +0 -7
  40. package/src/link.ts +0 -28
  41. package/src/push.ts +0 -18
  42. package/src/redirect.ts +0 -9
  43. package/src/spa-context.ts +0 -15
  44. package/src/spa-event.ts +0 -1
  45. package/src/types.ts +0 -46
  46. package/test-results/.last-run.json +0 -4
  47. package/tests/e2e.spec.ts +0 -133
  48. package/tsconfig.app.json +0 -27
  49. package/tsconfig.json +0 -7
  50. package/tsconfig.node.json +0 -24
  51. package/vite.config.ts +0 -8
  52. /package/{src → dist}/Router.svelte +0 -0
package/README.md CHANGED
@@ -1,22 +1,21 @@
1
1
  # svelte-spa-history-router
2
2
 
3
- History base router for [Svelte](https://svelte.dev/) SPA (Single Page Application).
3
+ A history-based router for [Svelte](https://svelte.dev/) Single Page Applications (SPAs).
4
4
 
5
5
  > [!TIP]
6
- > The offcial routing library of Svelte is [SvelteKit](https://svelte.dev/docs/kit/introduction). This library is intented to be used for small/simple project.
7
-
6
+ > Svelte's official routing library is [SvelteKit](https://svelte.dev/docs/kit/introduction). This library is designed for small or simple projects.
8
7
 
9
8
  ## Features
10
9
 
11
- - History-base routing
12
- - path matching and path variable capturing by regular expression
13
- - resolver (for dynamic routing, code-splitting, data preloading, etc...)
10
+ - History-Based Routing
11
+ - Path matching and Variable Capture using regular expressions
12
+ - Resolver for dynamic routing, code splitting, data preloading, etc.
14
13
 
15
- ## *Not* supported features
14
+ ## Features *not* supported
16
15
 
17
- - Hash-base routing
16
+ - Hash-based Routing
18
17
  - Nested router
19
- - SSR (Server Side Rendering)
18
+ - Server-Side Rendering (SSR)
20
19
 
21
20
  ## Install
22
21
 
@@ -28,7 +27,7 @@ $ yarn add svelte-spa-history-router
28
27
 
29
28
  ## Usage
30
29
 
31
- Import `Router` and put into your main component (typically App.svelte).
30
+ Import `Router` and include it in your main component (typically App.svelte).
32
31
 
33
32
  For example:
34
33
 
@@ -51,59 +50,76 @@ For example:
51
50
  <Router {routes}/>
52
51
  ```
53
52
 
54
- * `Routes` require a `routes` parameter.
55
- * `routes` is a list of route objects. route object has `path` property, and either `component` or `resolver` property.
53
+ * `Router` requires the `routes` parameter.
54
+ * `routes` is a list of route objects. Each route object must have a `path` property, and either a `component` or `resolver` property.
56
55
 
57
56
  * `path` can be a regular expression. `^` and `$` are automatically added when matching.
58
- * `component` is a Svelte component. there are no specific requirements for component.
59
- * `resolver` is a function to determine component dynamically.
57
+ * `component` is a Svelte component. There are no specific requirements for the component.
58
+ * `resolver` is a function to return a dynamic component and return props of the type expected by the component.
60
59
 
61
60
  * Matching is simply performed in the order defined by `routes`.
62
61
 
63
62
  ### Path variable
64
63
 
65
- Matched paramaters are passed to component as `params` property.
64
+ For routes that do not use a resolver, matched parameters are passed to the component via the `params` prop.
66
65
 
67
66
  For example:
68
67
 
69
68
  ```html
70
- # Article.svelte
69
+ # App.svelte
70
+ <script>
71
+ import { Router } from "svelte-spa-history-router";
72
+ import ItemPage from "./ItemPage.svelte";
73
+
74
+ const routes = [
75
+ { path: "/items/(?<itemId>\\d+)", component: ItemPage },
76
+ ];
77
+ </script>
78
+ <Router {routes}/>
79
+ ```
80
+
81
+ ```html
82
+ # ItemPage.svelte
71
83
 
72
84
  <script lang="ts">
73
- let { params }: { params: { postId: string } = $props();
85
+ let { params }: { params: { itemId: string } } = $props();
74
86
 
75
- const postId = $derived(parseInt(params.postId));
87
+ const itemId = $derived(parseInt(params.itemId));
76
88
  </script>
77
89
  <div>
78
- { postId }
90
+ { itemId }
79
91
  </div>
80
92
  ```
81
93
 
82
94
  ### Navigation methods
83
95
 
84
- To navigate another page, `link` and `push` are available.
96
+ To navigate to another page, `link` and `push` are available.
85
97
 
86
- * `link` is used with a `a` tag like below
98
+ * `link` turns an `<a>` tag into a spa navigation link. For example:
87
99
 
88
100
  ```html
89
- import { link } from 'svelte-spa-history-router';
101
+ <script>
102
+ import { link } from 'svelte-spa-history-router';
103
+ </script>
90
104
 
91
105
  <a use:link href="/">Home</a>
92
106
  ```
93
107
 
94
- * `push` is used to navigate programatically
108
+ * `push` navigates to the given path programatically.
95
109
 
96
110
  ```html
97
- import { push } from 'svelte-spa-history-router';
111
+ <script>
112
+ import { push } from 'svelte-spa-history-router';
113
+ <script>
98
114
 
99
115
  <button onclick={ () => push('/') }>Go to Home</button>
100
116
  ```
101
117
 
102
118
  ### resolver
103
119
 
104
- Resolver is a mechanism to dynamically determine component and can be used in multiple use cases.
120
+ A resolver is a mechanism for dynamically determining which component to render. It can be used for various purposes, such as:
105
121
 
106
- Example: code spliting (dynamic import)
122
+ Example: code splitting (dynamic import)
107
123
 
108
124
  ```html
109
125
  <script>
@@ -141,6 +157,9 @@ Example: dynamic routing and pass value to component props.
141
157
  <Router {routes}/>
142
158
  ```
143
159
 
160
+ > [!TIP]
161
+ > This routing mechanism allows preloading data before rendering the component, minimizing layout flicker and improving perceived performance. While skeleton screens are a common modern pattern, this approach can simplify state handling in simple apps.
162
+
144
163
  Example: guard
145
164
 
146
165
  ```html
@@ -167,6 +186,20 @@ Example: guard
167
186
  <Router {routes}/>
168
187
  ```
169
188
 
189
+ A resolver must return one of the following types:
190
+
191
+ ```typescript
192
+ | Component
193
+ | { component: Component, props: ComponentProps }
194
+ | Redirection // return value of `redirect()`
195
+ | Promise<
196
+ | Component
197
+ | { component: Component, props: ComponentProps }
198
+ | Redirection
199
+ | { default: Component } // return value of `import()`
200
+ >
201
+ ```
202
+
170
203
  (Added in v2.0.0)
171
204
 
172
205
  (Changed resolver interface in v3.0.0-next.1)
@@ -186,7 +219,7 @@ state to detect URL changes (including query string or hash)
186
219
 
187
220
  (Added in v2.1.0)
188
221
 
189
- (Replaced to svelte5 `$state()` in v3.0.0-next.1)
222
+ (Replaced with Svelte5's `$state()` in v3.0.0-next.1)
190
223
 
191
224
  ### Typing
192
225
 
@@ -204,7 +237,7 @@ svelte-spa-history-router provides `Route` type to check combination of componen
204
237
  const routes: [
205
238
  Route<typeof Top>,
206
239
  Route<typeof BlogPost | typeof NotFound>,
207
- ]: [
240
+ ] = [
208
241
  { path: "/", component: Top },
209
242
  {
210
243
  path: "/blog/posts/(?<slug>.*)",
@@ -226,60 +259,11 @@ svelte-spa-history-router provides `Route` type to check combination of componen
226
259
 
227
260
  ### Full example:
228
261
 
229
- [example](https://github.com/ykrods/svelte-spa-history-router/tree/master/example)
262
+ [example](https://github.com/ykrods/svelte-spa-history-router/tree/main/src)
230
263
 
231
264
  ## ChangeLog
232
265
 
233
- ### 3.0.0-next.1
234
-
235
- * *[Breaking change]* Drop Svelte4 support
236
-
237
- * Remove stores of `routeParams` and `currentURL`
238
-
239
- * *[Breaking change]* Change resolver interface
240
- * Add `currentURL()` which is rewriten to use `$state()`
241
-
242
- ### 2.2.0
243
-
244
- * Support Svelte5
245
-
246
- ### 2.2.0-next.1
247
-
248
- * Fix component type on svelte5 [PR13](https://github.com/ykrods/svelte-spa-history-router/pull/13)
249
-
250
- ### 2.2.0-next.0
251
-
252
- * Add the way to get routing params to via props [PR12](https://github.com/ykrods/svelte-spa-history-router/pull/12)
253
- * Refactor (changes: [2.1.2...7b7795b](https://github.com/ykrods/svelte-spa-history-router/compare/2.1.2...7b7795b2675c452a1a189d3931c0c4c9abb04c51) )
254
-
255
- ### 2.1.2 (2024-04-29)
256
-
257
- * Support types [PR10](https://github.com/ykrods/svelte-spa-history-router/pull/10)
258
-
259
- ### 2.1.1 (2024-01-13)
260
-
261
- * ~~Support Types~~ Add typecheck [PR9](https://github.com/ykrods/svelte-spa-history-router/pull/9)
262
-
263
- ### 2.1.0 (2021-04-29)
264
-
265
- * Add `currentURL` store to detect URL changes [PR6](https://github.com/ykrods/svelte-spa-history-router/pull/6)
266
-
267
- ### 2.0.0 (2021-04-15)
268
-
269
- * [Added] resolver
270
- * [Removed] guard
271
-
272
- ### 1.1.1 (2021-04-12)
273
-
274
- * Fix bug with async guard function causing loop
275
-
276
- ### 1.1.0 (2021-03-26)
277
-
278
- * Add guard
279
-
280
- ### 1.0.2
281
-
282
- * Fix import error
266
+ [ChangeLog](https://github.com/ykrods/svelte-spa-history-router/tree/main/ChangeLog.md)
283
267
 
284
268
  ## License
285
269
 
@@ -287,9 +271,9 @@ MIT License.
287
271
 
288
272
  ## Appendix
289
273
 
290
- Generally, history-base router requires server-side routing so that user can open the direct link or reload.
274
+ A history-based router generally requires server-side routing to support direct links or page reloads.
291
275
 
292
- For example, Nginx excerpt configuration is like bellow.
276
+ For example, the following nginx configuration allows proper routing:
293
277
 
294
278
  ```
295
279
  location / {
@@ -297,10 +281,10 @@ location / {
297
281
  }
298
282
  ```
299
283
 
300
- If you consider to use firebase hosting for your application, [rewrite](https://firebase.google.com/docs/hosting/full-config#rewrites) may be useful.
284
+ If you are considering using firebase hosting for your application, [rewrite](https://firebase.google.com/docs/hosting/full-config#rewrites) may be useful.
301
285
 
302
286
  ## Inspired
303
287
 
304
288
  svelte-spa-history-router is inspired by [svelte-spa-router](https://github.com/ItalyPaleAle/svelte-spa-router) and [Svelte Router SPA](https://github.com/jorgegorka/svelte-router).
305
289
 
306
- If you don't need both history-base and regular expression support, I reccommend these powerful routers.
290
+ If you don't need support for both history-based routing and regular expressions, I recommend these powerful routers.
@@ -0,0 +1,26 @@
1
+ import type { Component } from "svelte";
2
+ import type { Route } from "./types";
3
+ type $$ComponentProps = {
4
+ routes: Route<any>[];
5
+ };
6
+ /**
7
+ * Router component
8
+ *
9
+ * @example
10
+ * <script>
11
+ * import { Router } from "svelte-spa-history-router";
12
+ *
13
+ * import Top from "./Top.svelte"
14
+ * import NotFound from "./NotFound.svelte"
15
+ *
16
+ * const routes = [
17
+ * { path: "/", component: Top },
18
+ * { path: "/posts/(?<postId>.*)", resolver: () => import("./Article.svelte") },
19
+ * { path: ".*", component: NotFound },
20
+ * ];
21
+ * </script>
22
+ * <Router {routes}/>
23
+ */
24
+ declare const Router: Component<$$ComponentProps, {}, "">;
25
+ type Router = ReturnType<typeof Router>;
26
+ export default Router;
@@ -0,0 +1 @@
1
+ export declare function currentURL(): URL;
@@ -1,9 +1,6 @@
1
1
  // https://svelte.dev/docs/svelte/compiler-warnings#state_referenced_locally
2
2
  // https://svelte.dev/docs/svelte/$state#Passing-state-into-functions
3
-
4
- import { getSpaContext } from "./spa-context"
5
-
6
-
7
- export function currentURL(): URL {
8
- return getSpaContext().currentURL();
3
+ import { getSpaContext } from "./spa-context";
4
+ export function currentURL() {
5
+ return getSpaContext().currentURL();
9
6
  }
@@ -0,0 +1,6 @@
1
+ export type { Route } from "./types";
2
+ export { default as Router } from "./Router.svelte";
3
+ export { link } from "./link";
4
+ export { push } from "./push";
5
+ export { redirect } from "./redirect";
6
+ export { currentURL } from "./currentURL";
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { default as Router } from "./Router.svelte";
2
+ export { link } from "./link";
3
+ export { push } from "./push";
4
+ export { redirect } from "./redirect";
5
+ export { currentURL } from "./currentURL";
package/dist/link.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Svelte action to make `<a>` work as navigation of svelte-spa-history-router
3
+ *
4
+ * @param node - target `<a>`
5
+ *
6
+ * @example
7
+ *
8
+ * <a use:link href="/">top</a>
9
+ */
10
+ export declare function link(node: HTMLAnchorElement): {
11
+ destroy(): void;
12
+ };
package/dist/link.js ADDED
@@ -0,0 +1,25 @@
1
+ import { push } from "./push";
2
+ /**
3
+ * Svelte action to make `<a>` work as navigation of svelte-spa-history-router
4
+ *
5
+ * @param node - target `<a>`
6
+ *
7
+ * @example
8
+ *
9
+ * <a use:link href="/">top</a>
10
+ */
11
+ export function link(node) {
12
+ function onClick(event) {
13
+ event.preventDefault();
14
+ var href = node.getAttribute("href");
15
+ if (href) {
16
+ push(href);
17
+ }
18
+ }
19
+ node.addEventListener("click", onClick);
20
+ return {
21
+ destroy: function () {
22
+ node.removeEventListener("click", onClick);
23
+ },
24
+ };
25
+ }
package/dist/push.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Navigate to next page programmatically
3
+ *
4
+ * @example
5
+ *
6
+ * <button onclick={ () => push(`posts/${id}`) }>next</button>
7
+ */
8
+ export declare function push(next: string): void;
package/dist/push.js ADDED
@@ -0,0 +1,12 @@
1
+ import * as SpaEvent from "./spa-event";
2
+ /**
3
+ * Navigate to next page programmatically
4
+ *
5
+ * @example
6
+ *
7
+ * <button onclick={ () => push(`posts/${id}`) }>next</button>
8
+ */
9
+ export function push(next) {
10
+ var evt = new CustomEvent(SpaEvent.NAVIGATE, { detail: { next: next } });
11
+ window.dispatchEvent(evt);
12
+ }
@@ -0,0 +1,6 @@
1
+ import type { Redirection } from "./types";
2
+ /**
3
+ * This is special function used in resolvers.
4
+ * Normally, you use `push()` to change the url.
5
+ */
6
+ export declare function redirect(to: string): Redirection;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * This is special function used in resolvers.
3
+ * Normally, you use `push()` to change the url.
4
+ */
5
+ export function redirect(to) {
6
+ return { redirect: to };
7
+ }
@@ -0,0 +1,3 @@
1
+ import type { SpaContext } from "./types";
2
+ export declare function setSpaContext(ctx: SpaContext): void;
3
+ export declare function getSpaContext(): SpaContext;
@@ -0,0 +1,8 @@
1
+ import { setContext, getContext } from "svelte";
2
+ var key = Symbol("svelte-spa-history-router");
3
+ export function setSpaContext(ctx) {
4
+ setContext(key, ctx);
5
+ }
6
+ export function getSpaContext() {
7
+ return getContext(key);
8
+ }
@@ -0,0 +1 @@
1
+ export declare const NAVIGATE = "spa-navigate";
@@ -0,0 +1 @@
1
+ export var NAVIGATE = "spa-navigate";
@@ -0,0 +1,29 @@
1
+ import type { Component, ComponentProps } from "svelte";
2
+ import * as SpaEvent from "./spa-event";
3
+ export type NavigationEvent = CustomEvent<{
4
+ next: string;
5
+ }>;
6
+ declare global {
7
+ interface WindowEventMap {
8
+ [SpaEvent.NAVIGATE]: NavigationEvent;
9
+ }
10
+ }
11
+ export interface Redirection {
12
+ redirect: string;
13
+ }
14
+ export interface Destination<T extends Component<any>> {
15
+ component: T;
16
+ props: ComponentProps<T>;
17
+ }
18
+ type DestMap<T extends Component<any>> = T extends unknown ? Destination<T> : never;
19
+ export type Route<T extends Component<any> = Component> = {
20
+ path: string;
21
+ component?: T;
22
+ resolver?: (params: Record<string, string>) => DestMap<T> | T | Redirection | Promise<DestMap<T> | T | Redirection | {
23
+ default: T;
24
+ }>;
25
+ };
26
+ export interface SpaContext {
27
+ currentURL(): URL;
28
+ }
29
+ export {};
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ export {};
2
+ /*
3
+ export type ResolverArgs = {
4
+ path: string,
5
+ params: RouteParams,
6
+ props: RouteProps,
7
+ }
8
+ */
package/package.json CHANGED
@@ -1,17 +1,21 @@
1
1
  {
2
2
  "name": "svelte-spa-history-router",
3
- "version": "3.0.0-next.2",
3
+ "version": "3.0.1",
4
4
  "description": "History base router for Svelte SPA",
5
5
  "type": "module",
6
- "main": "src/index.ts",
7
- "svelte": "src/index.ts",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "svelte": "./dist/index.js",
8
10
  "exports": {
9
11
  ".": {
10
- "svelte": "./src/index.ts"
12
+ "svelte": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
11
14
  }
12
15
  },
13
16
  "scripts": {
14
17
  "dev": "vite",
18
+ "build": "svelte-package",
15
19
  "test": "playwright test",
16
20
  "check": "svelte-check --tsconfig ./tsconfig.app.json && tsc -p tsconfig.node.json"
17
21
  },
@@ -19,14 +23,15 @@
19
23
  "svelte": ">5.0.0"
20
24
  },
21
25
  "devDependencies": {
22
- "@playwright/test": "1.49.1",
26
+ "@playwright/test": "1.52.0",
27
+ "@sveltejs/package": "2.3.11",
23
28
  "@sveltejs/vite-plugin-svelte": "5.0.3",
24
29
  "@tsconfig/svelte": "5.0.4",
25
- "playwright": "1.49.1",
26
- "svelte": "5.16.0",
27
- "svelte-check": "4.1.1",
28
- "typescript": "5.7.2",
29
- "vite": "6.0.6"
30
+ "playwright": "1.52.0",
31
+ "svelte": "5.28.2",
32
+ "svelte-check": "4.1.6",
33
+ "typescript": "5.8.3",
34
+ "vite": "6.3.4"
30
35
  },
31
36
  "author": "ykrods",
32
37
  "license": "MIT",
@@ -1,3 +0,0 @@
1
- {
2
- "recommendations": ["svelte.svelte-vscode"]
3
- }
@@ -1,117 +0,0 @@
1
- <script lang="ts">
2
- import type { Route } from "svelte-spa-history-router"
3
- import { Router, link, push, redirect } from "svelte-spa-history-router"
4
-
5
- import type Admin from "./pages/Admin.svelte"
6
- import type Blog from "./pages/Blog.svelte"
7
- import type BlogPost from "./pages/BlogPost.svelte"
8
- import type Query from "./pages/Query.svelte"
9
-
10
- import IntParam from "./pages/IntParam.svelte"
11
- import Message from "./pages/Message.svelte"
12
- import NotFound from "./pages/NotFound.svelte"
13
- import Params from "./pages/Params.svelte"
14
- import Top from "./pages/Top.svelte"
15
-
16
- import { getArticle } from "./lib/getArticle"
17
-
18
-
19
- const routes: [
20
- Route,
21
- Route<typeof Params>,
22
- Route<typeof IntParam>,
23
- Route<typeof IntParam | typeof Message>,
24
- Route<typeof Blog>,
25
- Route<typeof BlogPost | typeof NotFound>,
26
- Route<typeof Admin>,
27
- Route<typeof Query>,
28
- Route<typeof NotFound>,
29
- ] = [
30
- { path: "/", component: Top },
31
- // path variable via params
32
- { path: "/params/(?<slug>.*)", component: Params },
33
- // typed props
34
- {
35
- path: "/int-param/(?<num>\\d+)",
36
- resolver: (params: Record<"num", string>) => ({
37
- component: IntParam,
38
- props: { num: parseInt(params.num) }
39
- }),
40
- },
41
- {
42
- path: "/conditional/(?<arg>.+)",
43
- resolver: (params: Record<"arg", string>) => {
44
- const arg = parseInt(params.arg)
45
- if (!Number.isNaN(arg)) {
46
- return { component: IntParam, props: { num: arg }}
47
- }
48
- return {
49
- component: Message,
50
- props: { message: `Unexpected param: ${params.arg}` }
51
- }
52
- }
53
- },
54
- // spliting
55
- {
56
- path: "/blog",
57
- resolver: () => import("./pages/Blog.svelte"),
58
- },
59
- // async resolver with props
60
- // path variable with slash
61
- // prefetch
62
- // spliting
63
- // return component
64
- {
65
- path: "/blog/posts/(?<slug>.*)",
66
- resolver: async (params: Record<"slug", string>) => {
67
- const article = await getArticle(params.slug);
68
- if (article) {
69
- const component = (await import("./pages/BlogPost.svelte")).default;
70
- return { component, props: { article } }
71
- } else {
72
- return NotFound;
73
- }
74
- },
75
- },
76
- // guard
77
- // redirect
78
- {
79
- path: "/admin",
80
- resolver: () => {
81
- if (user === "admin") {
82
- return import("./pages/Admin.svelte");
83
- } else {
84
- return redirect("/");
85
- }
86
- },
87
- },
88
- {
89
- path: "/query",
90
- resolver: () => import("./pages/Query.svelte")
91
- },
92
- { path: ".*", component: NotFound },
93
- ]
94
-
95
- let user = $state("anonymous");
96
- </script>
97
- <main>
98
- <header>
99
- <nav>
100
- <a use:link href="/">Top</a> |
101
- <a use:link href="/params/foo/bar">params</a> |
102
- <a use:link href="/int-param/3">int param</a> |
103
- <a use:link href="/conditional/1">conditional (1)</a> |
104
- <a use:link href="/conditional/a">conditional (a)</a> |
105
- <a use:link href="/blog">blog</a> |
106
- <a use:link href="/admin">admin</a> |
107
- <a use:link href="/query">query</a> |
108
-
109
- {#if user === "anonymous"}
110
- <button id="login" onclick={() => { user = "admin" }}>Login</button>
111
- {:else}
112
- user: { user } <button onclick={() => { user = "anonymous"; push("/"); }}>Logout</button>
113
- {/if}
114
- </nav>
115
- </header>
116
- <Router {routes} />
117
- </main>
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Vite + Svelte + TS</title>
8
- </head>
9
- <body>
10
- <div id="app"></div>
11
- <script type="module" src="/main.ts"></script>
12
- </body>
13
- </html>
@@ -1,13 +0,0 @@
1
- import type { Article } from "../types"
2
-
3
- import { getArticles } from "./getArticles"
4
-
5
-
6
- const sleep = (ms: number) => new Promise(r => setTimeout(r, ms));
7
-
8
-
9
- export async function getArticle(id: string): Promise<Article | undefined> {
10
- await sleep(50);
11
- const articles = await getArticles();
12
- return articles.find(a => a.id === id);
13
- }