galath 1.0.2

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 (55) hide show
  1. package/AGENTS.md +1 -0
  2. package/README.md +206 -0
  3. package/TODO.md +140 -0
  4. package/index.html +188 -0
  5. package/logo.jpg +0 -0
  6. package/logo.svg +96 -0
  7. package/package.json +32 -0
  8. package/packages/galath/package.json +28 -0
  9. package/packages/galath/src/behavior.js +193 -0
  10. package/packages/galath/src/binding.js +247 -0
  11. package/packages/galath/src/boot.js +52 -0
  12. package/packages/galath/src/command.js +117 -0
  13. package/packages/galath/src/component.js +505 -0
  14. package/packages/galath/src/controller.js +181 -0
  15. package/packages/galath/src/core.js +190 -0
  16. package/packages/galath/src/imports.js +132 -0
  17. package/packages/galath/src/index.js +38 -0
  18. package/packages/galath/src/instance-model.js +343 -0
  19. package/packages/galath/src/morph.js +237 -0
  20. package/packages/galath/src/rendering.js +556 -0
  21. package/packages/galath/src/signals.js +215 -0
  22. package/packages/galath/src/templates.js +24 -0
  23. package/packages/galath/src/xml-events.js +53 -0
  24. package/packages/galath-css/css/bootstrap-icons.min.css +5 -0
  25. package/packages/galath-css/css/bootstrap.min.css +6 -0
  26. package/packages/galath-css/css/fonts/bootstrap-icons.json +2077 -0
  27. package/packages/galath-css/css/fonts/bootstrap-icons.woff +0 -0
  28. package/packages/galath-css/css/fonts/bootstrap-icons.woff2 +0 -0
  29. package/packages/galath-css/js/bootstrap.bundle.min.js +7 -0
  30. package/packages/galath-css/package.json +13 -0
  31. package/playground/app.xml +214 -0
  32. package/playground/chapters/01-welcome.xml +94 -0
  33. package/playground/chapters/02-signals.xml +166 -0
  34. package/playground/chapters/03-instance.xml +130 -0
  35. package/playground/chapters/04-bindings.xml +156 -0
  36. package/playground/chapters/05-lists.xml +138 -0
  37. package/playground/chapters/06-commands.xml +144 -0
  38. package/playground/chapters/07-controller.xml +115 -0
  39. package/playground/chapters/08-events.xml +126 -0
  40. package/playground/chapters/09-behaviors.xml +210 -0
  41. package/playground/chapters/10-components.xml +152 -0
  42. package/playground/chapters/11-imports.xml +108 -0
  43. package/playground/chapters/12-expressions.xml +161 -0
  44. package/playground/chapters/13-paths.xml +197 -0
  45. package/playground/components/chapter-shell.xml +29 -0
  46. package/playground/components/highlighter.js +111 -0
  47. package/playground/components/run-snippet.js +120 -0
  48. package/public/basic/bootstrap-icons.min.css +5 -0
  49. package/public/basic/bootstrap.bundle.min.js +7 -0
  50. package/public/basic/bootstrap.min.css +6 -0
  51. package/public/basic/fonts/bootstrap-icons.json +2077 -0
  52. package/public/basic/fonts/bootstrap-icons.woff +0 -0
  53. package/public/basic/fonts/bootstrap-icons.woff2 +0 -0
  54. package/public/basic/theme.css +209 -0
  55. package/seed.html +321 -0
@@ -0,0 +1,209 @@
1
+ .text-wrap-balance { text-wrap: balance; }
2
+
3
+ /*
4
+ Cinematic Dark Bootstrap Theme — Nested CSS Version
5
+ For premium product pages, editorial landing pages, and night-fog marketing sites.
6
+ Drop this after Bootstrap, then use: <html data-bs-theme="dark">.
7
+
8
+ Mood: narrow dark fog band, warm luminous typography, Solarized-adjacent accents.
9
+
10
+ This version uses native CSS nesting. It is meant to make the theme read as one
11
+ dark-mode scope instead of many repeated [data-bs-theme="dark"] selectors.
12
+ */
13
+
14
+ [data-bs-theme="dark"] {
15
+ color-scheme: dark;
16
+
17
+ /* Core canvas */
18
+ --bs-body-color: #d7d8d1;
19
+ --bs-body-color-rgb: 215, 216, 209;
20
+ --bs-body-bg: #0b1014;
21
+ --bs-body-bg-rgb: 11, 16, 20;
22
+ --bs-emphasis-color: #fff6df;
23
+ --bs-emphasis-color-rgb: 255, 246, 223;
24
+
25
+ /* Muted text and layered fog surfaces */
26
+ --bs-secondary-color: rgba(215, 216, 209, 0.72);
27
+ --bs-secondary-color-rgb: 215, 216, 209;
28
+ --bs-secondary-bg: #111922;
29
+ --bs-secondary-bg-rgb: 17, 25, 34;
30
+ --bs-tertiary-color: rgba(215, 216, 209, 0.52);
31
+ --bs-tertiary-color-rgb: 215, 216, 209;
32
+ --bs-tertiary-bg: #172129;
33
+ --bs-tertiary-bg-rgb: 23, 33, 41;
34
+
35
+ /* Brand color system: Solarized-inspired, darker, cinematic, less synthetic. */
36
+ --bs-primary: #2aa198;
37
+ --bs-primary-rgb: 42, 161, 152;
38
+ --bs-secondary: #586e75;
39
+ --bs-secondary-rgb: 88, 110, 117;
40
+ --bs-success: #859900;
41
+ --bs-success-rgb: 133, 153, 0;
42
+ --bs-info: #268bd2;
43
+ --bs-info-rgb: 38, 139, 210;
44
+ --bs-warning: #b58900;
45
+ --bs-warning-rgb: 181, 137, 0;
46
+ --bs-danger: #dc322f;
47
+ --bs-danger-rgb: 220, 50, 47;
48
+ --bs-light: #eee8d5;
49
+ --bs-light-rgb: 238, 232, 213;
50
+ --bs-dark: #071014;
51
+ --bs-dark-rgb: 7, 16, 20;
52
+
53
+ /* Text emphasis: luminous but not neon. */
54
+ --bs-primary-text-emphasis: #65d1c9;
55
+ --bs-secondary-text-emphasis: #a4b2b7;
56
+ --bs-success-text-emphasis: #c4d65a;
57
+ --bs-info-text-emphasis: #7fc7f0;
58
+ --bs-warning-text-emphasis: #e8c766;
59
+ --bs-danger-text-emphasis: #f28b85;
60
+ --bs-light-text-emphasis: #fff6df;
61
+ --bs-dark-text-emphasis: #c4cdc9;
62
+
63
+ /* Subtle backgrounds: quiet color shadows, useful for badges, alerts, cards. */
64
+ --bs-primary-bg-subtle: #092e33;
65
+ --bs-secondary-bg-subtle: #151c22;
66
+ --bs-success-bg-subtle: #202800;
67
+ --bs-info-bg-subtle: #0a2638;
68
+ --bs-warning-bg-subtle: #2c2305;
69
+ --bs-danger-bg-subtle: #321010;
70
+ --bs-light-bg-subtle: #202a30;
71
+ --bs-dark-bg-subtle: #070b0e;
72
+
73
+ /* Borders: smoky, mineral, slightly chromatic. */
74
+ --bs-primary-border-subtle: #176c70;
75
+ --bs-secondary-border-subtle: #33434b;
76
+ --bs-success-border-subtle: #566400;
77
+ --bs-info-border-subtle: #185c83;
78
+ --bs-warning-border-subtle: #735a09;
79
+ --bs-danger-border-subtle: #7c211f;
80
+ --bs-light-border-subtle: #425058;
81
+ --bs-dark-border-subtle: #1c252c;
82
+
83
+ --bs-heading-color: #fff1cf;
84
+ --bs-link-color: #65d1c9;
85
+ --bs-link-hover-color: #8fe4dd;
86
+ --bs-link-color-rgb: 101, 209, 201;
87
+ --bs-link-hover-color-rgb: 143, 228, 221;
88
+ --bs-code-color: #d97aa6;
89
+ --bs-highlight-color: #fff6df;
90
+ --bs-highlight-bg: #4a3605;
91
+
92
+ --bs-border-color: #2b3941;
93
+ --bs-border-color-translucent: rgba(238, 232, 213, 0.14);
94
+
95
+ --bs-form-valid-color: #c4d65a;
96
+ --bs-form-valid-border-color: #6f8200;
97
+ --bs-form-invalid-color: #f28b85;
98
+ --bs-form-invalid-border-color: #9c2926;
99
+
100
+ /* Component affordances used by Bootstrap 5.3+ */
101
+ --bs-primary-bg-subtle-rgb: 9, 46, 51;
102
+ --bs-secondary-bg-subtle-rgb: 21, 28, 34;
103
+ --bs-success-bg-subtle-rgb: 32, 40, 0;
104
+ --bs-info-bg-subtle-rgb: 10, 38, 56;
105
+ --bs-warning-bg-subtle-rgb: 44, 35, 5;
106
+ --bs-danger-bg-subtle-rgb: 50, 16, 16;
107
+
108
+ /* Opinionated marketing/page tokens; optional, but useful in custom sections. */
109
+ --theme-canvas: #0b1014;
110
+ --theme-canvas-deep: #070b0e;
111
+ --theme-surface-1: #101821;
112
+ --theme-surface-2: #141e26;
113
+ --theme-surface-3: #1a252d;
114
+ --theme-fog: rgba(238, 232, 213, 0.08);
115
+ --theme-fog-strong: rgba(238, 232, 213, 0.14);
116
+ --theme-gold: #b58900;
117
+ --theme-cyan: #2aa198;
118
+ --theme-blue: #268bd2;
119
+ --theme-magenta: #d33682;
120
+ --theme-violet: #6c71c4;
121
+ --theme-red: #dc322f;
122
+ --theme-green: #859900;
123
+
124
+ --theme-hero-gradient:
125
+ radial-gradient(circle at 18% 8%, rgba(42, 161, 152, 0.22), transparent 34%),
126
+ radial-gradient(circle at 82% 18%, rgba(108, 113, 196, 0.18), transparent 30%),
127
+ radial-gradient(circle at 58% 82%, rgba(181, 137, 0, 0.12), transparent 36%),
128
+ linear-gradient(180deg, #0b1014 0%, #101821 48%, #070b0e 100%);
129
+ --theme-panel-gradient:
130
+ linear-gradient(180deg, rgba(255, 246, 223, 0.055), rgba(255, 246, 223, 0.018));
131
+ --theme-edge-light: rgba(255, 246, 223, 0.16);
132
+ --theme-edge-dark: rgba(0, 0, 0, 0.42);
133
+ --theme-shadow-soft: 0 24px 80px rgba(0, 0, 0, 0.42);
134
+ --theme-shadow-premium: 0 32px 120px rgba(0, 0, 0, 0.54), inset 0 1px 0 rgba(255, 246, 223, 0.08);
135
+
136
+ /* Optional polish for common Bootstrap surfaces on product/marketing pages. */
137
+ & body {
138
+ background:
139
+ radial-gradient(circle at 12% -8%, rgba(42, 161, 152, 0.16), transparent 28rem),
140
+ radial-gradient(circle at 84% 0%, rgba(108, 113, 196, 0.13), transparent 26rem),
141
+ var(--bs-body-bg);
142
+ background-repeat: no-repeat;
143
+ background-attachment: fixed;
144
+ }
145
+
146
+ & .card,
147
+ & .modal-content,
148
+ & .dropdown-menu,
149
+ & .offcanvas,
150
+ & .list-group-item {
151
+ background-color: var(--theme-surface-1);
152
+ background-image: var(--theme-panel-gradient);
153
+ border-color: var(--bs-border-color-translucent);
154
+ box-shadow: var(--theme-shadow-soft);
155
+ }
156
+
157
+ & .navbar,
158
+ & .bg-body-tertiary {
159
+ background-color: rgba(16, 24, 33, 0.82) !important;
160
+ /* backdrop-filter: blur(18px) saturate(122%); */
161
+ border-color: var(--bs-border-color-translucent);
162
+ }
163
+
164
+ & .btn-primary {
165
+ --bs-btn-color: #041113;
166
+ --bs-btn-bg: #65d1c9;
167
+ --bs-btn-border-color: #65d1c9;
168
+ --bs-btn-hover-color: #031012;
169
+ --bs-btn-hover-bg: #8fe4dd;
170
+ --bs-btn-hover-border-color: #8fe4dd;
171
+ --bs-btn-focus-shadow-rgb: 101, 209, 201;
172
+ --bs-btn-active-color: #031012;
173
+ --bs-btn-active-bg: #51beb6;
174
+ --bs-btn-active-border-color: #51beb6;
175
+ --bs-btn-disabled-color: #0b1014;
176
+ --bs-btn-disabled-bg: rgba(101, 209, 201, 0.45);
177
+ --bs-btn-disabled-border-color: rgba(101, 209, 201, 0.25);
178
+ }
179
+
180
+ & .btn-outline-primary {
181
+ --bs-btn-color: #65d1c9;
182
+ --bs-btn-border-color: rgba(101, 209, 201, 0.48);
183
+ --bs-btn-hover-color: #041113;
184
+ --bs-btn-hover-bg: #65d1c9;
185
+ --bs-btn-hover-border-color: #65d1c9;
186
+ --bs-btn-focus-shadow-rgb: 101, 209, 201;
187
+ --bs-btn-active-color: #041113;
188
+ --bs-btn-active-bg: #51beb6;
189
+ --bs-btn-active-border-color: #51beb6;
190
+ }
191
+
192
+ & .form-control,
193
+ & .form-select {
194
+ background-color: #0e151c;
195
+ border-color: #2e414a;
196
+ color: var(--bs-body-color);
197
+
198
+ &:focus {
199
+ background-color: #101922;
200
+ border-color: #65d1c9;
201
+ box-shadow: 0 0 0 0.25rem rgba(101, 209, 201, 0.16);
202
+ }
203
+ }
204
+
205
+ & ::selection {
206
+ color: #fff6df;
207
+ background: rgba(42, 161, 152, 0.42);
208
+ }
209
+ }
package/seed.html ADDED
@@ -0,0 +1,321 @@
1
+ <!doctype html>
2
+ <!--
3
+ seed.html
4
+ =========
5
+
6
+ A self-contained reference example for the Galath language. It demonstrates
7
+ every major feature in one page so a new author can read top-to-bottom and
8
+ see how the pieces fit:
9
+
10
+ * components with model + view + commandset + controller + listeners
11
+ * XML instance trees, signals, computed values
12
+ * bind:, on:, use:, drag:, drop: directives
13
+ * datatemplates and <items>
14
+ * routed XML events
15
+ * scoped <style>
16
+
17
+ The runtime lives in packages/galath. We pull it in via a native browser
18
+ import map so there is no build step. To run this file locally:
19
+
20
+ npx serve .
21
+ # or
22
+ python3 -m http.server 8080
23
+
24
+ Then open http://localhost:8080/seed.html
25
+ -->
26
+ <html lang="en" data-bs-theme="dark">
27
+ <head>
28
+ <meta charset="utf-8">
29
+ <meta name="viewport" content="width=device-width, initial-scale=1">
30
+ <title>Galath Strong Core - Reference Demo</title>
31
+
32
+ <!-- Local Bootstrap so the demo works offline. -->
33
+ <link href="./node_modules/galath-css/css/bootstrap.min.css" rel="stylesheet">
34
+ <link href="./node_modules/galath-css/css/bootstrap-icons.min.css" rel="stylesheet">
35
+
36
+ <!--
37
+ The import map lets `import 'galath'` resolve to our local source. No
38
+ bundler, no transpiler. The mapped path goes through the symlink at
39
+ node_modules/galath -> packages/galath.
40
+ -->
41
+ <script type="importmap">
42
+ {
43
+ "imports": {
44
+ "galath": "./node_modules/galath/src/index.js",
45
+ "galath/boot": "./node_modules/galath/src/boot.js"
46
+ }
47
+ }
48
+ </script>
49
+
50
+ <style>
51
+ /* These styles are page-level (the demo's chrome). Component-level
52
+ styles live inside the <component>'s own <style> block - see how the
53
+ feature-badge component's accent color is scoped, below. */
54
+ :root {
55
+ --xes-shell: #06101f;
56
+ --xes-line: rgba(255, 255, 255, .12);
57
+ --xes-card: rgba(255, 255, 255, .045);
58
+ --xes-card-2: rgba(255, 255, 255, .022);
59
+ }
60
+ body {
61
+ min-height: 100vh;
62
+ background:
63
+ radial-gradient(circle at top left, rgba(13, 202, 240, .14), transparent 34rem),
64
+ radial-gradient(circle at top right, rgba(255, 193, 7, .08), transparent 28rem),
65
+ linear-gradient(180deg, #040812, var(--xes-shell));
66
+ }
67
+ .xes-shell { min-height: 100vh; }
68
+ .xes-hero { border-bottom: 1px solid var(--xes-line); background: linear-gradient(180deg, rgba(255,255,255,.05), transparent); }
69
+ .xes-card { background: linear-gradient(180deg, var(--xes-card), var(--xes-card-2)); border: 1px solid var(--xes-line); box-shadow: 0 1rem 3rem rgba(0,0,0,.22); }
70
+ .xes-code { max-height: 24rem; overflow: auto; font-size: .825rem; background: rgba(0,0,0,.34); border: 1px solid var(--xes-line); }
71
+ .xes-nav-link { width: 100%; text-align: left; color: var(--bs-body-color); background: transparent; border: 0; }
72
+ .xes-nav-link:hover { background-color: rgba(255,255,255,.07); }
73
+ .xes-nav-link.active { background-color: rgba(13,202,240,.16); box-shadow: inset 3px 0 0 var(--bs-info); color: var(--bs-info-text-emphasis); }
74
+ .xes-pill { border: 1px solid var(--xes-line); background-color: rgba(255,255,255,.045); }
75
+ .xes-tiny { font-size: .78rem; }
76
+ .xes-drop-hint { outline: 1px dashed rgba(13, 202, 240, .35); outline-offset: .35rem; }
77
+ .xes-dragging { opacity: .55; }
78
+ </style>
79
+ </head>
80
+ <body>
81
+ <div id="mount"></div>
82
+
83
+ <!--
84
+ The Galath source lives in a script tag with a non-JS MIME type. The
85
+ browser does not execute it; we read its textContent at boot time.
86
+ Embedding the source as a <script> avoids escaping issues that you'd
87
+ hit with putting it inside a JS string.
88
+ -->
89
+ <script type="application/xml" id="galath-source">
90
+ <galath version="1.0"
91
+ xmlns:bind="urn:galath:bind"
92
+ xmlns:on="urn:galath:on"
93
+ xmlns:use="urn:galath:use"
94
+ xmlns:drag="urn:galath:drag"
95
+ xmlns:drop="urn:galath:drop"
96
+ xmlns:class="urn:galath:class">
97
+
98
+ <!--
99
+ A tiny presentational component. It accepts `icon`, `label`, and
100
+ `tone` props and renders a Bootstrap pill. `<style>` content is
101
+ auto-scoped to instances of this tag.
102
+ -->
103
+ <component name="feature-badge" tag="x-feature-badge" icon="bi-cpu" label="Feature" tone="info">
104
+ <style>
105
+ .badge { transition: transform .12s ease; }
106
+ .badge:hover { transform: translateY(-1px); }
107
+ </style>
108
+ <view>
109
+ <span class="badge rounded-pill xes-pill text-body-emphasis me-1 mb-1">
110
+ <i class="bi {icon} me-1"></i>{label}
111
+ </span>
112
+ </view>
113
+ </component>
114
+
115
+ <!--
116
+ The main app component. Holds an instance tree of todos plus a few
117
+ signals for UI state. Demonstrates: signals, computed, instance
118
+ tree, bindings, repeaters, items + datatemplate, commands,
119
+ controllers, listeners, behaviors, drag/drop.
120
+ -->
121
+ <component name="docs-app" tag="x-docs-app" title="Galath Strong Core">
122
+ <model>
123
+ <signal name="activeSection" value="model" />
124
+ <signal name="eventLog" value="" />
125
+ <signal name="noteText" value="Actions are controller-owned. Views stay declarative." />
126
+
127
+ <!--
128
+ The instance tree IS the application's state. Attributes are
129
+ reactive cells; mutations emit `xforms-*` events.
130
+ -->
131
+ <instance>
132
+ <draft text="Write a stronger XML app language" />
133
+ <todos>
134
+ <todo id="t1" text="Model data as XML instance nodes" done="true" />
135
+ <todo id="t2" text="Bind controls to paths" done="false" />
136
+ <todo id="t3" text="Render nodes with DataTemplate" done="false" />
137
+ </todos>
138
+ </instance>
139
+
140
+ <!--
141
+ <computed> is a derived signal. It re-evaluates whenever its
142
+ `from` source changes. We pin it to the tree's version counter
143
+ (any tree change) by referencing a magical `eventLog` signal
144
+ via `from` - see the engine's <computed> setup for the rule.
145
+ -->
146
+ <computed name="todoCount" from="eventLog">
147
+ <expression>select('/todos/todo').length</expression>
148
+ </computed>
149
+ </model>
150
+
151
+ <!-- Reusable view fragment. Used below by <items>. -->
152
+ <datatemplate name="todo-card" for="todo">
153
+ <div class="col-md-6 col-xl-4">
154
+ <div class="card xes-card h-100" drag:source="$todo" drop:target="$todo" drop:command="moveTodoBefore">
155
+ <div class="card-body">
156
+ <div class="d-flex gap-2 align-items-start">
157
+ <input class="form-check-input mt-1" type="checkbox" bind:checked="$todo/@done" />
158
+ <div class="flex-grow-1">
159
+ <div class="fw-semibold"><text value="$todo/@text" /></div>
160
+ <div class="text-secondary xes-tiny">id: <text value="$todo/@id" /></div>
161
+ </div>
162
+ <button class="btn btn-sm btn-outline-danger" on:click="deleteNode($todo)" title="Delete">
163
+ <i class="bi bi-x-lg"></i>
164
+ </button>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+ </datatemplate>
170
+
171
+ <!--
172
+ Centralized commands. Each one declares optional `enabled` logic
173
+ re-evaluated as part of every render so buttons disable
174
+ automatically.
175
+ -->
176
+ <commandset>
177
+ <command name="addTodo" enabled="valueOf('/draft/@text').trim().length > 0">
178
+ <insert ref="/todos">
179
+ <todo id="{uid()}" text="{valueOf('/draft/@text')}" done="false" />
180
+ </insert>
181
+ <setvalue ref="/draft/@text" value="'New XML task'" />
182
+ </command>
183
+
184
+ <command name="deleteDone" enabled="select('/todos/todo[@done=true]').length > 0">
185
+ <delete ref="/todos/todo[@done=true]" />
186
+ </command>
187
+
188
+ <command name="clearLog" enabled="eventLog.length > 0">
189
+ <set signal="eventLog" value="''" />
190
+ </command>
191
+
192
+ <!--
193
+ moveTodoBefore is bound to drop:command. It receives `$source`
194
+ and `$target` in scope - both are XNodes.
195
+ -->
196
+ <command name="moveTodoBefore">
197
+ <eval>
198
+ if ($source &amp;&amp; $target &amp;&amp; $source !== $target) {
199
+ $source.remove();
200
+ $target.parent.insertBefore($source, $target);
201
+ }
202
+ </eval>
203
+ </command>
204
+ </commandset>
205
+
206
+ <!-- Named actions. Views invoke them with `#actionName`. -->
207
+ <controller>
208
+ <action name="logTreeEvent">
209
+ <set signal="eventLog" value="$event.type + ' at ' + $event.path + '\n' + eventLog" />
210
+ </action>
211
+ <action name="markAllDone">
212
+ <setvalue ref="/todos/todo/@done" value="true" />
213
+ </action>
214
+ </controller>
215
+
216
+ <!--
217
+ Routed XML events: the controller can react to data-tree
218
+ mutations declaratively. `observer` filters by path prefix.
219
+ -->
220
+ <listeners>
221
+ <listener event="xforms-insert" observer="/todos" handler="#logTreeEvent" />
222
+ <listener event="xforms-delete" observer="/todos" handler="#logTreeEvent" />
223
+ <listener event="xforms-value-changed" observer="/todos" handler="#logTreeEvent" />
224
+ </listeners>
225
+
226
+ <view>
227
+ <main class="xes-shell">
228
+ <section class="xes-hero py-5">
229
+ <div class="container-xxl">
230
+ <div class="row align-items-center g-4">
231
+ <div class="col-lg-8">
232
+ <div class="d-flex gap-2 flex-wrap mb-3">
233
+ <x-feature-badge icon="bi-database" label="XForms" />
234
+ <x-feature-badge icon="bi-ui-checks-grid" label="XAML" />
235
+ <x-feature-badge icon="bi-command" label="XUL" />
236
+ <x-feature-badge icon="bi-person-gear" label="FXML" />
237
+ <x-feature-badge icon="bi-puzzle" label="Behaviors" />
238
+ </div>
239
+ <h1 class="display-5 fw-semibold mb-3">{title}</h1>
240
+ <p class="lead text-secondary mb-4">
241
+ Galath: a stronger XML language for the web. XML instance data, path
242
+ bindings, repeaters, templates, commandsets, controllers, routed events,
243
+ attached behaviors, scoped signals, and surgical DOM rendering.
244
+ </p>
245
+ <div class="d-flex gap-2 flex-wrap">
246
+ <a class="btn btn-info" href="./index.html">
247
+ <i class="bi bi-play-circle me-1"></i>Open the Playground
248
+ </a>
249
+ </div>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ </section>
254
+
255
+ <section class="container-xxl py-4">
256
+ <div class="row g-4">
257
+ <div class="col-lg-12">
258
+ <div class="card xes-card">
259
+ <div class="card-header bg-transparent d-flex justify-content-between align-items-center">
260
+ <strong><i class="bi bi-window-stack me-2"></i>Live XML instance demo</strong>
261
+ <span class="badge text-bg-info"><text value="todoCount" /> XML nodes</span>
262
+ </div>
263
+ <div class="card-body">
264
+ <div class="row g-3 mb-4">
265
+ <div class="col-lg-7">
266
+ <label class="form-label">Draft todo bound to <code>/draft/@text</code></label>
267
+ <div class="input-group">
268
+ <span class="input-group-text"><i class="bi bi-pencil-square"></i></span>
269
+ <input class="form-control" bind:value="/draft/@text" />
270
+ <button class="btn btn-info" command="addTodo">
271
+ <i class="bi bi-plus-circle me-1"></i>Insert
272
+ </button>
273
+ </div>
274
+ </div>
275
+ <div class="col-lg-5 d-flex align-items-end gap-2 flex-wrap">
276
+ <button class="btn btn-outline-light" command="deleteDone"><i class="bi bi-trash me-1"></i>Delete done</button>
277
+ <button class="btn btn-outline-light" on:click="#markAllDone"><i class="bi bi-check2-all me-1"></i>Mark all done</button>
278
+ <button class="btn btn-outline-secondary" command="clearLog"><i class="bi bi-eraser me-1"></i>Clear log</button>
279
+ </div>
280
+ </div>
281
+
282
+ <div class="row g-3 mb-4">
283
+ <items source="/todos/todo" as="todo" template="todo-card" />
284
+ </div>
285
+
286
+ <label class="form-label">Event log</label>
287
+ <textarea class="form-control font-monospace" rows="5" bind:value="eventLog"></textarea>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ </div>
292
+ </section>
293
+ </main>
294
+ </view>
295
+ </component>
296
+
297
+ <!-- The application is the page-level entry. -->
298
+ <application name="demo">
299
+ <x-docs-app title="Galath Strong Core"></x-docs-app>
300
+ </application>
301
+ </galath>
302
+ </script>
303
+
304
+ <!--
305
+ Boot: read the source from the script tag, hand it to galath, and let
306
+ the runtime register components and mount the app. Async because
307
+ `<import>` can fetch additional XML at startup.
308
+ -->
309
+ <script type="module">
310
+ import { boot } from 'galath/boot';
311
+
312
+ const language = await boot({
313
+ source: document.getElementById('galath-source').textContent,
314
+ mount: document.getElementById('mount'),
315
+ });
316
+
317
+ // Expose for console exploration in dev tools.
318
+ window.galath = language;
319
+ </script>
320
+ </body>
321
+ </html>