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.
Files changed (264) 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 +1330 -19
  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 +610 -15
  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 +485 -42
  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 +132 -42
  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 +659 -1200
  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/docs/CNAME +0 -1
  165. package/docs/api.html +0 -674
  166. package/docs/blank.html +0 -10
  167. package/docs/comparedto.html +0 -89
  168. package/docs/components/chart-repl.html +0 -69
  169. package/docs/components/components.js +0 -113
  170. package/docs/components/contents.html +0 -17
  171. package/docs/components/gantt-repl.html +0 -61
  172. package/docs/components/gantt.html +0 -42
  173. package/docs/components/gauge-repl.html +0 -66
  174. package/docs/components/gauge.html +0 -20
  175. package/docs/components/orgchart-repl.html +0 -64
  176. package/docs/components/orgchart.html +0 -41
  177. package/docs/components/repl-as-src.html +0 -17
  178. package/docs/components/repl-repl.html +0 -95
  179. package/docs/components/repl.html +0 -527
  180. package/docs/components/timeline-repl.html +0 -72
  181. package/docs/components.html +0 -14
  182. package/docs/css/highlightjs.min.css +0 -9
  183. package/docs/css/tutorial.css +0 -35
  184. package/docs/examples/anchor.html +0 -11
  185. package/docs/examples/chart.html +0 -34
  186. package/docs/examples/counter.html +0 -26
  187. package/docs/examples/counter.test.mjs +0 -47
  188. package/docs/examples/counter2.html +0 -26
  189. package/docs/examples/directives.html +0 -79
  190. package/docs/examples/foreign.html +0 -50
  191. package/docs/examples/forgeinform.html +0 -98
  192. package/docs/examples/form.html +0 -61
  193. package/docs/examples/gauge.html +0 -18
  194. package/docs/examples/invalid-template-literals.html +0 -44
  195. package/docs/examples/medium/remote.html +0 -60
  196. package/docs/examples/message.html +0 -18
  197. package/docs/examples/nested.html +0 -11
  198. package/docs/examples/object-bound-form.html +0 -34
  199. package/docs/examples/remote-server.js +0 -51
  200. package/docs/examples/remote.html +0 -34
  201. package/docs/examples/remote.json +0 -1
  202. package/docs/examples/scratch.html +0 -69
  203. package/docs/examples/sensors/index.html +0 -44
  204. package/docs/examples/sensors/sensor-server.js +0 -30
  205. package/docs/examples/shared.html +0 -41
  206. package/docs/examples/template.html +0 -33
  207. package/docs/examples/timeline.html +0 -21
  208. package/docs/examples/todo.html +0 -40
  209. package/docs/examples/top.html +0 -10
  210. package/docs/examples/types.html +0 -94
  211. package/docs/examples/xor.html +0 -62
  212. package/docs/examples.html +0 -25
  213. package/docs/javascript/codejar.min.js +0 -8
  214. package/docs/javascript/highlightjs.min.js +0 -1173
  215. package/docs/javascript/isomorphic-git.js +0 -9
  216. package/docs/javascript/json5.min.js +0 -1
  217. package/docs/javascript/lightning-fs.js +0 -1
  218. package/docs/javascript/lightview.js +0 -1285
  219. package/docs/javascript/marked.min.js +0 -6
  220. package/docs/javascript/peerjs.min.js +0 -70
  221. package/docs/javascript/turndown.js +0 -973
  222. package/docs/javascript/types.js +0 -606
  223. package/docs/javascript/utils.js +0 -45
  224. package/docs/lightview.html +0 -63
  225. package/docs/old_index.html +0 -965
  226. package/docs/old_index.md +0 -1132
  227. package/docs/slidein.html +0 -51
  228. package/docs/tutorial/0-getting-started.html +0 -67
  229. package/docs/tutorial/1-intro-to-variables.html +0 -103
  230. package/docs/tutorial/10-template-components.html +0 -80
  231. package/docs/tutorial/11-linked-components.html +0 -76
  232. package/docs/tutorial/12-imported-components.html +0 -67
  233. package/docs/tutorial/13-input-binding.html +0 -94
  234. package/docs/tutorial/14-automatic-variable-creation.html +0 -74
  235. package/docs/tutorial/15-form-binding.html +0 -110
  236. package/docs/tutorial/16-if-directive.html +0 -60
  237. package/docs/tutorial/17-loop-directives.html +0 -83
  238. package/docs/tutorial/18-sanitizing-and-escaping-input.html +0 -79
  239. package/docs/tutorial/2-imported-and-exported-variables.html +0 -80
  240. package/docs/tutorial/3-data-types.html +0 -89
  241. package/docs/tutorial/4-extended-data-types.html +0 -83
  242. package/docs/tutorial/5-extended-functional-types.html +0 -96
  243. package/docs/tutorial/5.1-extended-functional-types.html +0 -79
  244. package/docs/tutorial/5.2-extended-functional-types.html +0 -70
  245. package/docs/tutorial/6-conventional-javascript.html +0 -75
  246. package/docs/tutorial/7-monitoring-with-observers.html +0 -107
  247. package/docs/tutorial/8-event-listeners.html +0 -65
  248. package/docs/tutorial/9-intro-to-components.html +0 -91
  249. package/docs/tutorial/contents.html +0 -32
  250. package/docs/tutorial/my-component.html +0 -29
  251. package/docs/tutorial/remote-value.json +0 -4
  252. package/docs/websiterepl.html +0 -46
  253. package/jest-puppeteer.config.js +0 -5
  254. package/jest.config.json +0 -12
  255. package/lightview.min.js +0 -1
  256. package/lightview_good.js +0 -1267
  257. package/lightview_optimized.js +0 -1274
  258. package/repl_hold.html +0 -320
  259. package/test/basic.html +0 -104
  260. package/test/basic.test.mjs +0 -315
  261. package/test/extended.html +0 -29
  262. package/test/extended.test.mjs +0 -448
  263. package/types.js +0 -607
  264. package/unsplash.key +0 -1
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Lightview Tabs Component (DaisyUI)
3
+ * @see https://daisyui.com/components/tab/
4
+ */
5
+
6
+ import '../daisyui.js';
7
+
8
+ /**
9
+ * Tabs Component
10
+ * @param {Object} props
11
+ * @param {string} props.variant - 'boxed' | 'bordered' | 'lifted'
12
+ * @param {string} props.size - 'xs' | 'sm' | 'md' | 'lg'
13
+ * @param {boolean} props.useShadow - Render in Shadow DOM with isolated DaisyUI styles
14
+ */
15
+ const Tabs = (props = {}, ...children) => {
16
+ const { tags } = window.Lightview || {};
17
+ const LVX = window.LightviewX || {};
18
+
19
+ if (!tags) return null;
20
+
21
+ const { div, shadowDOM } = tags;
22
+
23
+ const {
24
+ variant,
25
+ size,
26
+ useShadow,
27
+ class: className = '',
28
+ ...rest
29
+ } = props;
30
+
31
+ const classes = ['tabs'];
32
+ if (variant === 'boxed') classes.push('tabs-boxed');
33
+ else if (variant === 'bordered') classes.push('tabs-bordered');
34
+ else if (variant === 'lifted') classes.push('tabs-lifted');
35
+ if (size) classes.push(`tabs-${size}`);
36
+ if (className) classes.push(className);
37
+
38
+ const tabsEl = div({
39
+ role: 'tablist',
40
+ class: classes.join(' '),
41
+ ...rest
42
+ }, ...children);
43
+
44
+ // Check if we should use shadow DOM
45
+ let usesShadow = false;
46
+ if (LVX.shouldUseShadow) {
47
+ usesShadow = LVX.shouldUseShadow(useShadow);
48
+ } else {
49
+ usesShadow = useShadow === true;
50
+ }
51
+
52
+ if (usesShadow) {
53
+ const adoptedStyleSheets = LVX.getAdoptedStyleSheets ? LVX.getAdoptedStyleSheets() : [];
54
+
55
+ const themeValue = LVX.themeSignal ? () => LVX.themeSignal.value : 'light';
56
+
57
+ return div({ class: 'contents' },
58
+ shadowDOM({ mode: 'open', adoptedStyleSheets },
59
+ div({ 'data-theme': themeValue },
60
+ tabsEl
61
+ )
62
+ )
63
+ );
64
+ }
65
+
66
+ return tabsEl;
67
+ };
68
+
69
+ /**
70
+ * Tab Item
71
+ */
72
+ Tabs.Tab = (props = {}, ...children) => {
73
+ const { tags } = window.Lightview || {};
74
+ if (!tags) return null;
75
+
76
+ const {
77
+ active = false,
78
+ disabled = false,
79
+ class: className = '',
80
+ ...rest
81
+ } = props;
82
+
83
+ const getClasses = () => {
84
+ const classes = ['tab'];
85
+ const isActive = typeof active === 'function' ? active() : active;
86
+ const isDisabled = typeof disabled === 'function' ? disabled() : disabled;
87
+ if (isActive) classes.push('tab-active');
88
+ if (isDisabled) classes.push('tab-disabled');
89
+ if (className) classes.push(className);
90
+ return classes.join(' ');
91
+ };
92
+
93
+ return tags.button({
94
+ role: 'tab',
95
+ class: typeof active === 'function' || typeof disabled === 'function'
96
+ ? () => getClasses()
97
+ : getClasses(),
98
+ ...rest
99
+ }, ...children);
100
+ };
101
+
102
+ /**
103
+ * Tab Content - for lifted tabs with content panels
104
+ */
105
+ Tabs.Content = (props = {}, ...children) => {
106
+ const { tags } = window.Lightview || {};
107
+ if (!tags) return null;
108
+
109
+ const { class: className = '', ...rest } = props;
110
+
111
+ return tags.div({
112
+ role: 'tabpanel',
113
+ class: `tab-content bg-base-100 border-base-300 p-6 ${className}`.trim(),
114
+ ...rest
115
+ }, ...children);
116
+ };
117
+
118
+ const tags = window.Lightview.tags;
119
+ tags.Tabs = Tabs;
120
+ tags['Tabs.Tab'] = Tabs.Tab;
121
+ tags['Tabs.Content'] = Tabs.Content;
122
+
123
+ export default Tabs;
@@ -0,0 +1,65 @@
1
+ .lv-theme-switch {
2
+ position: relative;
3
+ display: inline-flex;
4
+ align-items: center;
5
+ justify-content: center;
6
+ width: 2.5rem;
7
+ height: 2.5rem;
8
+ padding: 0;
9
+ background: none;
10
+ border: none;
11
+ border-radius: var(--lv-radius-md);
12
+ color: var(--lv-color-text);
13
+ cursor: pointer;
14
+ transition: all var(--lv-transition-fast);
15
+ }
16
+
17
+ .lv-theme-switch:hover {
18
+ background-color: var(--lv-color-neutral-light);
19
+ }
20
+
21
+ .lv-theme-switch:focus-visible {
22
+ outline: 2px solid var(--lv-color-primary);
23
+ outline-offset: 2px;
24
+ }
25
+
26
+ .lv-theme-switch__icon {
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ transition: transform var(--lv-transition);
31
+ }
32
+
33
+ .lv-theme-switch__icon[data-icon="sun"] {
34
+ transform: rotate(0deg);
35
+ }
36
+
37
+ .lv-theme-switch__icon[data-icon="moon"] {
38
+ transform: rotate(0deg);
39
+ }
40
+
41
+ /* Animated variant */
42
+ .lv-theme-switch[data-animated="true"] .lv-theme-switch__icon {
43
+ position: absolute;
44
+ }
45
+
46
+ .lv-theme-switch[data-animated="true"] .lv-theme-switch__icon[data-state="hidden"] {
47
+ transform: scale(0) rotate(-90deg);
48
+ opacity: 0;
49
+ }
50
+
51
+ .lv-theme-switch[data-animated="true"] .lv-theme-switch__icon[data-state="visible"] {
52
+ transform: scale(1) rotate(0deg);
53
+ opacity: 1;
54
+ }
55
+
56
+ /* Size variants */
57
+ .lv-theme-switch[data-size="sm"] {
58
+ width: 2rem;
59
+ height: 2rem;
60
+ }
61
+
62
+ .lv-theme-switch[data-size="lg"] {
63
+ width: 3rem;
64
+ height: 3rem;
65
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Lightview Components - ThemeSwitch
3
+ * A toggle for switching between light and dark themes
4
+ */
5
+
6
+ import { loadStylesheetSync } from '../utils/styles.js';
7
+ import { getIcon } from '../utils/icons.js';
8
+
9
+ // Load styles from external CSS file
10
+ loadStylesheetSync(import.meta.url);
11
+
12
+ /**
13
+ * ThemeSwitch Component
14
+ * @param {Object} props
15
+ * @param {string|Signal} props.theme - Current theme ('light' | 'dark')
16
+ * @param {string} props.defaultTheme - Default theme if uncontrolled
17
+ * @param {string} props.size - 'sm' | 'md' | 'lg' (default: 'md')
18
+ * @param {boolean} props.animated - Use animated transition (default: true)
19
+ * @param {string} props.storageKey - localStorage key to persist theme (default: 'lv-theme')
20
+ * @param {Function} props.onChange - Theme change handler
21
+ */
22
+ const ThemeSwitch = (props = {}) => {
23
+
24
+ const { tags, signal, effect } = window.Lightview || {};
25
+ if (!tags) {
26
+ console.error('Lightview not found');
27
+ return null;
28
+ }
29
+
30
+ const { button, span } = tags;
31
+
32
+ const {
33
+ theme,
34
+ defaultTheme,
35
+ size = 'md',
36
+ animated = true,
37
+ storageKey = 'lv-theme',
38
+ onChange,
39
+ class: className = '',
40
+ ...rest
41
+ } = props;
42
+
43
+ // Detect system preference
44
+ const getSystemTheme = () => {
45
+ if (typeof window === 'undefined') return 'light';
46
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
47
+ };
48
+
49
+ // Get initial theme
50
+ const getInitialTheme = () => {
51
+ if (typeof window === 'undefined') return defaultTheme || 'light';
52
+
53
+ // Check localStorage first
54
+ const stored = localStorage.getItem(storageKey);
55
+ if (stored === 'light' || stored === 'dark') return stored;
56
+
57
+ // Then default or system
58
+ return defaultTheme || getSystemTheme();
59
+ };
60
+
61
+ // Internal state
62
+ const internalTheme = signal ? signal(getInitialTheme()) : { value: getInitialTheme() };
63
+
64
+ const isControlled = theme !== undefined;
65
+
66
+ const getTheme = () => {
67
+ if (isControlled) {
68
+ return typeof theme === 'function' ? theme() :
69
+ (theme && typeof theme.value !== 'undefined') ? theme.value : theme;
70
+ }
71
+ return internalTheme.value;
72
+ };
73
+
74
+ const applyTheme = (newTheme) => {
75
+ document.documentElement.setAttribute('data-theme', newTheme);
76
+
77
+ // Also update meta theme-color for mobile browsers
78
+ let metaTheme = document.querySelector('meta[name="theme-color"]');
79
+ if (!metaTheme) {
80
+ metaTheme = document.createElement('meta');
81
+ metaTheme.name = 'theme-color';
82
+ document.head.appendChild(metaTheme);
83
+ }
84
+ metaTheme.content = newTheme === 'dark' ? '#0f172a' : '#ffffff';
85
+ };
86
+
87
+ const toggle = () => {
88
+ const currentTheme = getTheme();
89
+ const newTheme = currentTheme === 'light' ? 'dark' : 'light';
90
+
91
+ if (!isControlled) {
92
+ internalTheme.value = newTheme;
93
+ }
94
+
95
+ if (isControlled && theme && typeof theme.value !== 'undefined') {
96
+ theme.value = newTheme;
97
+ }
98
+
99
+ // Persist to localStorage
100
+ if (storageKey) {
101
+ localStorage.setItem(storageKey, newTheme);
102
+ }
103
+
104
+ applyTheme(newTheme);
105
+
106
+ if (onChange) {
107
+ onChange(newTheme);
108
+ }
109
+ };
110
+
111
+ // Apply theme on mount
112
+ if (typeof window !== 'undefined') {
113
+ // Apply immediately
114
+ applyTheme(getTheme());
115
+
116
+ // Set up effect to watch for changes
117
+ if (effect) {
118
+ effect(() => {
119
+ applyTheme(getTheme());
120
+ });
121
+ }
122
+
123
+ // Listen for system theme changes
124
+ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
125
+ if (!localStorage.getItem(storageKey)) {
126
+ const newTheme = e.matches ? 'dark' : 'light';
127
+ if (!isControlled) {
128
+ internalTheme.value = newTheme;
129
+ }
130
+ applyTheme(newTheme);
131
+ }
132
+ });
133
+ }
134
+
135
+ const iconSize = size === 'sm' ? 16 : size === 'lg' ? 28 : 20;
136
+
137
+ const classes = ['lv-theme-switch', `lv-theme-switch--${size}`];
138
+ if (animated) classes.push('lv-theme-switch--animated');
139
+ if (className) classes.push(className);
140
+
141
+ if (animated) {
142
+ return button({
143
+ class: classes.join(' '),
144
+ onclick: toggle,
145
+ 'aria-label': () => `Switch to ${getTheme() === 'light' ? 'dark' : 'light'} mode`,
146
+ title: () => `Switch to ${getTheme() === 'light' ? 'dark' : 'light'} mode`,
147
+ ...rest
148
+ },
149
+ span({
150
+ class: () => `lv-theme-switch__icon ${getTheme() === 'light' ? 'lv-theme-switch__icon--visible' : 'lv-theme-switch__icon--hidden'}`,
151
+ innerHTML: getIcon('sun', { size: iconSize })
152
+ }),
153
+ span({
154
+ class: () => `lv-theme-switch__icon ${getTheme() === 'dark' ? 'lv-theme-switch__icon--visible' : 'lv-theme-switch__icon--hidden'}`,
155
+ innerHTML: getIcon('moon', { size: iconSize })
156
+ })
157
+ );
158
+ }
159
+
160
+ return button({
161
+ class: classes.join(' '),
162
+ onclick: toggle,
163
+ 'aria-label': () => `Switch to ${getTheme() === 'light' ? 'dark' : 'light'} mode`,
164
+ title: () => `Switch to ${getTheme() === 'light' ? 'dark' : 'light'} mode`,
165
+ ...rest
166
+ },
167
+ span({
168
+ class: 'lv-theme-switch__icon',
169
+ innerHTML: () => getIcon(getTheme() === 'light' ? 'sun' : 'moon', { size: iconSize })
170
+ })
171
+ );
172
+ };
173
+
174
+ // Auto-register
175
+ window.Lightview.tags.ThemeSwitch = ThemeSwitch;
176
+
177
+ export default ThemeSwitch;
@@ -0,0 +1,164 @@
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>About Lightview</h1>
12
+ <p class="text-secondary" style="font-size: 1.125rem;">
13
+ A lighter way to build.
14
+ </p>
15
+
16
+ <div
17
+ style="background: var(--site-bg-alt); border-radius: var(--site-radius-lg); padding: 2rem; margin: 2rem 0; text-align: center;">
18
+ <img src="/docs/assets/images/logo.svg" alt="Lightview"
19
+ style="width: 80px; height: 80px; margin-bottom: 1rem;">
20
+ <p style="font-size: 1.25rem; font-style: italic; color: var(--site-text-secondary); margin: 0;">
21
+ "The view is beautiful from here."
22
+ </p>
23
+ </div>
24
+
25
+ <h2>Genesis</h2>
26
+
27
+ <p>
28
+ It all started with a mix of admiration and frustration. I liked <strong>Bau</strong>,
29
+ <strong>HTMX</strong>, and
30
+ <strong>Juris</strong>. They were elegant, but they were also opinionated—they forced a choice.
31
+ </p>
32
+
33
+ <p>
34
+ I didn't want to choose. I wanted a framework that supported <em>all</em> approaches. None of them quite hit
35
+ the mark on their own. Plus, I wanted something none provided, template literals right inside HTML. I also
36
+ wanted a rich component library (with
37
+ charts!) without having to build everything from scratch available as both JavaScript and custom HTML
38
+ elements.
39
+ </p>
40
+
41
+ <p>
42
+ I wanted a framework that was easy to use and learn, as close to regular HTML and JavaScript as possible,
43
+ something that felt more like regular HTML than even HTMX does.
44
+ This would also require thorough and fully interactive documentation accessible via direct URLs and an SPA
45
+ like experience.
46
+ This manadated a router with at least partial "automatic" SSR—where code could execute and replace itself on
47
+ the server with a simple
48
+ DOM emulation and "have-your-cake-and-eat-it-too" single page apps that are SEO enabled without any extra
49
+ work.
50
+ </p>
51
+
52
+ <p>
53
+ In today's age, the ability of an LLM to generate cohensive applications using the library is also important
54
+ to me. If figured that if an LLM generated it and it followed conventional patterns, it will be able to use
55
+ it well and perhaps generate a little less slop.
56
+ </p>
57
+
58
+ <p>
59
+ So, I decided to run an experiment. I told Claude Opus 4.5 via Google Antigravity to "create me the
60
+ combo of HTMX, Bau, and
61
+ Juris with no special attribute names plus HTML template literals, and an SPA router. And, give me a UI
62
+ component library like
63
+ Bau's with automatic custom elment creation but don't build it from scratch. Finally, make it possible to
64
+ create SEO enabled apps with no extra work" I also provied a few examples of the kind of code I wanted to
65
+ write
66
+ using the library.
67
+ </p>
68
+
69
+ <p>
70
+ Naturally, it took a little iterating, but the basic framework was in place after just a few hours of
71
+ working with both Claude Opus 4.5 and Gemini 3 Pro. I then asked for
72
+ an extensive interactive website for documenting and promoting Lightview that also used Lightview, despsite
73
+ the fact that in the age of LLM code generation the need for extensive documentation websites is limited.
74
+ This took a lot more work, 3
75
+ weeks in fact. Very little of this time was spent addressing issues with or enhancing Ligntview. Most of it
76
+ was spent adding, debugginng and testing all the UI components. The LLM would get locked in on a particular
77
+ approach that worked form simple components bu no more complex ones.
78
+ But, that is a story for another time. Here we are 3 weeks later with about 2,000 lines of code for
79
+ Lightview
80
+ as a whole across three
81
+ files, 25,000 lines of component code, and 30,000 lines of documentation.
82
+ </p>
83
+
84
+ <p>
85
+ The resulting Lightview 2.0 library is a replacement for an experiment I ran 4 years ago to create a linrary
86
+ with
87
+ remote state storage and extended type declarations for state management. It is specific yet flexible.
88
+ Although it drops some of the features of Livghtview v1.0 and is not syntax compatible, it brings together
89
+ the features I craved without
90
+ locking me into a single paradigm. I hope you like it.
91
+ </p>
92
+
93
+ <h2>Design Principles</h2>
94
+
95
+ <div
96
+ style="background: var(--site-accent-light); border-left: 4px solid var(--site-accent); padding: 1.5rem; border-radius: 0 var(--site-radius) var(--site-radius) 0; margin: 1.5rem 0;">
97
+ <p style="margin: 0; color: var(--site-text-primary); font-size: 1.25rem; font-style: italic;">
98
+ "My opinion, don't be opinionated!"
99
+ </p>
100
+ </div>
101
+
102
+ <div class="feature-grid" style="margin-top: 1.5rem;">
103
+ <div class="feature-card">
104
+ <h3 class="feature-title">🪶 Keep It Light</h3>
105
+ <p class="feature-description">
106
+ Life's too short for heavy frameworks. Although Ligheview is not tiny (core is 8K), I tried to keep
107
+ it lean and modular so your apps stay fast.
108
+ </p>
109
+ </div>
110
+ <div class="feature-card">
111
+ <h3 class="feature-title">🔌 Zero Dependencies</h3>
112
+ <p class="feature-description">
113
+ No external dependencies. No supply chain worries. No version conflicts. Just works.
114
+ </p>
115
+ </div>
116
+ <div class="feature-card">
117
+ <h3 class="feature-title">🚀 No Build Step</h3>
118
+ <p class="feature-description">
119
+ Drop in a script tag and go. Instant gratification. Your bundler can take the day off.
120
+ </p>
121
+ </div>
122
+ <div class="feature-card">
123
+ <h3 class="feature-title">🎨 Your Way</h3>
124
+ <p class="feature-description">
125
+ Four syntaxes, one system. Incremental adoption by enhancing just the HTML you want. Pick what
126
+ feels right. See the function <code>enhance</code> in the <a href="./api/enhance">API docs</a>.
127
+ </p>
128
+ </div>
129
+ <div class="feature-card">
130
+ <h3 class="feature-title">😊 Have Fun</h3>
131
+ <p class="feature-description">
132
+ Coding should spark joy. Simple API, clear and interactive docs, helpful errors. Built for humans
133
+ who like to smile.
134
+ </p>
135
+ </div>
136
+ </div>
137
+
138
+ <h2>Credits & Inspiration</h2>
139
+ <p>
140
+ Lightview stands on the shoulders of giants. Big thanks to:
141
+ </p>
142
+ <ul>
143
+ <li><strong>Bau.js</strong> — The elegant tagged template API</li>
144
+ <li><strong>HTMX</strong> — Hypermedia as the engine of application state</li>
145
+ <li><strong>Juris.js</strong> — Simplicity and progressive enhancement</li>
146
+ </ul>
147
+
148
+ <h2>License</h2>
149
+ <p>
150
+ Lightview is open source software licensed under the <a href="https://opensource.org/licenses/MIT"
151
+ target="_blank" rel="noopener">MIT License</a>.
152
+ </p>
153
+ <p>
154
+ Free to use, modify, and distribute. Go forth and build light things. ✨
155
+ </p>
156
+
157
+ <div style="margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--site-border); text-align: center;">
158
+ <p style="font-size: 1.125rem; margin-bottom: 1rem;">
159
+ Ready to lighten up?
160
+ </p>
161
+ <a href="./getting-started" class="btn btn-primary">Enlighten Your UI</a>
162
+ </div>
163
+ </div>
164
+ </div>