lightview 1.8.2 → 2.0.0
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.
- package/.agent/workflows/daisyui-component-migration.md +155 -0
- package/.codacy/cli.sh +149 -0
- package/.codacy/codacy.yaml +15 -0
- package/.github/instructions/codacy.instructions.md +72 -0
- package/.wranglerignore +21 -0
- package/README.md +1330 -19
- package/_headers +4 -0
- package/build.js +70 -0
- package/components/actions/button.js +151 -0
- package/components/actions/dropdown.js +120 -0
- package/components/actions/modal.js +146 -0
- package/components/actions/swap.js +118 -0
- package/components/daisyui.js +288 -0
- package/components/data-display/accordion.js +128 -0
- package/components/data-display/alert.js +112 -0
- package/components/data-display/avatar.js +170 -0
- package/components/data-display/badge.js +82 -0
- package/components/data-display/card.js +151 -0
- package/components/data-display/carousel.js +94 -0
- package/components/data-display/chart.js +220 -0
- package/components/data-display/chat.js +128 -0
- package/components/data-display/collapse.js +103 -0
- package/components/data-display/countdown.js +69 -0
- package/components/data-display/diff.js +111 -0
- package/components/data-display/kbd.js +65 -0
- package/components/data-display/loading.js +75 -0
- package/components/data-display/progress.js +79 -0
- package/components/data-display/radial-progress.js +88 -0
- package/components/data-display/skeleton.js +66 -0
- package/components/data-display/stats.js +159 -0
- package/components/data-display/table.js +146 -0
- package/components/data-display/timeline.js +146 -0
- package/components/data-display/toast.js +72 -0
- package/components/data-display/tooltip.js +74 -0
- package/components/data-input/checkbox.js +253 -0
- package/components/data-input/file-input.js +224 -0
- package/components/data-input/input.js +264 -0
- package/components/data-input/radio.js +338 -0
- package/components/data-input/range.js +204 -0
- package/components/data-input/rating.js +219 -0
- package/components/data-input/select.js +287 -0
- package/components/data-input/textarea.js +287 -0
- package/components/data-input/toggle.js +201 -0
- package/components/index.js +137 -0
- package/components/layout/divider.js +72 -0
- package/components/layout/drawer.js +142 -0
- package/components/layout/footer.js +100 -0
- package/components/layout/hero.js +109 -0
- package/components/layout/indicator.js +90 -0
- package/components/layout/join.js +78 -0
- package/components/layout/navbar.js +110 -0
- package/components/navigation/breadcrumbs.js +91 -0
- package/components/navigation/dock.js +103 -0
- package/components/navigation/menu.js +126 -0
- package/components/navigation/pagination.js +105 -0
- package/components/navigation/steps.js +89 -0
- package/components/navigation/tabs.css +177 -0
- package/components/navigation/tabs.js +123 -0
- package/components/theme/theme-switch.css +65 -0
- package/components/theme/theme-switch.js +177 -0
- package/docs/about.html +164 -0
- package/docs/api/computed.html +184 -0
- package/docs/api/effects.html +173 -0
- package/docs/api/elements.html +180 -0
- package/docs/api/enhance.html +225 -0
- package/docs/api/hypermedia.html +165 -0
- package/docs/api/index.html +178 -0
- package/docs/api/nav.html +18 -0
- package/docs/api/signals.html +136 -0
- package/docs/api/state.html +217 -0
- package/docs/assets/images/logo-favicon.svg +42 -0
- package/docs/assets/images/logo-static.svg +40 -0
- package/docs/assets/images/logo.svg +66 -0
- package/docs/assets/js/examplify.js +395 -0
- package/docs/assets/styles/site.css +1102 -0
- package/docs/assets/styles/themes.css +236 -0
- package/docs/components/accordion.html +439 -0
- package/docs/components/alert.html +528 -0
- package/docs/components/avatar.html +586 -0
- package/docs/components/badge.html +531 -0
- package/docs/components/breadcrumbs.html +278 -0
- package/docs/components/button.html +579 -0
- package/docs/components/card.html +561 -0
- package/docs/components/carousel.html +286 -0
- package/docs/components/chart-area.html +702 -0
- package/docs/components/chart-bar.html +782 -0
- package/docs/components/chart-column.html +735 -0
- package/docs/components/chart-line.html +794 -0
- package/docs/components/chart-pie.html +823 -0
- package/docs/components/chart.html +610 -15
- package/docs/components/chat.html +547 -0
- package/docs/components/checkbox.html +641 -0
- package/docs/components/collapse.html +536 -0
- package/docs/components/component-nav.html +53 -0
- package/docs/components/countdown.html +470 -0
- package/docs/components/diff.html +245 -0
- package/docs/components/divider.html +240 -0
- package/docs/components/dock.html +277 -0
- package/docs/components/drawer.html +515 -0
- package/docs/components/dropdown.html +479 -0
- package/docs/components/file-input.html +591 -0
- package/docs/components/footer.html +301 -0
- package/docs/components/gallery.html +504 -0
- package/docs/components/hero.html +264 -0
- package/docs/components/index.css +840 -0
- package/docs/components/index.html +735 -0
- package/docs/components/indicator.html +342 -0
- package/docs/components/input.html +644 -0
- package/docs/components/join.html +285 -0
- package/docs/components/kbd.html +322 -0
- package/docs/components/loading.html +521 -0
- package/docs/components/menu.html +461 -0
- package/docs/components/modal.html +639 -0
- package/docs/components/navbar.html +321 -0
- package/docs/components/pagination.html +279 -0
- package/docs/components/progress.html +514 -0
- package/docs/components/radial-progress.html +434 -0
- package/docs/components/radio.html +655 -0
- package/docs/components/range.html +611 -0
- package/docs/components/rating.html +642 -0
- package/docs/components/select.html +696 -0
- package/docs/components/sidebar-setup.js +93 -0
- package/docs/components/skeleton.html +447 -0
- package/docs/components/spinner.html +68 -0
- package/docs/components/stats.html +486 -0
- package/docs/components/steps.html +356 -0
- package/docs/components/swap.html +517 -0
- package/docs/components/switch.html +68 -0
- package/docs/components/table.html +668 -0
- package/docs/components/tabs.html +506 -0
- package/docs/components/text-input.html +68 -0
- package/docs/components/textarea.html +603 -0
- package/docs/components/timeline.html +485 -42
- package/docs/components/toast.html +474 -0
- package/docs/components/toggle.html +564 -0
- package/docs/components/tooltip.html +423 -0
- package/docs/examples/getting-started-example.html +40 -0
- package/docs/examples/index.html +93 -0
- package/docs/getting-started/index.html +739 -0
- package/docs/getting-started/reviews.html +23 -0
- package/docs/getting-started/reviews.odom +108 -0
- package/docs/getting-started/reviews.vdom +84 -0
- package/docs/index.html +132 -42
- package/docs/playground.html +416 -0
- package/docs/router.html +285 -0
- package/docs/styles/index.html +190 -0
- package/functions/_middleware.js +32 -0
- package/index.html +309 -0
- package/lightview-router.js +364 -0
- package/lightview-x.js +1577 -0
- package/lightview.js +659 -1200
- package/lightview.js.backup +793 -0
- package/middleware/locale.js +25 -0
- package/middleware/markdown.js +44 -0
- package/middleware/notFound.js +37 -0
- package/package.json +27 -41
- package/watch.js +92 -0
- package/wrangler.toml +12 -0
- package/.idea/lightview.iml +0 -12
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/LICENSE +0 -21
- package/codepen-no-tabs-embed.css +0 -2
- package/docs/CNAME +0 -1
- package/docs/api.html +0 -674
- package/docs/blank.html +0 -10
- package/docs/comparedto.html +0 -89
- package/docs/components/chart-repl.html +0 -69
- package/docs/components/components.js +0 -113
- package/docs/components/contents.html +0 -17
- package/docs/components/gantt-repl.html +0 -61
- package/docs/components/gantt.html +0 -42
- package/docs/components/gauge-repl.html +0 -66
- package/docs/components/gauge.html +0 -20
- package/docs/components/orgchart-repl.html +0 -64
- package/docs/components/orgchart.html +0 -41
- package/docs/components/repl-as-src.html +0 -17
- package/docs/components/repl-repl.html +0 -95
- package/docs/components/repl.html +0 -527
- package/docs/components/timeline-repl.html +0 -72
- package/docs/components.html +0 -14
- package/docs/css/highlightjs.min.css +0 -9
- package/docs/css/tutorial.css +0 -35
- package/docs/examples/anchor.html +0 -11
- package/docs/examples/chart.html +0 -34
- package/docs/examples/counter.html +0 -26
- package/docs/examples/counter.test.mjs +0 -47
- package/docs/examples/counter2.html +0 -26
- package/docs/examples/directives.html +0 -79
- package/docs/examples/foreign.html +0 -50
- package/docs/examples/forgeinform.html +0 -98
- package/docs/examples/form.html +0 -61
- package/docs/examples/gauge.html +0 -18
- package/docs/examples/invalid-template-literals.html +0 -44
- package/docs/examples/medium/remote.html +0 -60
- package/docs/examples/message.html +0 -18
- package/docs/examples/nested.html +0 -11
- package/docs/examples/object-bound-form.html +0 -34
- package/docs/examples/remote-server.js +0 -51
- package/docs/examples/remote.html +0 -34
- package/docs/examples/remote.json +0 -1
- package/docs/examples/scratch.html +0 -69
- package/docs/examples/sensors/index.html +0 -44
- package/docs/examples/sensors/sensor-server.js +0 -30
- package/docs/examples/shared.html +0 -41
- package/docs/examples/template.html +0 -33
- package/docs/examples/timeline.html +0 -21
- package/docs/examples/todo.html +0 -40
- package/docs/examples/top.html +0 -10
- package/docs/examples/types.html +0 -94
- package/docs/examples/xor.html +0 -62
- package/docs/examples.html +0 -25
- package/docs/javascript/codejar.min.js +0 -8
- package/docs/javascript/highlightjs.min.js +0 -1173
- package/docs/javascript/isomorphic-git.js +0 -9
- package/docs/javascript/json5.min.js +0 -1
- package/docs/javascript/lightning-fs.js +0 -1
- package/docs/javascript/lightview.js +0 -1285
- package/docs/javascript/marked.min.js +0 -6
- package/docs/javascript/peerjs.min.js +0 -70
- package/docs/javascript/turndown.js +0 -973
- package/docs/javascript/types.js +0 -606
- package/docs/javascript/utils.js +0 -45
- package/docs/lightview.html +0 -63
- package/docs/old_index.html +0 -965
- package/docs/old_index.md +0 -1132
- package/docs/slidein.html +0 -51
- package/docs/tutorial/0-getting-started.html +0 -67
- package/docs/tutorial/1-intro-to-variables.html +0 -103
- package/docs/tutorial/10-template-components.html +0 -80
- package/docs/tutorial/11-linked-components.html +0 -76
- package/docs/tutorial/12-imported-components.html +0 -67
- package/docs/tutorial/13-input-binding.html +0 -94
- package/docs/tutorial/14-automatic-variable-creation.html +0 -74
- package/docs/tutorial/15-form-binding.html +0 -110
- package/docs/tutorial/16-if-directive.html +0 -60
- package/docs/tutorial/17-loop-directives.html +0 -83
- package/docs/tutorial/18-sanitizing-and-escaping-input.html +0 -79
- package/docs/tutorial/2-imported-and-exported-variables.html +0 -80
- package/docs/tutorial/3-data-types.html +0 -89
- package/docs/tutorial/4-extended-data-types.html +0 -83
- package/docs/tutorial/5-extended-functional-types.html +0 -96
- package/docs/tutorial/5.1-extended-functional-types.html +0 -79
- package/docs/tutorial/5.2-extended-functional-types.html +0 -70
- package/docs/tutorial/6-conventional-javascript.html +0 -75
- package/docs/tutorial/7-monitoring-with-observers.html +0 -107
- package/docs/tutorial/8-event-listeners.html +0 -65
- package/docs/tutorial/9-intro-to-components.html +0 -91
- package/docs/tutorial/contents.html +0 -32
- package/docs/tutorial/my-component.html +0 -29
- package/docs/tutorial/remote-value.json +0 -4
- package/docs/websiterepl.html +0 -46
- package/jest-puppeteer.config.js +0 -5
- package/jest.config.json +0 -12
- package/lightview.min.js +0 -1
- package/lightview_good.js +0 -1267
- package/lightview_optimized.js +0 -1274
- package/repl_hold.html +0 -320
- package/test/basic.html +0 -104
- package/test/basic.test.mjs +0 -315
- package/test/extended.html +0 -29
- package/test/extended.test.mjs +0 -448
- package/types.js +0 -607
- package/unsplash.key +0 -1
package/docs/router.html
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
<!-- SEO-friendly SPA Shim -->
|
|
2
|
+
<script src="/lightview-router.js"></script>
|
|
3
|
+
<script>
|
|
4
|
+
if (window.LightviewRouter) {
|
|
5
|
+
LightviewRouter.base('/index.html');
|
|
6
|
+
}
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="section">
|
|
10
|
+
<div class="section-content" style="max-width: 800px;">
|
|
11
|
+
<h1>Lightview Router</h1>
|
|
12
|
+
<p class="text-secondary" style="font-size: 1.125rem;">
|
|
13
|
+
A lightweight, pipeline-based History API router with middleware support.
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<h2>Overview</h2>
|
|
17
|
+
<p>
|
|
18
|
+
The Lightview Router provides a simple yet powerful way to handle client-side routing in your application.
|
|
19
|
+
It supports standard routes, wildcards, named parameters, and middleware pipelines.
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<h3>Features</h3>
|
|
23
|
+
<ul>
|
|
24
|
+
<li>Pipeline-based routing (middleware style)</li>
|
|
25
|
+
<li>History API integration</li>
|
|
26
|
+
<li>Zero dependencies</li>
|
|
27
|
+
<li>Route parameters <code>/user/:id</code></li>
|
|
28
|
+
<li>Wildcard support <code>/api/*</code></li>
|
|
29
|
+
<li>Async handler support</li>
|
|
30
|
+
<li>Locale prefix handling</li>
|
|
31
|
+
<li>Markdown rendering</li>
|
|
32
|
+
</ul>
|
|
33
|
+
|
|
34
|
+
<h2>Basic Usage</h2>
|
|
35
|
+
<p>Initialize the router with a target element and define your routes.</p>
|
|
36
|
+
|
|
37
|
+
<div class="code-block">
|
|
38
|
+
<pre><code>import { LightviewRouter } from '/lightview-router.js';
|
|
39
|
+
|
|
40
|
+
// 1. Initialize
|
|
41
|
+
const appRouter = LightviewRouter.router({
|
|
42
|
+
contentEl: document.getElementById('app'), // Routes will render here automatically
|
|
43
|
+
|
|
44
|
+
// Optional: Lifecycle hooks
|
|
45
|
+
// onStart: (path) => console.log('Loading...'),
|
|
46
|
+
// notFound: (path) => console.log('404 Not Found')
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 2. Register routes
|
|
50
|
+
// Simple path mapping (fetches /index.html -> renders to #app)
|
|
51
|
+
appRouter.use('/', '/index.html');
|
|
52
|
+
|
|
53
|
+
// Self-mapping (fetches /about.html -> renders to #app)
|
|
54
|
+
appRouter.use('/about.html');
|
|
55
|
+
|
|
56
|
+
// Wildcards (fetches matching path -> renders to #app)
|
|
57
|
+
appRouter.use('/docs/*');
|
|
58
|
+
|
|
59
|
+
// 3. Start listening
|
|
60
|
+
appRouter.start();</code></pre>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<h2>Middleware & Pipelines</h2>
|
|
64
|
+
<p>
|
|
65
|
+
Lightview Router uses a "chain of responsibility" pattern. When you register a route, you can provide
|
|
66
|
+
multiple handlers.
|
|
67
|
+
</p>
|
|
68
|
+
<p>
|
|
69
|
+
<strong>Automatic Rendering:</strong> If you provide <code>contentEl</code> and your route chain ends with a
|
|
70
|
+
string (or has no handlers),
|
|
71
|
+
the router automatically appends a handler that fetches the path and renders it to <code>contentEl</code>.
|
|
72
|
+
</p>
|
|
73
|
+
<p>
|
|
74
|
+
You can still define manual handlers for advanced logic:
|
|
75
|
+
</p>
|
|
76
|
+
|
|
77
|
+
<div class="feature-grid" style="margin: 2rem 0;">
|
|
78
|
+
<div class="feature-card">
|
|
79
|
+
<h3 class="feature-title">➡️ Continue Chain</h3>
|
|
80
|
+
<p>
|
|
81
|
+
If a handler returns <strong>null</strong>, <strong>undefined</strong>, or a <strong>context
|
|
82
|
+
object</strong>, the router continues to the next handler in the chain.
|
|
83
|
+
</p>
|
|
84
|
+
<p class="text-secondary" style="font-size: 0.875rem;">Use this for logging, auth checks, or
|
|
85
|
+
transforming the path.</p>
|
|
86
|
+
<pre style="margin-top: 1rem;"><code>// Middleware
|
|
87
|
+
const logger = (ctx) => {
|
|
88
|
+
console.log('Visiting:', ctx.path);
|
|
89
|
+
// Returns undefined, so routing continues
|
|
90
|
+
};</code></pre>
|
|
91
|
+
</div>
|
|
92
|
+
<div class="feature-card">
|
|
93
|
+
<h3 class="feature-title">🛑 Stop & Return</h3>
|
|
94
|
+
<p>
|
|
95
|
+
If a handler returns a <strong>Response</strong> object, the chain stops immediately, and the router
|
|
96
|
+
considers the navigation complete.
|
|
97
|
+
</p>
|
|
98
|
+
<p class="text-secondary" style="font-size: 0.875rem;">Use this for custom API responses or redirects.
|
|
99
|
+
</p>
|
|
100
|
+
<pre style="margin-top: 1rem;"><code>// Final Handler
|
|
101
|
+
const loadPage = async (ctx) => {
|
|
102
|
+
return await fetch(ctx.path);
|
|
103
|
+
// Returns Response, stops routing
|
|
104
|
+
};</code></pre>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<h3>Example Pipeline</h3>
|
|
109
|
+
<div class="code-block">
|
|
110
|
+
<pre><code>appRouter.use('/admin/*',
|
|
111
|
+
// 1. Authentication Middleware
|
|
112
|
+
(ctx) => {
|
|
113
|
+
if (!user.isLoggedIn) {
|
|
114
|
+
router.navigate('/login');
|
|
115
|
+
return new Response('Redirecting...'); // Stop chain
|
|
116
|
+
}
|
|
117
|
+
// User is logged in, continue...
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// 2. Logging Middleware
|
|
121
|
+
(ctx) => {
|
|
122
|
+
console.log('Admin access at', new Date());
|
|
123
|
+
// implicitly returns undefined, continues...
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
// 3. Implicit Fetch (if contentEl is set)
|
|
127
|
+
// The router automatically fetches /admin/* and renders it
|
|
128
|
+
);</code></pre>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<h2>Advanced Usage</h2>
|
|
132
|
+
|
|
133
|
+
<h3>Functional Arguments</h3>
|
|
134
|
+
<p>
|
|
135
|
+
The <code>use(...)</code> method accepts a variadic list of arguments. While standard usage involves strings
|
|
136
|
+
for
|
|
137
|
+
matching and replacement, you can pass functions for any argument to achieve fine-grained control.
|
|
138
|
+
</p>
|
|
139
|
+
<p>
|
|
140
|
+
Internally, all strings and regexes are converted to functions. Passing a function directly gives you access
|
|
141
|
+
to the raw context pipeline.
|
|
142
|
+
</p>
|
|
143
|
+
|
|
144
|
+
<h3>Anatomy of a <code>use()</code> call</h3>
|
|
145
|
+
<p>
|
|
146
|
+
<code>appRouter.use(Matcher, ...Middleware);</code>
|
|
147
|
+
</p>
|
|
148
|
+
<ul>
|
|
149
|
+
<li><strong>Matcher (Arg 0):</strong> Determines if this chain runs. Returns a context object (continue) or
|
|
150
|
+
null (skip).</li>
|
|
151
|
+
<li><strong>Middleware (Args 1...n):</strong> Logic that executes if the matcher succeeds.</li>
|
|
152
|
+
</ul>
|
|
153
|
+
|
|
154
|
+
<div class="code-block">
|
|
155
|
+
<pre><code>appRouter.use(
|
|
156
|
+
// Argument 1: The Matcher
|
|
157
|
+
// Can be a string '/path', regex /path/, or function
|
|
158
|
+
(ctx) => {
|
|
159
|
+
// Custom matching logic
|
|
160
|
+
if (ctx.path.includes('secret') && user.isAdmin) {
|
|
161
|
+
return ctx; // Match!
|
|
162
|
+
}
|
|
163
|
+
return null; // No match, try next route
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// Argument 2: Middleware / Logic
|
|
167
|
+
(ctx) => {
|
|
168
|
+
console.log('Secret route accessed');
|
|
169
|
+
// Modify the context for the next handler
|
|
170
|
+
return { ...ctx, path: '/admin/secret.html' };
|
|
171
|
+
}
|
|
172
|
+
// Note: If no implementation is provided and contentEl is set,
|
|
173
|
+
// the router automatically appends a fetch handler for the final path.
|
|
174
|
+
);</code></pre>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
<h2>API Reference</h2>
|
|
178
|
+
|
|
179
|
+
<h3><code>LightviewRouter.router(options)</code></h3>
|
|
180
|
+
<p>Creates a new router instance.</p>
|
|
181
|
+
<p><strong>Options:</strong></p>
|
|
182
|
+
<ul>
|
|
183
|
+
<li><code>contentEl</code> (HTMLElement): Element to automatically render content into.</li>
|
|
184
|
+
<li><code>base</code> (string): Base path for the router.</li>
|
|
185
|
+
<li><code>onStart</code> (function): Callback when navigation begins.</li>
|
|
186
|
+
<li><code>onResponse</code> (function): Callback when a handler returns a response.</li>
|
|
187
|
+
</ul>
|
|
188
|
+
|
|
189
|
+
<h2>Built-in Middleware</h2>
|
|
190
|
+
|
|
191
|
+
<h3><code>localeHandler(ctx)</code></h3>
|
|
192
|
+
<p>
|
|
193
|
+
Extracts locale prefixes (e.g., <code>/en/about</code>) from the path. It modifies the context
|
|
194
|
+
by stripping the prefix (<code>/about</code>) and adding a <code>locale</code> property.
|
|
195
|
+
</p>
|
|
196
|
+
<p><strong>Usage:</strong> Add it early in your chain so subsequent handlers see the clean path.</p>
|
|
197
|
+
<div class="code-block">
|
|
198
|
+
<pre><code>import { localeHandler } from '/middleware/locale.js';
|
|
199
|
+
|
|
200
|
+
appRouter.use('/*', localeHandler);
|
|
201
|
+
|
|
202
|
+
// If user visits /en/about:
|
|
203
|
+
// 1. localeHandler strips /en/, sets ctx.locale = 'en'
|
|
204
|
+
// 2. Next handlers see ctx.path = '/about'</code></pre>
|
|
205
|
+
</div>
|
|
206
|
+
|
|
207
|
+
<h3><code>markdownHandler(ctx)</code></h3>
|
|
208
|
+
<p>
|
|
209
|
+
Intercepts requests for <code>.md</code> files, fetches the content, parses it using <code>marked.js</code>
|
|
210
|
+
(loaded on demand), and renders the resulting HTML.
|
|
211
|
+
</p>
|
|
212
|
+
<p><strong>Returns:</strong> A <code>Response</code> object (stops the route chain).</p>
|
|
213
|
+
<div class="code-block">
|
|
214
|
+
<pre><code>import { markdownHandler } from '/middleware/markdown.js';
|
|
215
|
+
|
|
216
|
+
// Handle all markdown files
|
|
217
|
+
appRouter.use('/*.md', markdownHandler);</code></pre>
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<h3><code>notFound(options)</code></h3>
|
|
221
|
+
<p>A final middleware that handles 404 errors when no other route matches.</p>
|
|
222
|
+
<p><strong>Usage:</strong> Add it as the very last route in your configuration.</p>
|
|
223
|
+
|
|
224
|
+
<div class="code-block">
|
|
225
|
+
<pre><code>import { notFound } from '/middleware/notFound.js';
|
|
226
|
+
|
|
227
|
+
appRouter.use(notFound({
|
|
228
|
+
// contentEl: inherited from router options,
|
|
229
|
+
html: '<h1>404 Not Found</h1>' // Optional custom HTML
|
|
230
|
+
}));</code></pre>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<h3><code>router.use(pattern, ...handlers)</code></h3>
|
|
234
|
+
<p>Registers a route or middleware.</p>
|
|
235
|
+
|
|
236
|
+
<p><strong>Pattern types:</strong></p>
|
|
237
|
+
<ul>
|
|
238
|
+
<li><strong>String literal:</strong> <code>'/about'</code> - Exact match.</li>
|
|
239
|
+
<li><strong>Wildcard:</strong> <code>'/api/*'</code> - Matches any path starting with /api/.</li>
|
|
240
|
+
<li><strong>Parameter:</strong> <code>'/user/:id'</code> - Captures <code>:id</code> as a parameter.</li>
|
|
241
|
+
</ul>
|
|
242
|
+
|
|
243
|
+
<h3><code>router.navigate(path)</code></h3>
|
|
244
|
+
<p>Programmatically navigate to a new path.</p>
|
|
245
|
+
<div class="code-block">
|
|
246
|
+
<pre><code>router.navigate('/profile/settings');</code></pre>
|
|
247
|
+
</div>
|
|
248
|
+
|
|
249
|
+
<h3>Context Object</h3>
|
|
250
|
+
<p>Handlers receive a <code>context</code> object containing:</p>
|
|
251
|
+
<ul>
|
|
252
|
+
<li><code>path</code>: The current normalized path.</li>
|
|
253
|
+
<li><code>params</code>: Object containing named parameters (if any).</li>
|
|
254
|
+
<li><code>wildcard</code>: Content of the wildcard match (if any).</li>
|
|
255
|
+
<li><code>contentEl</code>: The main content element (allows middleware to render content or override the
|
|
256
|
+
target).</li>
|
|
257
|
+
</ul>
|
|
258
|
+
|
|
259
|
+
<h2>Advanced Configuration</h2>
|
|
260
|
+
<p>
|
|
261
|
+
The <code>router()</code> constructor accepts an options object for lifecycle hooks and error handling.
|
|
262
|
+
</p>
|
|
263
|
+
|
|
264
|
+
<div class="code-block">
|
|
265
|
+
<pre><code>const appRouter = LightviewRouter.router({
|
|
266
|
+
contentEl: document.getElementById('app'),
|
|
267
|
+
|
|
268
|
+
// Lifecycle: Called when navigation triggers (e.g., click or back button)
|
|
269
|
+
// Good for starting loading spinners
|
|
270
|
+
onStart: (path) => {
|
|
271
|
+
document.getElementById('spinner').style.display = 'block';
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// Lifecycle: Called AFTER auto-render completes
|
|
275
|
+
// Good for post-render logic like analytics or scroll position
|
|
276
|
+
onResponse: (response, path) => {
|
|
277
|
+
document.getElementById('spinner').style.display = 'none';
|
|
278
|
+
window.scrollTo(0, 0);
|
|
279
|
+
// Run additional logic here (analytics, etc.)
|
|
280
|
+
}
|
|
281
|
+
});</code></pre>
|
|
282
|
+
</div>
|
|
283
|
+
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
<!-- SEO-friendly SPA Shim -->
|
|
2
|
+
<script src="/lightview-router.js"></script>
|
|
3
|
+
<script>
|
|
4
|
+
if (window.LightviewRouter) {
|
|
5
|
+
LightviewRouter.base('/index.html');
|
|
6
|
+
}
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<div class="section">
|
|
10
|
+
<div class="section-content" style="max-width: 1000px;">
|
|
11
|
+
<h1>Styles</h1>
|
|
12
|
+
<p class="text-lg opacity-70 mb-6">
|
|
13
|
+
Lightview components use <strong>DaisyUI</strong> for styling — a complete component library
|
|
14
|
+
built on top of Tailwind CSS with 12+ themes and 50+ components.
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<!-- (DaisyUI Styles removed to prevent global conflicts. Content below uses Shadow DOM isolation) -->
|
|
18
|
+
|
|
19
|
+
<!-- Include DaisyUI -->
|
|
20
|
+
<section class="mb-12">
|
|
21
|
+
<h2 class="text-2xl font-bold mb-4">Including DaisyUI</h2>
|
|
22
|
+
<p class="opacity-70 mb-4">DaisyUI and Tailwind pollute the global CSS space and redefine things like H1. By
|
|
23
|
+
default Lightview components isolate DaisyUI and Tailwind styles to Shadow DOM. If you would like to
|
|
24
|
+
use DaisyUI and Tailwind styles outside of Shadow DOM, add DaisyUI and Tailwind to your HTML:</p>
|
|
25
|
+
<pre class="bg-base-300 p-4 rounded-lg text-sm overflow-x-auto"><code><!-- DaisyUI + Tailwind CSS (CDN) -->
|
|
26
|
+
<link href="https://cdn.jsdelivr.net/npm/daisyui@3.9.4/dist/full.min.css" rel="stylesheet" type="text/css" />
|
|
27
|
+
<script src="https://cdn.tailwindcss.com"></script></code></pre>
|
|
28
|
+
</section>
|
|
29
|
+
|
|
30
|
+
<!-- Themes -->
|
|
31
|
+
<section class="mb-12">
|
|
32
|
+
<h2 class="text-2xl font-bold mb-4">Themes</h2>
|
|
33
|
+
<p class="opacity-70 mb-4">DaisyUI includes many built-in themes. You can try these themes by selecting a
|
|
34
|
+
theme using the dropdown in the top right corner of this page. This will impact the theme colors
|
|
35
|
+
globally across all components.</p>
|
|
36
|
+
</section>
|
|
37
|
+
|
|
38
|
+
<!-- Theme Colors Preview (Using Lightview Components) -->
|
|
39
|
+
<section class="mb-12">
|
|
40
|
+
<h2 class="text-2xl font-bold mb-4">Theme Colors</h2>
|
|
41
|
+
<p class="opacity-70 mb-4">Each theme provides semantic color variables. Here is how they look in the
|
|
42
|
+
current theme:</p>
|
|
43
|
+
<div id="theme-colors-preview" class="mb-6"></div>
|
|
44
|
+
</section>
|
|
45
|
+
|
|
46
|
+
<!-- Base Colors (Using Reactive Cards) -->
|
|
47
|
+
<section class="mb-12">
|
|
48
|
+
<h2 class="text-2xl font-bold mb-4">Base Colors</h2>
|
|
49
|
+
<p class="opacity-70 mb-4">Background and surface colors for consistent UI in the current theme:</p>
|
|
50
|
+
<div id="base-colors-preview" class="mb-6"></div>
|
|
51
|
+
</section>
|
|
52
|
+
|
|
53
|
+
<script type="module">
|
|
54
|
+
await import('/components/actions/button.js');
|
|
55
|
+
await import('/components/data-display/card.js');
|
|
56
|
+
|
|
57
|
+
// Wait for Lightview if loaded async
|
|
58
|
+
const init = () => {
|
|
59
|
+
if (!window.Lightview) return setTimeout(init, 50);
|
|
60
|
+
|
|
61
|
+
const { tags, $ } = Lightview;
|
|
62
|
+
const { div, span, p, Button, Card } = tags;
|
|
63
|
+
|
|
64
|
+
// Render Theme Colors Buttons
|
|
65
|
+
$('#theme-colors-preview').content(
|
|
66
|
+
div({ style: 'display: flex; flex-wrap: wrap; gap: 0.5rem;' },
|
|
67
|
+
Button({ color: 'primary' }, 'Primary'),
|
|
68
|
+
Button({ color: 'secondary' }, 'Secondary'),
|
|
69
|
+
Button({ color: 'accent' }, 'Accent'),
|
|
70
|
+
Button({ color: 'neutral' }, 'Neutral'),
|
|
71
|
+
Button({ color: 'info' }, 'Info'),
|
|
72
|
+
Button({ color: 'success' }, 'Success'),
|
|
73
|
+
Button({ color: 'warning' }, 'Warning'),
|
|
74
|
+
Button({ color: 'error' }, 'Error')
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Render Base Colors using actual Card components
|
|
79
|
+
const cardStyle = 'text-align: center;';
|
|
80
|
+
|
|
81
|
+
$('#base-colors-preview').content(
|
|
82
|
+
div({ style: 'display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1.5rem;' },
|
|
83
|
+
Card({ bg: 'base-100', useShadow: true, class: 'border border-base-300' },
|
|
84
|
+
Card.Body({ style: 'align-items: center; text-align: center;' },
|
|
85
|
+
Card.Title({ style: 'font-size: 1rem;' }, 'base-100'),
|
|
86
|
+
p({ style: 'font-size: 0.875rem; opacity: 0.7;' }, 'Main Background')
|
|
87
|
+
)
|
|
88
|
+
),
|
|
89
|
+
Card({ bg: 'base-200', useShadow: true },
|
|
90
|
+
Card.Body({ style: 'align-items: center; text-align: center;' },
|
|
91
|
+
Card.Title({ style: 'font-size: 1rem;' }, 'base-200'),
|
|
92
|
+
p({ style: 'font-size: 0.875rem; opacity: 0.7;' }, 'Secondary')
|
|
93
|
+
)
|
|
94
|
+
),
|
|
95
|
+
Card({ bg: 'base-300', useShadow: true },
|
|
96
|
+
Card.Body({ style: 'align-items: center; text-align: center;' },
|
|
97
|
+
Card.Title({ style: 'font-size: 1rem;' }, 'base-300'),
|
|
98
|
+
p({ style: 'font-size: 0.875rem; opacity: 0.7;' }, 'Tertiary')
|
|
99
|
+
)
|
|
100
|
+
),
|
|
101
|
+
Card({ bg: 'base-content', class: 'text-base-100', useShadow: true },
|
|
102
|
+
Card.Body({ style: 'align-items: center; text-align: center;' },
|
|
103
|
+
Card.Title({ style: 'font-size: 1rem;' }, 'base-content'),
|
|
104
|
+
p({ style: 'font-size: 0.875rem; opacity: 0.7;' }, 'Content/Text')
|
|
105
|
+
)
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
init();
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<!-- Registering Stylesheets -->
|
|
115
|
+
<section class="mb-12">
|
|
116
|
+
<h2 class="text-2xl font-bold mb-4">Registering Stylesheets</h2>
|
|
117
|
+
<p class="opacity-70 mb-4">
|
|
118
|
+
When using Shadow DOM, global styles are not inherited. <code>LightviewX</code> provides methods to
|
|
119
|
+
register stylesheets that can be adopted by components or applied globally to all components.
|
|
120
|
+
</p>
|
|
121
|
+
|
|
122
|
+
<h3 class="text-xl font-bold mb-2">Named Stylesheets</h3>
|
|
123
|
+
<p class="opacity-70 mb-4">
|
|
124
|
+
Register a stylesheet by name, and components can then request it by ID. You can register styles from a
|
|
125
|
+
string, a URL, or an existing <code><style></code> tag.
|
|
126
|
+
</p>
|
|
127
|
+
<pre class="bg-base-300 p-4 rounded-lg text-sm overflow-x-auto mb-6"><code>// From a CSS string
|
|
128
|
+
LightviewX.registerStyleSheet('custom-vars', ':host { --my-color: #ff00ff; }');
|
|
129
|
+
|
|
130
|
+
// From a URL
|
|
131
|
+
LightviewX.registerStyleSheet('/styles/extra.css');
|
|
132
|
+
|
|
133
|
+
// From an existing style tag in the document
|
|
134
|
+
LightviewX.registerStyleSheet('#global-overrides');</code></pre>
|
|
135
|
+
|
|
136
|
+
<h3 class="text-xl font-bold mb-2">Global Theme Stylesheets</h3>
|
|
137
|
+
<p class="opacity-70 mb-4">
|
|
138
|
+
To apply a stylesheet to every Shadow DOM component automatically (like a global theme override),
|
|
139
|
+
use <code>registerThemeSheet</code>.
|
|
140
|
+
</p>
|
|
141
|
+
<pre class="bg-base-300 p-4 rounded-lg text-sm overflow-x-auto mb-6"><code>// This sheet will be adopted by all components
|
|
142
|
+
LightviewX.registerThemeSheet('/styles/theme-overrides.css');</code></pre>
|
|
143
|
+
|
|
144
|
+
<p class="opacity-70">
|
|
145
|
+
For more details on these functions, see the <a href="../api/" class="link">API Reference</a>.
|
|
146
|
+
</p>
|
|
147
|
+
</section>
|
|
148
|
+
|
|
149
|
+
<!-- Controlling Themes -->
|
|
150
|
+
<section class="mb-12">
|
|
151
|
+
<h2 class="text-2xl font-bold mb-4">Controlling Themes Programmatically</h2>
|
|
152
|
+
<p class="opacity-70 mb-4">You can control the active theme globally using <code>LightviewX</code>.</p>
|
|
153
|
+
|
|
154
|
+
<h3 class="text-xl font-bold mb-2">Setting the Theme</h3>
|
|
155
|
+
<p class="opacity-70 mb-4">Use <code>setTheme</code> to change the active theme. This updates the
|
|
156
|
+
<code>themeSignal</code> and persists the choice to LocalStorage.
|
|
157
|
+
</p>
|
|
158
|
+
<pre class="bg-base-300 p-4 rounded-lg text-sm overflow-x-auto mb-6"><code>// Set theme to 'dark'
|
|
159
|
+
LightviewX.setTheme('dark');
|
|
160
|
+
|
|
161
|
+
// Set theme to 'cyberpunk'
|
|
162
|
+
LightviewX.setTheme('cyberpunk');</code></pre>
|
|
163
|
+
|
|
164
|
+
<h3 class="text-xl font-bold mb-2">Reactive Theme Signal</h3>
|
|
165
|
+
<p class="opacity-70 mb-4">Access the current theme reactively using <code>LightviewX.themeSignal</code>.
|
|
166
|
+
</p>
|
|
167
|
+
<pre class="bg-base-300 p-4 rounded-lg text-sm overflow-x-auto"><code>const { themeSignal } = LightviewX;
|
|
168
|
+
|
|
169
|
+
// Build a reactive component that logs the theme
|
|
170
|
+
const ThemeLogger = () => {
|
|
171
|
+
return div({}, () => `Current theme is: ${themeSignal.value}`);
|
|
172
|
+
};</code></pre>
|
|
173
|
+
</section>
|
|
174
|
+
|
|
175
|
+
<!-- DaisyUI Documentation Link -->
|
|
176
|
+
<div class="alert alert-info">
|
|
177
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
|
178
|
+
class="h-6 w-6 shrink-0 stroke-current">
|
|
179
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
180
|
+
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
181
|
+
</svg>
|
|
182
|
+
<div>
|
|
183
|
+
<h3 class="font-bold">Full DaisyUI Documentation</h3>
|
|
184
|
+
<div class="text-sm">For complete styling options, themes, and utilities, visit the
|
|
185
|
+
<a href="https://daisyui.com" target="_blank" rel="noopener" class="link">DaisyUI documentation</a>.
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
|
|
4
|
+
export const onRequest = async (context) => {
|
|
5
|
+
const url = new URL(context.request.url);
|
|
6
|
+
|
|
7
|
+
// Intercept requests for .md files
|
|
8
|
+
if (url.pathname.endsWith('.md')) {
|
|
9
|
+
|
|
10
|
+
// Fetch the asset (the actual markdown file)
|
|
11
|
+
const response = await context.next();
|
|
12
|
+
|
|
13
|
+
// If the file exists and was retrieved successfully
|
|
14
|
+
if (response.ok) {
|
|
15
|
+
const text = await response.text();
|
|
16
|
+
|
|
17
|
+
// Convert markdown to HTML
|
|
18
|
+
// marked.parse is synchronous by default but can be async
|
|
19
|
+
const html = await marked.parse(text);
|
|
20
|
+
|
|
21
|
+
return new Response(html, {
|
|
22
|
+
status: 200,
|
|
23
|
+
headers: {
|
|
24
|
+
'content-type': 'text/html;charset=UTF-8',
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Pass through for all other requests
|
|
31
|
+
return context.next();
|
|
32
|
+
};
|