lightview 1.8.1-b → 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.
Files changed (224) hide show
  1. package/.agent/workflows/daisyui-component-migration.md +155 -0
  2. package/.codacy/cli.sh +149 -0
  3. package/.codacy/codacy.yaml +15 -0
  4. package/.github/instructions/codacy.instructions.md +72 -0
  5. package/.wranglerignore +21 -0
  6. package/README.md +1331 -21
  7. package/_headers +4 -0
  8. package/build.js +70 -0
  9. package/components/actions/button.js +151 -0
  10. package/components/actions/dropdown.js +120 -0
  11. package/components/actions/modal.js +146 -0
  12. package/components/actions/swap.js +118 -0
  13. package/components/daisyui.js +288 -0
  14. package/components/data-display/accordion.js +128 -0
  15. package/components/data-display/alert.js +112 -0
  16. package/components/data-display/avatar.js +170 -0
  17. package/components/data-display/badge.js +82 -0
  18. package/components/data-display/card.js +151 -0
  19. package/components/data-display/carousel.js +94 -0
  20. package/components/data-display/chart.js +220 -0
  21. package/components/data-display/chat.js +128 -0
  22. package/components/data-display/collapse.js +103 -0
  23. package/components/data-display/countdown.js +69 -0
  24. package/components/data-display/diff.js +111 -0
  25. package/components/data-display/kbd.js +65 -0
  26. package/components/data-display/loading.js +75 -0
  27. package/components/data-display/progress.js +79 -0
  28. package/components/data-display/radial-progress.js +88 -0
  29. package/components/data-display/skeleton.js +66 -0
  30. package/components/data-display/stats.js +159 -0
  31. package/components/data-display/table.js +146 -0
  32. package/components/data-display/timeline.js +146 -0
  33. package/components/data-display/toast.js +72 -0
  34. package/components/data-display/tooltip.js +74 -0
  35. package/components/data-input/checkbox.js +253 -0
  36. package/components/data-input/file-input.js +224 -0
  37. package/components/data-input/input.js +264 -0
  38. package/components/data-input/radio.js +338 -0
  39. package/components/data-input/range.js +204 -0
  40. package/components/data-input/rating.js +219 -0
  41. package/components/data-input/select.js +287 -0
  42. package/components/data-input/textarea.js +287 -0
  43. package/components/data-input/toggle.js +201 -0
  44. package/components/index.js +137 -0
  45. package/components/layout/divider.js +72 -0
  46. package/components/layout/drawer.js +142 -0
  47. package/components/layout/footer.js +100 -0
  48. package/components/layout/hero.js +109 -0
  49. package/components/layout/indicator.js +90 -0
  50. package/components/layout/join.js +78 -0
  51. package/components/layout/navbar.js +110 -0
  52. package/components/navigation/breadcrumbs.js +91 -0
  53. package/components/navigation/dock.js +103 -0
  54. package/components/navigation/menu.js +126 -0
  55. package/components/navigation/pagination.js +105 -0
  56. package/components/navigation/steps.js +89 -0
  57. package/components/navigation/tabs.css +177 -0
  58. package/components/navigation/tabs.js +123 -0
  59. package/components/theme/theme-switch.css +65 -0
  60. package/components/theme/theme-switch.js +177 -0
  61. package/docs/about.html +164 -0
  62. package/docs/api/computed.html +184 -0
  63. package/docs/api/effects.html +173 -0
  64. package/docs/api/elements.html +180 -0
  65. package/docs/api/enhance.html +225 -0
  66. package/docs/api/hypermedia.html +165 -0
  67. package/docs/api/index.html +178 -0
  68. package/docs/api/nav.html +18 -0
  69. package/docs/api/signals.html +136 -0
  70. package/docs/api/state.html +217 -0
  71. package/docs/assets/images/logo-favicon.svg +42 -0
  72. package/docs/assets/images/logo-static.svg +40 -0
  73. package/docs/assets/images/logo.svg +66 -0
  74. package/docs/assets/js/examplify.js +395 -0
  75. package/docs/assets/styles/site.css +1102 -0
  76. package/docs/assets/styles/themes.css +236 -0
  77. package/docs/components/accordion.html +439 -0
  78. package/docs/components/alert.html +528 -0
  79. package/docs/components/avatar.html +586 -0
  80. package/docs/components/badge.html +531 -0
  81. package/docs/components/breadcrumbs.html +278 -0
  82. package/docs/components/button.html +579 -0
  83. package/docs/components/card.html +561 -0
  84. package/docs/components/carousel.html +286 -0
  85. package/docs/components/chart-area.html +702 -0
  86. package/docs/components/chart-bar.html +782 -0
  87. package/docs/components/chart-column.html +735 -0
  88. package/docs/components/chart-line.html +794 -0
  89. package/docs/components/chart-pie.html +823 -0
  90. package/docs/components/chart.html +612 -0
  91. package/docs/components/chat.html +547 -0
  92. package/docs/components/checkbox.html +641 -0
  93. package/docs/components/collapse.html +536 -0
  94. package/docs/components/component-nav.html +53 -0
  95. package/docs/components/countdown.html +470 -0
  96. package/docs/components/diff.html +245 -0
  97. package/docs/components/divider.html +240 -0
  98. package/docs/components/dock.html +277 -0
  99. package/docs/components/drawer.html +515 -0
  100. package/docs/components/dropdown.html +479 -0
  101. package/docs/components/file-input.html +591 -0
  102. package/docs/components/footer.html +301 -0
  103. package/docs/components/gallery.html +504 -0
  104. package/docs/components/hero.html +264 -0
  105. package/docs/components/index.css +840 -0
  106. package/docs/components/index.html +735 -0
  107. package/docs/components/indicator.html +342 -0
  108. package/docs/components/input.html +644 -0
  109. package/docs/components/join.html +285 -0
  110. package/docs/components/kbd.html +322 -0
  111. package/docs/components/loading.html +521 -0
  112. package/docs/components/menu.html +461 -0
  113. package/docs/components/modal.html +639 -0
  114. package/docs/components/navbar.html +321 -0
  115. package/docs/components/pagination.html +279 -0
  116. package/docs/components/progress.html +514 -0
  117. package/docs/components/radial-progress.html +434 -0
  118. package/docs/components/radio.html +655 -0
  119. package/docs/components/range.html +611 -0
  120. package/docs/components/rating.html +642 -0
  121. package/docs/components/select.html +696 -0
  122. package/docs/components/sidebar-setup.js +93 -0
  123. package/docs/components/skeleton.html +447 -0
  124. package/docs/components/spinner.html +68 -0
  125. package/docs/components/stats.html +486 -0
  126. package/docs/components/steps.html +356 -0
  127. package/docs/components/swap.html +517 -0
  128. package/docs/components/switch.html +68 -0
  129. package/docs/components/table.html +668 -0
  130. package/docs/components/tabs.html +506 -0
  131. package/docs/components/text-input.html +68 -0
  132. package/docs/components/textarea.html +603 -0
  133. package/docs/components/timeline.html +487 -0
  134. package/docs/components/toast.html +474 -0
  135. package/docs/components/toggle.html +564 -0
  136. package/docs/components/tooltip.html +423 -0
  137. package/docs/examples/getting-started-example.html +40 -0
  138. package/docs/examples/index.html +93 -0
  139. package/docs/getting-started/index.html +739 -0
  140. package/docs/getting-started/reviews.html +23 -0
  141. package/docs/getting-started/reviews.odom +108 -0
  142. package/docs/getting-started/reviews.vdom +84 -0
  143. package/docs/index.html +134 -0
  144. package/docs/playground.html +416 -0
  145. package/docs/router.html +285 -0
  146. package/docs/styles/index.html +190 -0
  147. package/functions/_middleware.js +32 -0
  148. package/index.html +309 -0
  149. package/lightview-router.js +364 -0
  150. package/lightview-x.js +1577 -0
  151. package/lightview.js +658 -1109
  152. package/lightview.js.backup +793 -0
  153. package/middleware/locale.js +25 -0
  154. package/middleware/markdown.js +44 -0
  155. package/middleware/notFound.js +37 -0
  156. package/package.json +27 -41
  157. package/watch.js +92 -0
  158. package/wrangler.toml +12 -0
  159. package/.idea/lightview.iml +0 -12
  160. package/.idea/modules.xml +0 -8
  161. package/.idea/vcs.xml +0 -6
  162. package/LICENSE +0 -21
  163. package/codepen-no-tabs-embed.css +0 -2
  164. package/components/chart/chart.html +0 -17
  165. package/components/chart/example.html +0 -32
  166. package/components/chart.html +0 -83
  167. package/components/components.js +0 -113
  168. package/components/gantt/example.html +0 -22
  169. package/components/gantt/gantt.html +0 -42
  170. package/components/gauge/example.html +0 -28
  171. package/components/gauge/gauge.html +0 -20
  172. package/components/gauge.html +0 -60
  173. package/components/orgchart/example.html +0 -25
  174. package/components/orgchart/orgchart.html +0 -41
  175. package/components/repl/code-editor.html +0 -64
  176. package/components/repl/editor.html +0 -37
  177. package/components/repl/editorjs-inline-tool/index.js +0 -3
  178. package/components/repl/editorjs-inline-tool/inline-tools.js +0 -28
  179. package/components/repl/editorjs-inline-tool/tool.js +0 -175
  180. package/components/repl/repl-with-wysiwyg.html +0 -355
  181. package/components/repl/repl.html +0 -345
  182. package/components/repl/sup.js +0 -44
  183. package/components/repl/wysiwyg-repl.html +0 -258
  184. package/components/timeline/example.html +0 -33
  185. package/components/timeline/timeline.html +0 -44
  186. package/components/timeline.html +0 -81
  187. package/examples/anchor.html +0 -11
  188. package/examples/chart.html +0 -34
  189. package/examples/counter.html +0 -26
  190. package/examples/counter.test.mjs +0 -47
  191. package/examples/counter2.html +0 -26
  192. package/examples/directives.html +0 -79
  193. package/examples/foreign.html +0 -50
  194. package/examples/forgeinform.html +0 -98
  195. package/examples/form.html +0 -61
  196. package/examples/gauge.html +0 -18
  197. package/examples/invalid-template-literals.html +0 -44
  198. package/examples/medium/remote.html +0 -60
  199. package/examples/message.html +0 -18
  200. package/examples/nested.html +0 -11
  201. package/examples/object-bound-form.html +0 -34
  202. package/examples/remote-server.js +0 -51
  203. package/examples/remote.html +0 -34
  204. package/examples/remote.json +0 -1
  205. package/examples/scratch.html +0 -69
  206. package/examples/sensors/index.html +0 -30
  207. package/examples/sensors/sensor-server.js +0 -30
  208. package/examples/shared.html +0 -41
  209. package/examples/template.html +0 -33
  210. package/examples/timeline.html +0 -21
  211. package/examples/todo.html +0 -38
  212. package/examples/top.html +0 -10
  213. package/examples/types.html +0 -94
  214. package/examples/xor.html +0 -62
  215. package/jest-puppeteer.config.js +0 -5
  216. package/jest.config.json +0 -12
  217. package/sites/client.html +0 -48
  218. package/sites/index.html +0 -247
  219. package/test/basic.html +0 -93
  220. package/test/basic.test.mjs +0 -315
  221. package/test/extended.html +0 -29
  222. package/test/extended.test.mjs +0 -448
  223. package/types.js +0 -534
  224. package/unsplash.key +0 -1
@@ -0,0 +1,136 @@
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="docs-layout">
10
+ <aside class="docs-sidebar" src="./nav.html"></aside>
11
+
12
+ <main class="docs-content">
13
+ <h1>Signals</h1>
14
+ <p>
15
+ Signals are the heart of Lightview's reactivity. They hold values that can change over time,
16
+ and automatically notify anything that depends on them.
17
+ </p>
18
+
19
+ <h2>Creating Signals</h2>
20
+ <pre><code>const { signal } = Lightview;
21
+
22
+ // Create a signal with an initial value
23
+ const count = signal(0);
24
+ const name = signal('World');
25
+ const items = signal([]);
26
+ const user = signal({ name: 'Alice', age: 25 });</code></pre>
27
+
28
+ <h2>Reading Values</h2>
29
+ <pre><code>// Two ways to read
30
+ console.log(count.value); // Property access: 0
31
+ console.log(count()); // Function call: 0
32
+
33
+ // Both work identically - pick your style</code></pre>
34
+
35
+ <h2>Writing Values</h2>
36
+ <pre><code>// Two ways to write
37
+ count.value = 5; // Property assignment
38
+ count(10); // Function call with argument
39
+
40
+ // Both trigger reactive updates</code></pre>
41
+
42
+ <h2>Reactive UI</h2>
43
+ <p>
44
+ The magic happens when you use signals in your UI. Wrap expressions in functions to make them reactive:
45
+ </p>
46
+ <pre><code>const { signal, tags } = Lightview;
47
+ const { div, p, button } = tags;
48
+
49
+ const count = signal(0);
50
+
51
+ // Static - won't update
52
+ p(`Count: ${count.value}`) // ❌ "Count: 0" forever
53
+
54
+ // Reactive - updates automatically
55
+ p(() => `Count: ${count.value}`) // ✅ Updates when count changes!</code></pre>
56
+
57
+ <div class="code-example">
58
+ <div class="code-example-preview" id="signal-demo"></div>
59
+ <div class="code-example-code">
60
+ <pre><code>const count = signal(0);
61
+
62
+ div(
63
+ p(() => `Count: ${count.value}`),
64
+ button({ onclick: () => count.value++ }, '+1')
65
+ )</code></pre>
66
+ </div>
67
+ </div>
68
+
69
+ <h2>Named Signals</h2>
70
+ <p>
71
+ You can give signals a name for easy access across your application:
72
+ </p>
73
+ <pre><code>// Create a named signal and keep it in sessionStorage
74
+ const count = signal(0, 'count');
75
+
76
+ // Retrieve it elsewhere (even in another file)
77
+ const sameCount = signal.get('count');
78
+
79
+ // Get or create with default value
80
+ // If ' ' exists, returns it. If not, creates it with 100.
81
+ const score = signal.get('count', 0);</code></pre>
82
+
83
+ <h2>Stored Signals</h2>
84
+ <p>
85
+ You can store named signals in Storage objects (e.g. sessionStorage or localStorage) for persistence. It
86
+ will be saved any time there is a change.
87
+ </p>
88
+ <pre><code>const count = signal(0, {name:'count', storage:sessionStorage});
89
+
90
+ // Retrieve it elsewhere (even in another file)
91
+ const sameCount = signal.get('count');
92
+
93
+ // Get or create with default value
94
+ // If ' ' exists, returns it. If not, creates it with 100.
95
+ const score = signal.get('count', {storage:sessionStorage, defaultValue:0});</code></pre>
96
+ <p>Note: Manually updating the value in storage will not trigger updates.</p>
97
+
98
+ <h2>Tips & Patterns</h2>
99
+
100
+ <h3>Derived State</h3>
101
+ <p>For values computed from signals, use <a href="./computed">computed()</a> instead:</p>
102
+ <pre><code>const count = signal(0);
103
+ const doubled = computed(() => count.value * 2); // Auto-updates</code></pre>
104
+
105
+ <h3>Objects & Arrays</h3>
106
+ <p>For deep reactivity on objects/arrays, consider <a href="./state">state()</a>:</p>
107
+ <pre><code>// Signal: only triggers on reassignment
108
+ const items = signal([1, 2, 3]);
109
+ items.value.push(4); // ❌ Won't trigger update
110
+ items.value = [...items.value, 4]; // ✅ Triggers update
111
+
112
+ // State: deep reactivity
113
+ const items = state([1, 2, 3]);
114
+ items.push(4); // ✅ Triggers update automatically</code></pre>
115
+ </main>
116
+ </div>
117
+
118
+ <script>
119
+ (function () {
120
+ const { signal, tags } = Lightview;
121
+ const { div, p, button } = tags;
122
+
123
+ const count = signal(0);
124
+
125
+ const demo = div({ style: 'display: flex; align-items: center; gap: 1rem;' },
126
+ p({ style: 'margin: 0; font-size: 1.25rem;' }, () => `Count: ${count.value}`),
127
+ button({
128
+ onclick: () => count.value++,
129
+ style: 'padding: 0.5rem 1rem; cursor: pointer; background: var(--site-primary); color: white; border: none; border-radius: 6px;'
130
+ }, '+1')
131
+ );
132
+
133
+ const container = document.getElementById('signal-demo');
134
+ if (container) container.appendChild(demo.domEl);
135
+ })();
136
+ </script>
@@ -0,0 +1,217 @@
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="docs-layout">
10
+ <aside class="docs-sidebar" src="./nav.html"></aside>
11
+
12
+ <main class="docs-content">
13
+ <h1>State (Store)</h1>
14
+ <p>
15
+ State provides deep reactivity for objects and arrays. Unlike signals which only track reassignment,
16
+ state tracks nested property changes automatically.
17
+ </p>
18
+
19
+ <h2>The Problem with Signals + Objects</h2>
20
+ <pre><code>// Signals only react to reassignment
21
+ const user = signal({ name: 'Alice', age: 25 });
22
+
23
+ user.value.age = 26; // ❌ Won't trigger updates!
24
+ user.value = { ...user.value, age: 26 }; // ✅ Works, but verbose
25
+
26
+ // Arrays have the same issue
27
+ const items = signal([1, 2, 3]);
28
+ items.value.push(4); // ❌ Won't trigger updates!
29
+ items.value = [...items.value, 4]; // ✅ Works, but tedious</code></pre>
30
+
31
+ <h2>State to the Rescue</h2>
32
+ <pre><code>const { state } = LightviewX;
33
+
34
+ // Deep reactivity - mutations work!
35
+ const user = state({ name: 'Alice', age: 25 });
36
+
37
+ user.age = 26; // ✅ Triggers updates!
38
+ user.name = 'Bob'; // ✅ Triggers updates!
39
+
40
+ // Arrays just work
41
+ const items = state([1, 2, 3]);
42
+ items.push(4); // ✅ Triggers updates!
43
+ items[0] = 10; // ✅ Triggers updates!
44
+ items.sort(); // ✅ Triggers updates!</code></pre>
45
+
46
+ <h2>Nested Objects</h2>
47
+ <p>State tracks changes at any depth:</p>
48
+ <pre><code>const app = state({
49
+ user: {
50
+ profile: {
51
+ name: 'Alice',
52
+ settings: {
53
+ theme: 'dark',
54
+ notifications: true
55
+ }
56
+ }
57
+ },
58
+ items: []
59
+ });
60
+
61
+ // All of these trigger updates:
62
+ app.user.profile.name = 'Bob';
63
+ app.user.profile.settings.theme = 'light';
64
+ app.items.push({ id: 1, text: 'Hello' });</code></pre>
65
+
66
+ <h2>In the UI</h2>
67
+
68
+ <div class="code-example">
69
+ <div class="code-example-preview" id="state-demo"></div>
70
+ <div class="code-example-code">
71
+ <pre><code>const todos = state([
72
+ { text: 'Learn Lightview', done: true },
73
+ { text: 'Build app', done: false }
74
+ ]);
75
+
76
+ div(
77
+ ul(() => todos.map((todo, i) =>
78
+ li(
79
+ input({
80
+ type: 'checkbox',
81
+ checked: todo.done,
82
+ onchange: () => todos[i].done = !todos[i].done
83
+ }),
84
+ span(todo.text)
85
+ )
86
+ )),
87
+ button({ onclick: () => todos.push({ text: 'New', done: false }) }, 'Add')
88
+ )</code></pre>
89
+ </div>
90
+ </div>
91
+
92
+ <h2>Array Methods</h2>
93
+ <p>All mutating array methods are reactive:</p>
94
+ <pre><code>const items = state([1, 2, 3]);
95
+
96
+ items.push(4); // Add to end
97
+ items.pop(); // Remove from end
98
+ items.shift(); // Remove from start
99
+ items.unshift(0); // Add to start
100
+ items.splice(1, 1); // Remove at index
101
+ items.sort(); // Sort in place
102
+ items.reverse(); // Reverse in place
103
+ items.fill(0); // Fill with value</code></pre>
104
+
105
+ <h2>Named State</h2>
106
+ <p>
107
+ Like signals, you can name state objects for global access. This is especially useful for
108
+ shared application state:
109
+ </p>
110
+ <pre><code>// Create named state
111
+ const appState = state({
112
+ user: 'Guest',
113
+ theme: 'dark'
114
+ }, 'app');
115
+
116
+ // Retrieve it anywhere
117
+ const globalState = state.get('app');
118
+
119
+ // Get or create
120
+ const settings = state.get('settings', { notifications: true });</code></pre>
121
+
122
+ <h2>Stored State</h2>
123
+ <p>
124
+ You can store named state objects in Storage objects (e.g. sessionStorage or localStorage) for persistence.
125
+ It will be saved any time there is a change. Objects are automatically
126
+ serialized to JSON and deserialized back to objects.
127
+ </p>
128
+ <pre><code>const user = state({name:'Guest', theme:'dark'}, {name:'user', storage:sessionStorage});
129
+
130
+ // Retrieve it elsewhere (even in another file)
131
+ const sameUser = state.get('user');
132
+
133
+ // Get or create with default value
134
+ // If 'user' exists, returns it. If not, creates it with default value.
135
+ const score = state.get('user', {storage:sessionStorage, defaultValue:{name:'Guest', theme:'dark'}});</code></pre>
136
+ <p>Note: Manually updating the object in storage will not trigger updates.</p>
137
+
138
+ <h2>Signal vs State</h2>
139
+ <table class="api-table">
140
+ <thead>
141
+ <tr>
142
+ <th>Use Signal</th>
143
+ <th>Use State</th>
144
+ </tr>
145
+ </thead>
146
+ <tbody>
147
+ <tr>
148
+ <td>Primitives (numbers, strings, bools)</td>
149
+ <td>Objects with nested properties</td>
150
+ </tr>
151
+ <tr>
152
+ <td>Simple objects (replace whole thing)</td>
153
+ <td>Objects you'll mutate in place</td>
154
+ </tr>
155
+ <tr>
156
+ <td>Arrays you'll replace</td>
157
+ <td>Arrays you'll push/pop/splice</td>
158
+ </tr>
159
+ <tr>
160
+ <td>Slightly better performance</td>
161
+ <td>More convenient API</td>
162
+ </tr>
163
+ </tbody>
164
+ </table>
165
+
166
+ <h2>Pro Tip</h2>
167
+ <p>
168
+ You can mix both! Use signals for simple values and state for complex structures:
169
+ </p>
170
+ <pre><code>const isLoading = signal(false); // Simple boolean → signal
171
+ const error = signal(null); // Simple value → signal
172
+ const items = state([]); // Array to mutate → state (from LightviewX)
173
+ const formData = state({ // Object to mutate → state (from LightviewX)
174
+ name: '',
175
+ email: '',
176
+ message: ''
177
+ });</code></pre>
178
+ </main>
179
+ </div>
180
+
181
+ <script>
182
+ (function () {
183
+ const { tags } = Lightview;
184
+ const { state } = LightviewX;
185
+ const { div, ul, li, input, span, button } = tags;
186
+
187
+ const todos = state([
188
+ { text: 'Learn Lightview', done: true },
189
+ { text: 'Build something', done: false }
190
+ ]);
191
+
192
+ const demo = div({ style: 'padding: 0.5rem;' },
193
+ ul({ style: 'list-style: none; padding: 0; margin: 0 0 1rem;' },
194
+ () => todos.map((todo, i) =>
195
+ li({ style: 'display: flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0;' },
196
+ input({
197
+ type: 'checkbox',
198
+ checked: todo.done,
199
+ onchange: () => todos[i].done = !todos[i].done,
200
+ style: 'cursor: pointer;'
201
+ }),
202
+ span({
203
+ style: () => `${todo.done ? 'text-decoration: line-through; opacity: 0.6;' : ''}`
204
+ }, todo.text)
205
+ )
206
+ )
207
+ ),
208
+ button({
209
+ onclick: () => todos.push({ text: `Task ${todos.length + 1}`, done: false }),
210
+ style: 'padding: 0.5rem 1rem; cursor: pointer; background: var(--site-primary); color: white; border: none; border-radius: 6px;'
211
+ }, '+ Add Task')
212
+ );
213
+
214
+ const container = document.getElementById('state-demo');
215
+ if (container) container.appendChild(demo.domEl);
216
+ })();
217
+ </script>
@@ -0,0 +1,42 @@
1
+ <svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <!-- Vibrant Blue/Purple Gradient -->
4
+ <linearGradient id="bladeGradient" x1="100" y1="100" x2="400" y2="400" gradientUnits="userSpaceOnUse">
5
+ <stop offset="0%" stop-color="#0ea5e9" /> <!-- Sky Blue -->
6
+ <stop offset="50%" stop-color="#8b5cf6" /> <!-- Violet -->
7
+ <stop offset="100%" stop-color="#ec4899" /> <!-- Pink/Magenta -->
8
+ </linearGradient>
9
+
10
+ <!-- Glow effect for the center -->
11
+ <filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
12
+ <feGaussianBlur stdDeviation="15" result="blur"/>
13
+ <feComposite in="SourceGraphic" in2="blur" operator="over"/>
14
+ </filter>
15
+ </defs>
16
+
17
+ <!-- Group centered and scaled up by 25% -->
18
+ <g transform="translate(256 256) scale(1.25)">
19
+
20
+ <!-- 8-blade Geometric Aperture -->
21
+ <g class="aperture-panels" stroke="none">
22
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(0)" />
23
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(45)" />
24
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(90)" />
25
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(135)" />
26
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(180)" />
27
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(225)" />
28
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(270)" />
29
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(315)" />
30
+ </g>
31
+
32
+ </g>
33
+
34
+ <!-- Central Pupil (needs to be grouped/transformed similarly or manually adjusted) -->
35
+ <!-- Since the pupil is defined by absolute coordinates cx=256 cy=256, we can just wrap it in a group with the same transform relative to the center -->
36
+ <g transform="translate(256 256) scale(1.25)">
37
+ <!-- Circle coordinates must be 0,0 relative to the group for the scale to work from center -->
38
+ <circle cx="0" cy="0" r="60" fill="url(#bladeGradient)" opacity="0.3" filter="url(#centerGlow)" />
39
+ <circle cx="0" cy="0" r="24" fill="url(#bladeGradient)" />
40
+ </g>
41
+
42
+ </svg>
@@ -0,0 +1,40 @@
1
+ <svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <!-- Vibrant Blue/Purple Gradient -->
4
+ <linearGradient id="bladeGradient" x1="100" y1="100" x2="400" y2="400" gradientUnits="userSpaceOnUse">
5
+ <stop offset="0%" stop-color="#0ea5e9" /> <!-- Sky Blue -->
6
+ <stop offset="50%" stop-color="#8b5cf6" /> <!-- Violet -->
7
+ <stop offset="100%" stop-color="#ec4899" /> <!-- Pink/Magenta -->
8
+ </linearGradient>
9
+
10
+ <!-- Glow effect for the center -->
11
+ <filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
12
+ <feGaussianBlur stdDeviation="15" result="blur"/>
13
+ <feComposite in="SourceGraphic" in2="blur" operator="over"/>
14
+ </filter>
15
+ </defs>
16
+
17
+ <!-- Group centered -->
18
+ <g transform="translate(256 256)">
19
+
20
+ <!-- 8-blade Geometric Aperture -->
21
+ <g class="aperture-panels" stroke="none">
22
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(0)" />
23
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(45)" />
24
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(90)" />
25
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(135)" />
26
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(180)" />
27
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(225)" />
28
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(270)" />
29
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(315)" />
30
+ </g>
31
+
32
+ </g>
33
+
34
+ <!-- Central Pupil -->
35
+ <g class="hero-pupil">
36
+ <circle cx="256" cy="256" r="60" fill="url(#bladeGradient)" opacity="0.3" filter="url(#centerGlow)" />
37
+ <circle cx="256" cy="256" r="24" fill="url(#bladeGradient)" />
38
+ </g>
39
+
40
+ </svg>
@@ -0,0 +1,66 @@
1
+ <svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <!-- Vibrant Blue/Purple Gradient -->
4
+ <linearGradient id="bladeGradient" x1="100" y1="100" x2="400" y2="400" gradientUnits="userSpaceOnUse">
5
+ <stop offset="0%" stop-color="#0ea5e9" /> <!-- Sky Blue -->
6
+ <stop offset="50%" stop-color="#8b5cf6" /> <!-- Violet -->
7
+ <stop offset="100%" stop-color="#ec4899" /> <!-- Pink/Magenta -->
8
+ </linearGradient>
9
+
10
+ <!-- Glow effect for the center -->
11
+ <filter id="centerGlow" x="-50%" y="-50%" width="200%" height="200%">
12
+ <feGaussianBlur stdDeviation="15" result="blur"/>
13
+ <feComposite in="SourceGraphic" in2="blur" operator="over"/>
14
+ </filter>
15
+ </defs>
16
+
17
+ <style>
18
+ .aperture-panels {
19
+ transform-origin: 0 0;
20
+ animation: aperture-spin 5s ease-in-out infinite;
21
+ }
22
+
23
+ @keyframes aperture-spin {
24
+ 0% { transform: rotate(0deg); }
25
+ 5% { transform: rotate(-45deg); }
26
+ 8% { transform: rotate(0deg); }
27
+ 100% { transform: rotate(0deg); }
28
+ }
29
+
30
+ .hero-pupil {
31
+ transform-origin: 256px 256px;
32
+ animation: pupil-blink 5s ease-in-out infinite;
33
+ }
34
+
35
+ @keyframes pupil-blink {
36
+ 0% { transform: scale(1); opacity: 1; }
37
+ 5% { transform: scale(0.1); opacity: 0; }
38
+ 8% { transform: scale(1); opacity: 1; }
39
+ 100% { transform: scale(1); opacity: 1; }
40
+ }
41
+ </style>
42
+
43
+ <!-- Group centered -->
44
+ <g transform="translate(256 256)">
45
+
46
+ <!-- 8-blade Geometric Aperture -->
47
+ <g class="aperture-panels" stroke="none">
48
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(0)" />
49
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(45)" />
50
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(90)" />
51
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(135)" />
52
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(180)" />
53
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(225)" />
54
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(270)" />
55
+ <path d="M0,-60 L130,-160 L180,-40 Z" fill="url(#bladeGradient)" opacity="0.9" transform="rotate(315)" />
56
+ </g>
57
+
58
+ </g>
59
+
60
+ <!-- Central Pupil -->
61
+ <g class="hero-pupil">
62
+ <circle cx="256" cy="256" r="60" fill="url(#bladeGradient)" opacity="0.3" filter="url(#centerGlow)" />
63
+ <circle cx="256" cy="256" r="24" fill="url(#bladeGradient)" />
64
+ </g>
65
+
66
+ </svg>