@everystate/examples 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +15 -0
  2. package/everyState-core/001-counter/README.md +44 -0
  3. package/everyState-core/001-counter/index.html +79 -0
  4. package/everyState-core/002-counter-improved/README.md +44 -0
  5. package/everyState-core/002-counter-improved/index.html +83 -0
  6. package/everyState-core/003-input-reactive/README.md +44 -0
  7. package/everyState-core/003-input-reactive/index.html +68 -0
  8. package/everyState-core/004-computed-state/README.md +45 -0
  9. package/everyState-core/004-computed-state/index.html +83 -0
  10. package/everyState-core/005-conditional-rendering/README.md +42 -0
  11. package/everyState-core/005-conditional-rendering/index.html +68 -0
  12. package/everyState-core/006-list-rendering/README.md +49 -0
  13. package/everyState-core/006-list-rendering/index.html +92 -0
  14. package/everyState-core/007-form-validation/README.md +52 -0
  15. package/everyState-core/007-form-validation/index.html +108 -0
  16. package/everyState-core/008-undo-redo/README.md +70 -0
  17. package/everyState-core/008-undo-redo/index.html +133 -0
  18. package/everyState-core/009-localStorage-side-effects/README.md +72 -0
  19. package/everyState-core/009-localStorage-side-effects/index.html +80 -0
  20. package/everyState-core/010-decoupled-components/README.md +74 -0
  21. package/everyState-core/010-decoupled-components/index.html +117 -0
  22. package/everyState-core/011-async-patterns/README.md +98 -0
  23. package/everyState-core/011-async-patterns/index.html +132 -0
  24. package/everyState-css/001-stateDrivenCSS/index.html +377 -0
  25. package/everyState-css/002-cssV2FullDemo/index.html +630 -0
  26. package/everyState-view/001/counter/index.css +31 -0
  27. package/everyState-view/001/counter/index.html +50 -0
  28. package/everyState-view/002/datatable/index.css +70 -0
  29. package/everyState-view/002/datatable/index.html +118 -0
  30. package/everyState-view/003/todo/index.css +260 -0
  31. package/everyState-view/003/todo/index.html +218 -0
  32. package/everyState-view/003-input-reactive/README.md +44 -0
  33. package/everyState-view/003-input-reactive/index.html +68 -0
  34. package/everyState-view/004/quotesFetcher/index.css +124 -0
  35. package/everyState-view/004/quotesFetcher/index.html +108 -0
  36. package/everyState-view/004_01/quotesFetcher/app.js +32 -0
  37. package/everyState-view/004_01/quotesFetcher/components/appHeader/appSubtitle.js +2 -0
  38. package/everyState-view/004_01/quotesFetcher/components/appHeader/appTitle.js +2 -0
  39. package/everyState-view/004_01/quotesFetcher/components/appHeader.js +9 -0
  40. package/everyState-view/004_01/quotesFetcher/components/historyHeading.js +2 -0
  41. package/everyState-view/004_01/quotesFetcher/components/historyList/histAuthor.js +2 -0
  42. package/everyState-view/004_01/quotesFetcher/components/historyList/histQuote.js +2 -0
  43. package/everyState-view/004_01/quotesFetcher/components/historyList.js +14 -0
  44. package/everyState-view/004_01/quotesFetcher/components/quoteCard/fetchButton.js +2 -0
  45. package/everyState-view/004_01/quotesFetcher/components/quoteCard/quoteAuthor.js +2 -0
  46. package/everyState-view/004_01/quotesFetcher/components/quoteCard/quoteMessage.js +2 -0
  47. package/everyState-view/004_01/quotesFetcher/components/quoteCard/quoteText.js +2 -0
  48. package/everyState-view/004_01/quotesFetcher/components/quoteCard.js +11 -0
  49. package/everyState-view/004_01/quotesFetcher/index.css +124 -0
  50. package/everyState-view/004_01/quotesFetcher/index.html +23 -0
  51. package/everyState-view/004_01/quotesFetcher/store.js +35 -0
  52. package/everyState-view/004_02/quotesFetcher/app.js +20 -0
  53. package/everyState-view/004_02/quotesFetcher/components.js +46 -0
  54. package/everyState-view/004_02/quotesFetcher/index.css +124 -0
  55. package/everyState-view/004_02/quotesFetcher/index.html +23 -0
  56. package/everyState-view/004_02/quotesFetcher/store.js +35 -0
  57. package/everyState-view/004_03/quotesFetcher/actions.js +27 -0
  58. package/everyState-view/004_03/quotesFetcher/app.js +19 -0
  59. package/everyState-view/004_03/quotesFetcher/components.js +28 -0
  60. package/everyState-view/004_03/quotesFetcher/index.css +124 -0
  61. package/everyState-view/004_03/quotesFetcher/index.html +23 -0
  62. package/everyState-view/004_03/quotesFetcher/resolve.js +34 -0
  63. package/everyState-view/004_03/quotesFetcher/store.js +11 -0
  64. package/everyState-view/004_04/quotesFetcher/actions.js +66 -0
  65. package/everyState-view/004_04/quotesFetcher/app.js +24 -0
  66. package/everyState-view/004_04/quotesFetcher/components/archive.js +40 -0
  67. package/everyState-view/004_04/quotesFetcher/components/fetcher.js +29 -0
  68. package/everyState-view/004_04/quotesFetcher/components.js +20 -0
  69. package/everyState-view/004_04/quotesFetcher/index.css +283 -0
  70. package/everyState-view/004_04/quotesFetcher/index.html +24 -0
  71. package/everyState-view/004_04/quotesFetcher/resolve.js +34 -0
  72. package/everyState-view/004_04/quotesFetcher/store.js +21 -0
  73. package/everyState-view/004_04/statedump.json +826 -0
  74. package/everyState-view/004_05/quoteExplorer/actions.js +58 -0
  75. package/everyState-view/004_05/quoteExplorer/app.js +27 -0
  76. package/everyState-view/004_05/quoteExplorer/components.js +83 -0
  77. package/everyState-view/004_05/quoteExplorer/index.css +231 -0
  78. package/everyState-view/004_05/quoteExplorer/index.html +23 -0
  79. package/everyState-view/004_05/quoteExplorer/resolve.js +50 -0
  80. package/everyState-view/004_05/quoteExplorer/store.js +33 -0
  81. package/everyState-view/004_06/quoteExplorer/actions.js +21 -0
  82. package/everyState-view/004_06/quoteExplorer/app.js +44 -0
  83. package/everyState-view/004_06/quoteExplorer/components.js +80 -0
  84. package/everyState-view/004_06/quoteExplorer/derived.js +43 -0
  85. package/everyState-view/004_06/quoteExplorer/index.css +346 -0
  86. package/everyState-view/004_06/quoteExplorer/index.html +25 -0
  87. package/everyState-view/004_06/quoteExplorer/intents.js +44 -0
  88. package/everyState-view/004_06/quoteExplorer/policies.js +25 -0
  89. package/everyState-view/004_06/quoteExplorer/resolve.js +51 -0
  90. package/everyState-view/004_06/quoteExplorer/store.js +44 -0
  91. package/everyState-view/004_07/quoteExplorer/app.js +47 -0
  92. package/everyState-view/004_07/quoteExplorer/components.js +85 -0
  93. package/everyState-view/004_07/quoteExplorer/derived.js +43 -0
  94. package/everyState-view/004_07/quoteExplorer/index.css +346 -0
  95. package/everyState-view/004_07/quoteExplorer/index.html +25 -0
  96. package/everyState-view/004_07/quoteExplorer/intents.js +51 -0
  97. package/everyState-view/004_07/quoteExplorer/policies.js +21 -0
  98. package/everyState-view/004_07/quoteExplorer/resolve.js +39 -0
  99. package/everyState-view/004_07/quoteExplorer/store.js +44 -0
  100. package/everyState-view/004_08/quoteExplorer/app.js +78 -0
  101. package/everyState-view/004_08/quoteExplorer/components.js +85 -0
  102. package/everyState-view/004_08/quoteExplorer/derived.js +43 -0
  103. package/everyState-view/004_08/quoteExplorer/index.css +346 -0
  104. package/everyState-view/004_08/quoteExplorer/index.html +25 -0
  105. package/everyState-view/004_08/quoteExplorer/intents.js +51 -0
  106. package/everyState-view/004_08/quoteExplorer/policies.js +21 -0
  107. package/everyState-view/004_08/quoteExplorer/resolve.js +39 -0
  108. package/everyState-view/004_08/quoteExplorer/store.js +44 -0
  109. package/everyState-view/004_08_V2/app.js +78 -0
  110. package/everyState-view/004_08_V2/components/appDetail.js +8 -0
  111. package/everyState-view/004_08_V2/components/appDetailBar.js +7 -0
  112. package/everyState-view/004_08_V2/components/appDetailBarClose.js +8 -0
  113. package/everyState-view/004_08_V2/components/appDetailBarCount.js +7 -0
  114. package/everyState-view/004_08_V2/components/appDetailBarHeading.js +7 -0
  115. package/everyState-view/004_08_V2/components/appDetailQuotes.js +15 -0
  116. package/everyState-view/004_08_V2/components/appHeader.js +7 -0
  117. package/everyState-view/004_08_V2/components/appHeaderSubtitle.js +7 -0
  118. package/everyState-view/004_08_V2/components/appHeaderTitle.js +7 -0
  119. package/everyState-view/004_08_V2/components/appLog.js +7 -0
  120. package/everyState-view/004_08_V2/components/appLogHeading.js +7 -0
  121. package/everyState-view/004_08_V2/components/appLogList.js +16 -0
  122. package/everyState-view/004_08_V2/components/appSearch.js +7 -0
  123. package/everyState-view/004_08_V2/components/appSearchInput.js +9 -0
  124. package/everyState-view/004_08_V2/components/appStats.js +7 -0
  125. package/everyState-view/004_08_V2/components/appStatsContent.js +8 -0
  126. package/everyState-view/004_08_V2/components/appStatsContentFavcount.js +7 -0
  127. package/everyState-view/004_08_V2/components/appStatsContentText.js +7 -0
  128. package/everyState-view/004_08_V2/components/appStatsToggle.js +8 -0
  129. package/everyState-view/004_08_V2/components/appTags.js +7 -0
  130. package/everyState-view/004_08_V2/components/appTagsLabel.js +7 -0
  131. package/everyState-view/004_08_V2/components/appTagsRow.js +15 -0
  132. package/everyState-view/004_08_V2/components/index.js +59 -0
  133. package/everyState-view/004_08_V2/components/utils/css.js +88 -0
  134. package/everyState-view/004_08_V2/components/utils/elements.js +87 -0
  135. package/everyState-view/004_08_V2/components.js +79 -0
  136. package/everyState-view/004_08_V2/derived.js +43 -0
  137. package/everyState-view/004_08_V2/index.css +350 -0
  138. package/everyState-view/004_08_V2/index.html +25 -0
  139. package/everyState-view/004_08_V2/intents.js +51 -0
  140. package/everyState-view/004_08_V2/policies.js +21 -0
  141. package/everyState-view/004_08_V2/resolve.js +39 -0
  142. package/everyState-view/004_08_V2/store.js +44 -0
  143. package/everyState-view/006/api-datatable/index.css +388 -0
  144. package/everyState-view/006/api-datatable/index.html +355 -0
  145. package/everyState-view/007/apiUsers/index.html +307 -0
  146. package/everyState-view/007-form-validation/README.md +52 -0
  147. package/everyState-view/007-form-validation/index.html +108 -0
  148. package/everyState-view/010-decoupled-components/README.md +74 -0
  149. package/everyState-view/010-decoupled-components/index.html +117 -0
  150. package/everyState-view/index.html +36 -0
  151. package/index.js +0 -5
  152. package/package.json +2 -4
@@ -0,0 +1,44 @@
1
+ // ─── Store: namespaced state tree ───────────────────────────────
2
+ // state.* = source of truth (user data)
3
+ // derived.* = auto-computed by subscribers
4
+ // ui.* = ephemeral UI flags
5
+ // intent.* = written directly by UI events, consumed by intent handlers
6
+
7
+ import { createEveryState } from '@everystate/core';
8
+
9
+ export const store = createEveryState({
10
+ state: {
11
+ quotes: [
12
+ { id: 1, author: 'Rumi', text: 'Your heart is the size of an ocean. Go find yourself in its hidden depths.', fav: false },
13
+ { id: 2, author: 'Rumi', text: 'Respond to every call that excites your spirit.', fav: false },
14
+ { id: 3, author: 'Rumi', text: 'Everything in the universe is within you. Ask all from yourself.', fav: false },
15
+ { id: 4, author: 'Rumi', text: 'When I am silent, I have thunder hidden inside.', fav: false },
16
+ { id: 5, author: 'Einstein', text: 'Imagination is more important than knowledge.', fav: false },
17
+ { id: 6, author: 'Einstein', text: 'Life is like riding a bicycle. To keep your balance, you must keep moving.', fav: false },
18
+ { id: 7, author: 'Einstein', text: "If you can't explain it simply, you don't understand it well enough.", fav: false },
19
+ { id: 8, author: 'Mother Teresa', text: 'Spread love everywhere you go.', fav: false },
20
+ { id: 9, author: 'Mother Teresa', text: 'If you judge people, you have no time to love them.', fav: false },
21
+ { id: 10, author: 'Mother Teresa', text: 'Not all of us can do great things. But we can do small things with great love.', fav: false },
22
+ { id: 11, author: 'Muhammad Ali', text: 'Float like a butterfly, sting like a bee.', fav: false },
23
+ { id: 12, author: 'Muhammad Ali', text: "Don't count the days, make the days count.", fav: false },
24
+ { id: 13, author: 'Muhammad Ali', text: 'Service to others is the rent you pay for your room here on earth.', fav: false },
25
+ { id: 14, author: 'Socrates', text: 'The unexamined life is not worth living.', fav: false },
26
+ { id: 15, author: 'Socrates', text: 'I know that I know nothing.', fav: false },
27
+ { id: 16, author: 'Socrates', text: 'Wonder is the beginning of wisdom.', fav: false },
28
+ ],
29
+ authors: ['Rumi', 'Einstein', 'Mother Teresa', 'Muhammad Ali', 'Socrates'],
30
+ selectedAuthor: '',
31
+ searchTerm: '',
32
+ },
33
+ derived: {
34
+ filteredQuotes: [],
35
+ quoteCount: 0,
36
+ favCount: 0,
37
+ stats: '',
38
+ activityLog: [],
39
+ },
40
+ ui: {
41
+ statsVisible: false,
42
+ toggleLabel: '📊 Show Stats',
43
+ },
44
+ });
@@ -0,0 +1,78 @@
1
+ // ─── App: boot sequence ─────────────────────────────────────────
2
+ // 004_08: Fully transparent auto-intent.
3
+ //
4
+ // No Proxy. No actions.js. No runtime metaprogramming.
5
+ // intentHandlers() scans the component registry at boot time and
6
+ // builds a plain handlers map: { 'intent.X': fn } for every
7
+ // onClick/onDblClick/onEnter/onBlur target starting with 'intent.'.
8
+ //
9
+ // The result is a regular object. console.log(handlers) shows every key.
10
+ // grep 'intent.' finds the spec, the handler, and the subscriber.
11
+
12
+ import { flatten } from '@everystate/view/resolve';
13
+ import { mount } from '@everystate/view/project';
14
+ import { createPerfMonitor, mountOverlay } from '@everystate/perf';
15
+ import { store } from './store.js';
16
+ import { c } from './components.js';
17
+ import { resolveTree, buildRefs } from './resolve.js';
18
+ import { mountIntents } from './intents.js';
19
+ import { mountDerived } from './derived.js';
20
+ import { mountPolicies } from './policies.js';
21
+
22
+ // ─── intentHandlers: scan registry, build plain handlers map ────
23
+ // Walks all component specs + nested templates. For every event
24
+ // target starting with 'intent.', registers a handler that calls
25
+ // store.set(intentPath, resolvedArg). Returns a plain object.
26
+
27
+ function intentHandlers(store, components) {
28
+ const handlers = {};
29
+ const seen = new Set();
30
+ const EVENT_KEYS = ['onClick', 'onDblClick', 'onEnter', 'onBlur'];
31
+
32
+ function scan(spec) {
33
+ if (!spec || typeof spec !== 'object') return;
34
+ for (const key of EVENT_KEYS) {
35
+ const target = spec[key];
36
+ if (typeof target === 'string' && target.startsWith('intent.')) {
37
+ const name = target.replace(/\(.*\)$/, '');
38
+ if (!seen.has(name)) {
39
+ seen.add(name);
40
+ handlers[name] = (arg, event) => {
41
+ store.set(name, arg instanceof Event ? Date.now() : (arg ?? Date.now()));
42
+ };
43
+ }
44
+ }
45
+ }
46
+ // Recurse into templates and template children
47
+ if (spec.template) scan(spec.template);
48
+ if (Array.isArray(spec.template?.children)) {
49
+ spec.template.children.forEach(scan);
50
+ }
51
+ }
52
+
53
+ Object.values(components).forEach(scan);
54
+ return handlers;
55
+ }
56
+
57
+ // ─── Boot ───────────────────────────────────────────────────────
58
+
59
+ // 1. Resolve component tree + flatten into store
60
+ const spec = resolveTree(c, 'app');
61
+ const { nodes } = flatten(spec, store, 'view');
62
+ const refs = buildRefs(nodes);
63
+
64
+ // 2. Mount reactive subscribers (order: derived, policies, intents)
65
+ mountDerived(store);
66
+ mountPolicies(store);
67
+ mountIntents(store, refs);
68
+
69
+ // 3. Build handlers from registry (plain object, fully inspectable)
70
+ const handlers = intentHandlers(store, c);
71
+ console.log('[004_08 intent handlers]', Object.keys(handlers));
72
+
73
+ // 4. Mount DOM
74
+ mount(store, 'view', document.getElementById('app'), handlers);
75
+
76
+ // 5. Perf overlay
77
+ const perf = createPerfMonitor(store);
78
+ mountOverlay(perf, document.body);
@@ -0,0 +1,8 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appDetail = {
4
+ ...div,
5
+ class: 'detail-panel',
6
+ ref: 'detail',
7
+ children: ['app.detail.bar', 'app.detail.quotes']
8
+ }
@@ -0,0 +1,7 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appDetailBar = {
4
+ ...div,
5
+ class: 'detail-bar',
6
+ children: ['app.detail.bar.heading', 'app.detail.bar.count', 'app.detail.bar.close']
7
+ }
@@ -0,0 +1,8 @@
1
+ import { button } from "./utils/elements.js";
2
+
3
+ export const appDetailBarClose = {
4
+ ...button,
5
+ class: 'btn btn-close',
6
+ text: '✕',
7
+ onClick: 'intent.closeDetail'
8
+ }
@@ -0,0 +1,7 @@
1
+ import { span } from "./utils/elements.js";
2
+
3
+ export const appDetailBarCount = {
4
+ ...span,
5
+ class: 'badge',
6
+ text: '{derived.quoteCount} quotes'
7
+ }
@@ -0,0 +1,7 @@
1
+ import { h2 } from "./utils/elements.js";
2
+
3
+ export const appDetailBarHeading = {
4
+ ...h2,
5
+ class: 'detail-heading',
6
+ text: '{state.selectedAuthor}'
7
+ }
@@ -0,0 +1,15 @@
1
+ import { ul, li, span, button } from "./utils/elements.js";
2
+
3
+ export const appDetailQuotes = {
4
+ ...ul,
5
+ class: 'detail-quotes',
6
+ forEach: 'derived.filteredQuotes', as: 'item',
7
+ template: {
8
+ ...li,
9
+ class: 'quote-item',
10
+ children: [
11
+ { ...span, class: 'quote-text', text: 'item.text' },
12
+ { ...button, class: 'fav-btn', classIf: { 'is-fav': 'item.fav' }, text: '♥', onClick: 'intent.toggleFav(item.id)' }
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,7 @@
1
+ import { header } from './utils/elements.js';
2
+
3
+ export const appHeader = {
4
+ ...header,
5
+ class: 'app-header',
6
+ children: ['app.header.title', 'app.header.subtitle']
7
+ };
@@ -0,0 +1,7 @@
1
+ import { p } from "./utils/elements.js";
2
+
3
+ export const appHeaderSubtitle = {
4
+ ...p,
5
+ class: 'subtitle',
6
+ text: 'Intent-driven · Derived state · Policy subscriptions'
7
+ };
@@ -0,0 +1,7 @@
1
+ import { h1 } from "./utils/elements.js";
2
+
3
+ export const appHeaderTitle = {
4
+ ...h1,
5
+ class: 'app-header h1',
6
+ text: '💬 Quote Explorer Pro'
7
+ };
@@ -0,0 +1,7 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appLog = {
4
+ ...div,
5
+ class: 'log-section',
6
+ children: ['app.log.heading', 'app.log.list']
7
+ }
@@ -0,0 +1,7 @@
1
+ import { h3 } from "./utils/elements.js";
2
+
3
+ export const appLogHeading = {
4
+ ...h3,
5
+ class: 'log-heading',
6
+ text: '📋 Activity Log'
7
+ }
@@ -0,0 +1,16 @@
1
+ import { ul, li, span } from "./utils/elements.js";
2
+
3
+ export const appLogList = {
4
+ ...ul,
5
+ class: 'log-list',
6
+ forEach: 'derived.activityLog', as: 'entry',
7
+ template: {
8
+ ...li,
9
+ class: 'log-entry',
10
+ children: [
11
+ { ...span, class: 'log-time', text: 'entry.time' },
12
+ { ...span, class: 'log-intent', text: 'entry.intent' },
13
+ { ...span, class: 'log-value', text: 'entry.value' },
14
+ ]
15
+ }
16
+ }
@@ -0,0 +1,7 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appSearch = {
4
+ ...div,
5
+ class: 'search-bar',
6
+ children: ['app.search.input']
7
+ }
@@ -0,0 +1,9 @@
1
+ import { input } from "./utils/elements.js";
2
+
3
+ export const appSearchInput = {
4
+ ...input,
5
+ class: 'search-input',
6
+ type: 'text',
7
+ placeholder: 'Search quotes...',
8
+ bind: 'state.searchTerm'
9
+ };
@@ -0,0 +1,7 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appStats = {
4
+ ...div,
5
+ class: 'stats-section',
6
+ children: ['app.stats.toggle', 'app.stats.content']
7
+ }
@@ -0,0 +1,8 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appStatsContent = {
4
+ ...div,
5
+ class: 'stats-content hidden',
6
+ ref: 'statsContent',
7
+ children: ['app.stats.content.text', 'app.stats.content.favcount']
8
+ }
@@ -0,0 +1,7 @@
1
+ import { p } from "./utils/elements.js";
2
+
3
+ export const appStatsContentFavcount = {
4
+ ...p,
5
+ class: 'stats-fav',
6
+ text: '❤ {derived.favCount} favorites'
7
+ }
@@ -0,0 +1,7 @@
1
+ import { p } from "./utils/elements.js";
2
+
3
+ export const appStatsContentText = {
4
+ ...p,
5
+ class: 'stats-text',
6
+ text: '{derived.stats}'
7
+ }
@@ -0,0 +1,8 @@
1
+ import { button } from "./utils/elements.js";
2
+
3
+ export const appStatsToggle = {
4
+ ...button,
5
+ class: 'btn btn-secondary',
6
+ text: '{ui.toggleLabel}',
7
+ onClick: 'intent.toggleStats'
8
+ }
@@ -0,0 +1,7 @@
1
+ import { div } from "./utils/elements.js";
2
+
3
+ export const appTags = {
4
+ ...div,
5
+ class: 'author-tags',
6
+ children: ['app.tags.label', 'app.tags.row']
7
+ };
@@ -0,0 +1,7 @@
1
+ import { label } from "./utils/elements.js";
2
+
3
+ export const appTagsLabel = {
4
+ ...label,
5
+ class: 'tags-label',
6
+ text: 'Tags'
7
+ };
@@ -0,0 +1,15 @@
1
+ import { div, button } from "./utils/elements.js";
2
+ import { cssClasses } from "./utils/css.js";
3
+
4
+ export const appTagsRow = {
5
+ ...div,
6
+ class: 'tags-row',
7
+ forEach: 'state.authors',
8
+ as: 'author',
9
+ template: {
10
+ ...button,
11
+ class: 'tag',
12
+ text: 'author',
13
+ onClick: 'intent.selectAuthor(author)'
14
+ }
15
+ }
@@ -0,0 +1,59 @@
1
+ // components/index.js
2
+ import { appHeader } from "./appHeader.js";
3
+ import { appHeaderTitle } from './appHeaderTitle.js';
4
+ import { appHeaderSubtitle } from './appHeaderSubtitle.js';
5
+ import { appSearch } from './appSearch.js';
6
+ import { appSearchInput } from './appSearchInput.js';
7
+ import { appTags } from './appTags.js';
8
+ import { appTagsLabel } from './appTagsLabel.js';
9
+ import { appTagsRow } from './appTagsRow.js';
10
+ import { appDetail } from './appDetail.js';
11
+ import { appDetailBar } from './appDetailBar.js';
12
+ import { appDetailBarHeading } from './appDetailBarHeading.js';
13
+ import { appDetailBarCount } from './appDetailBarCount.js';
14
+ import { appDetailBarClose } from './appDetailBarClose.js';
15
+ import { appDetailQuotes } from './appDetailQuotes.js';
16
+ import { appStats } from './appStats.js';
17
+ import { appStatsToggle } from './appStatsToggle.js';
18
+ import { appStatsContent } from './appStatsContent.js';
19
+ import { appStatsContentText } from './appStatsContentText.js';
20
+ import { appStatsContentFavcount } from './appStatsContentFavcount.js';
21
+ import { appLog } from "./appLog.js";
22
+ import { appLogHeading } from "./appLogHeading.js";
23
+ import { appLogList } from "./appLogList.js";
24
+
25
+ export {
26
+ appHeader,
27
+ appHeaderTitle,
28
+ appHeaderSubtitle,
29
+ appSearch,
30
+ appSearchInput,
31
+ appTags,
32
+ appTagsLabel,
33
+ appTagsRow,
34
+ appDetail,
35
+ appDetailBar,
36
+ appDetailBarHeading,
37
+ appDetailBarCount,
38
+ appDetailBarClose,
39
+ appDetailQuotes,
40
+ appStats,
41
+ appStatsToggle,
42
+ appStatsContent,
43
+ appStatsContentText,
44
+ appStatsContentFavcount,
45
+ appLog,
46
+ appLogHeading,
47
+ appLogList,
48
+ };
49
+
50
+ /*
51
+ // Optional: Group them logically
52
+ export const header = {
53
+ app: appHeader,
54
+ title: appHeaderTitle,
55
+ subtitle: appHeaderSubtitle
56
+ };
57
+
58
+ export const searchBar = appSearch;
59
+ */
@@ -0,0 +1,88 @@
1
+ // Composable CSS classes
2
+ // Atomic building blocks. Each export is a minimal spec object representing a single css class
3
+ // Compose with obbject spread:
4
+ // { ...cssAppHeader }
5
+ // The state engine hydrates text, bindings, and handlers via
6
+ // dot-path addressing - elements don't need content at birth.
7
+ // Observer before observed.
8
+
9
+ export const cssClasses = {
10
+ appHeader: `
11
+ app-header
12
+ text-align-center
13
+ margin-bottom-2rem`,
14
+ appHeaderTitle: `
15
+ app-header-title
16
+ font-size-2rem
17
+ font-weight-700
18
+ background-linear-gradient-135deg-var-accent-a78bfa
19
+ background-clip-text
20
+ -webkit-background-clip-text
21
+ -webkit-text-fill-color-transparent`,
22
+ appHeaderSubtitle: `
23
+ app-header-subtitle
24
+ color-var-text-muted
25
+ font-size-0_85rem
26
+ margin-top-0_25rem
27
+ letter-spacing-0_04em`,
28
+ appSearch: `
29
+ app-search
30
+ margin-bottom-1_5rem`,
31
+ appSearchInput: `
32
+ app-search-input
33
+ width-100p
34
+ padding-0_7rem-1rem
35
+ background-var-surface
36
+ color-var-text
37
+ border-1px-solid-var-border
38
+ border-radius-var-radius
39
+ font-size-0_95rem
40
+ outline-none
41
+ transition-border-color-0_2s`,
42
+ appTags: `
43
+ app-tags
44
+ margin-bottom-1_5rem`,
45
+ appTagsLabel: `
46
+ app-tags-label
47
+ display-block
48
+ font-size-0_8rem
49
+ color-var-text-muted
50
+ margin-bottom-0_5rem
51
+ text-transform-uppercase
52
+ letter-spacing-0_06em`,
53
+ appTagsRow: `
54
+ app-tags-row
55
+ display-flex
56
+ flex-wrap
57
+ gap-0_5rem`,
58
+ tag: `
59
+ tag
60
+ padding-0_4rem-0_9rem
61
+ background-var-accent
62
+ color-white
63
+ border-none
64
+ border-radius-0_25rem
65
+ cursor-pointer
66
+ font-size-0_85rem
67
+ transition-background-0_2s`,
68
+ appDetail: `
69
+ app-detail
70
+ background-var-surface
71
+ border-1px-solid-var-border
72
+ border-radius-var-radius
73
+ padding-1_25rem
74
+ margin-bottom-1_5rem
75
+ animation-slideIn-0_25s-ease-out`,
76
+ appDetailBar: `
77
+ detail-bar
78
+ display-flex
79
+ align-items-center
80
+ gap-0_75rem
81
+ margin-bottom-1rem
82
+ padding-bottom-0_75rem
83
+ border-bottom-1px-solid-var-border`,
84
+ appDetailBarHeading: 'detail-bar-heading',
85
+ appDetailBarCount: 'detail-bar-count',
86
+ appDetailBarClose: 'detail-bar-close',
87
+ appDetailQuotes: 'detail-quotes',
88
+ }
@@ -0,0 +1,87 @@
1
+ // ─── Composable HTML Elements ────────────────────────────────────
2
+ // Atomic building blocks. Each export is a minimal spec object
3
+ // representing a single HTML element. Compose with object spread:
4
+ //
5
+ // { ...div, class: 'card', children: ['child1', 'child2'] }
6
+ //
7
+ // The state engine hydrates text, bindings, and handlers via
8
+ // dot-path addressing - elements don't need content at birth.
9
+ // Observer before observed.
10
+
11
+ // ── Document sections ──
12
+ export const header = { tag: 'header' };
13
+ export const footer = { tag: 'footer' };
14
+ export const main = { tag: 'main' };
15
+ export const nav = { tag: 'nav' };
16
+ export const section = { tag: 'section' };
17
+ export const article = { tag: 'article' };
18
+ export const aside = { tag: 'aside' };
19
+
20
+ // ── Headings ──
21
+ export const h1 = { tag: 'h1' };
22
+ export const h2 = { tag: 'h2' };
23
+ export const h3 = { tag: 'h3' };
24
+ export const h4 = { tag: 'h4' };
25
+ export const h5 = { tag: 'h5' };
26
+ export const h6 = { tag: 'h6' };
27
+
28
+ // ── Block content ──
29
+ export const div = { tag: 'div' };
30
+ export const p = { tag: 'p' };
31
+ export const blockquote = { tag: 'blockquote' };
32
+ export const pre = { tag: 'pre' };
33
+ export const code = { tag: 'code' };
34
+ export const hr = { tag: 'hr' };
35
+
36
+ // ── Inline content ──
37
+ export const span = { tag: 'span' };
38
+ export const a = { tag: 'a' };
39
+ export const strong = { tag: 'strong' };
40
+ export const em = { tag: 'em' };
41
+ export const small = { tag: 'small' };
42
+ export const mark = { tag: 'mark' };
43
+ export const time = { tag: 'time' };
44
+ export const abbr = { tag: 'abbr' };
45
+
46
+ // ── Lists ──
47
+ export const ul = { tag: 'ul' };
48
+ export const ol = { tag: 'ol' };
49
+ export const li = { tag: 'li' };
50
+ export const dl = { tag: 'dl' };
51
+ export const dt = { tag: 'dt' };
52
+ export const dd = { tag: 'dd' };
53
+
54
+ // ── Forms ──
55
+ export const form = { tag: 'form' };
56
+ export const input = { tag: 'input' };
57
+ export const textarea = { tag: 'textarea' };
58
+ export const select = { tag: 'select' };
59
+ export const option = { tag: 'option' };
60
+ export const label = { tag: 'label' };
61
+ export const fieldset = { tag: 'fieldset' };
62
+ export const legend = { tag: 'legend' };
63
+ export const button = { tag: 'button' };
64
+ export const output = { tag: 'output' };
65
+
66
+ // ── Media ──
67
+ export const img = { tag: 'img' };
68
+ export const video = { tag: 'video' };
69
+ export const audio = { tag: 'audio' };
70
+ export const canvas = { tag: 'canvas' };
71
+ export const svg = { tag: 'svg' };
72
+
73
+ // ── Table ──
74
+ export const table = { tag: 'table' };
75
+ export const thead = { tag: 'thead' };
76
+ export const tbody = { tag: 'tbody' };
77
+ export const tfoot = { tag: 'tfoot' };
78
+ export const tr = { tag: 'tr' };
79
+ export const th = { tag: 'th' };
80
+ export const td = { tag: 'td' };
81
+
82
+ // ── Interactive / Semantic ──
83
+ export const details = { tag: 'details' };
84
+ export const summary = { tag: 'summary' };
85
+ export const dialog = { tag: 'dialog' };
86
+ export const progress = { tag: 'progress' };
87
+ export const meter = { tag: 'meter' };
@@ -0,0 +1,79 @@
1
+ // Component registry
2
+ // Flat dot-path keyed specs. Every component is a resource.
3
+ // children/template are dot-path strings or inline objects.
4
+ //
5
+ // KEY CHANGE from 004_06:
6
+ // onClick targets use 'intent.*' directly instead of 'actions.*'.
7
+ // The view engine's auto-intent handler writes the resolved arg
8
+ // to the store at the intent path. No actions.js file needed.
9
+ //
10
+ // {path} interpolation reads from the store at mount time.
11
+ // ref: stable handle for intent handlers to toggle view node classes.
12
+ // bind: two-way binding to a store path (no action needed).
13
+
14
+ import {
15
+ appHeader,
16
+ appHeaderTitle,
17
+ appHeaderSubtitle,
18
+ appSearch,
19
+ appSearchInput,
20
+ appTags,
21
+ appTagsLabel,
22
+ appTagsRow,
23
+ appDetail,
24
+ appDetailBar,
25
+ appDetailBarHeading,
26
+ appDetailBarCount,
27
+ appDetailBarClose,
28
+ appDetailQuotes,
29
+ appStats,
30
+ appStatsToggle,
31
+ appStatsContent,
32
+ appStatsContentText,
33
+ appStatsContentFavcount,
34
+ appLog,
35
+ appLogHeading,
36
+ appLogList,
37
+ } from "./components/index.js";
38
+
39
+ export const c = {
40
+ // Root
41
+ 'app': {
42
+ tag: 'div', class: 'app',
43
+ children: ['app.header', 'app.search', 'app.tags', 'app.detail', 'app.stats', 'app.log']
44
+ },
45
+
46
+ // Header
47
+ 'app.header': appHeader,
48
+ 'app.header.title': appHeaderTitle,
49
+ 'app.header.subtitle': appHeaderSubtitle,
50
+
51
+ // Search (two-way bind - no action needed)
52
+ 'app.search': appSearch,
53
+ 'app.search.input': appSearchInput,
54
+
55
+ // Author Tags
56
+ 'app.tags': appTags,
57
+ 'app.tags.label': appTagsLabel,
58
+ 'app.tags.row': appTagsRow,
59
+
60
+ // Detail Panel (conditional - hidden by default)
61
+ 'app.detail': appDetail,
62
+ 'app.detail.bar': appDetailBar,
63
+ 'app.detail.bar.heading': appDetailBarHeading,
64
+ 'app.detail.bar.count': appDetailBarCount,
65
+ 'app.detail.bar.close': appDetailBarClose,
66
+ 'app.detail.quotes': appDetailQuotes,
67
+
68
+ // Stats Section (conditional toggle)
69
+ 'app.stats': appStats,
70
+ 'app.stats.toggle': appStatsToggle,
71
+ 'app.stats.content': appStatsContent,
72
+ 'app.stats.content.text': appStatsContentText,
73
+ 'app.stats.content.favcount': appStatsContentFavcount,
74
+
75
+ // Activity Log (policy-driven via intent.* wildcard)
76
+ 'app.log': appLog,
77
+ 'app.log.heading': appLogHeading,
78
+ 'app.log.list': appLogList,
79
+ };