lego-dom 1.3.4 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -1
- package/main.js +48 -17
- package/main.min.js +2 -2
- package/package.json +1 -1
- package/parse-lego.js +2 -2
- package/vite-plugin.js +0 -14
- package/.github/workflows/deploy-docs.yml +0 -56
- package/.legodom +0 -87
- package/docs/.vitepress/config.js +0 -161
- package/docs/api/config.md +0 -95
- package/docs/api/define.md +0 -58
- package/docs/api/directives.md +0 -50
- package/docs/api/globals.md +0 -29
- package/docs/api/index.md +0 -30
- package/docs/api/lifecycle.md +0 -40
- package/docs/api/route.md +0 -37
- package/docs/api/vite-plugin.md +0 -58
- package/docs/contributing/01-welcome.md +0 -38
- package/docs/contributing/02-registry.md +0 -133
- package/docs/contributing/03-batcher.md +0 -110
- package/docs/contributing/04-reactivity.md +0 -87
- package/docs/contributing/05-caching.md +0 -59
- package/docs/contributing/06-init.md +0 -136
- package/docs/contributing/07-observer.md +0 -72
- package/docs/contributing/08-snap.md +0 -140
- package/docs/contributing/09-diffing.md +0 -69
- package/docs/contributing/10-studs.md +0 -78
- package/docs/contributing/11-scanner.md +0 -117
- package/docs/contributing/12-render.md +0 -138
- package/docs/contributing/13-directives.md +0 -243
- package/docs/contributing/14-events.md +0 -57
- package/docs/contributing/15-router.md +0 -57
- package/docs/contributing/16-state.md +0 -47
- package/docs/contributing/17-legodom.md +0 -48
- package/docs/contributing/index.md +0 -24
- package/docs/examples/form.md +0 -42
- package/docs/examples/index.md +0 -104
- package/docs/examples/routing.md +0 -409
- package/docs/examples/sfc-showcase.md +0 -34
- package/docs/examples/todo-app.md +0 -383
- package/docs/guide/cdn-usage.md +0 -354
- package/docs/guide/components.md +0 -418
- package/docs/guide/directives.md +0 -539
- package/docs/guide/directory-structure.md +0 -248
- package/docs/guide/faq.md +0 -210
- package/docs/guide/getting-started.md +0 -262
- package/docs/guide/index.md +0 -88
- package/docs/guide/lifecycle.md +0 -525
- package/docs/guide/quick-start.md +0 -49
- package/docs/guide/reactivity.md +0 -415
- package/docs/guide/routing.md +0 -334
- package/docs/guide/server-side.md +0 -134
- package/docs/guide/sfc.md +0 -464
- package/docs/guide/templating.md +0 -388
- package/docs/index.md +0 -160
- package/docs/public/logo.svg +0 -17
- package/docs/router/basic-routing.md +0 -103
- package/docs/router/cold-entry.md +0 -91
- package/docs/router/history.md +0 -69
- package/docs/router/index.md +0 -73
- package/docs/router/resolver.md +0 -74
- package/docs/router/surgical-swaps.md +0 -134
- package/docs/tutorial/01-project-setup.md +0 -152
- package/docs/tutorial/02-your-first-component.md +0 -226
- package/docs/tutorial/03-adding-routes.md +0 -279
- package/docs/tutorial/04-multi-page-app.md +0 -329
- package/docs/tutorial/05-state-and-globals.md +0 -285
- package/docs/tutorial/index.md +0 -40
- package/examples/vite-app/README.md +0 -71
- package/examples/vite-app/index.html +0 -42
- package/examples/vite-app/package.json +0 -18
- package/examples/vite-app/src/app.css +0 -3
- package/examples/vite-app/src/app.js +0 -29
- package/examples/vite-app/src/components/app-navbar.lego +0 -34
- package/examples/vite-app/src/components/customers/customer-details.lego +0 -24
- package/examples/vite-app/src/components/customers/customer-orders.lego +0 -21
- package/examples/vite-app/src/components/customers/order-list.lego +0 -55
- package/examples/vite-app/src/components/greeting-card.lego +0 -41
- package/examples/vite-app/src/components/sample-component.lego +0 -75
- package/examples/vite-app/src/components/shells/customers-shell.lego +0 -21
- package/examples/vite-app/src/components/side-menu.lego +0 -46
- package/examples/vite-app/src/components/todo-list.lego +0 -239
- package/examples/vite-app/src/components/widgets/user-card.lego +0 -27
- package/examples/vite-app/vite.config.js +0 -22
- package/tests/error.test.js +0 -74
- package/tests/main.test.js +0 -103
- package/tests/memory.test.js +0 -68
- package/tests/monitoring.test.js +0 -74
- package/tests/naming.test.js +0 -74
- package/tests/parse-lego.test.js +0 -65
- package/tests/security.test.js +0 -67
- package/tests/server.test.js +0 -114
- package/tests/syntax.test.js +0 -67
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
# Todo App Example
|
|
2
|
-
|
|
3
|
-
A complete todo application demonstrating Lego features.
|
|
4
|
-
|
|
5
|
-
## Live Demo
|
|
6
|
-
|
|
7
|
-
<iframe src="/demos/todo-app.html" style="width:100%;height:500px;border:1px solid #ddd;border-radius:4px;"></iframe>
|
|
8
|
-
|
|
9
|
-
## Full Source Code
|
|
10
|
-
|
|
11
|
-
```html
|
|
12
|
-
<!DOCTYPE html>
|
|
13
|
-
<html lang="en">
|
|
14
|
-
<head>
|
|
15
|
-
<meta charset="UTF-8">
|
|
16
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
-
<title>Todo App - Lego</title>
|
|
18
|
-
<style>
|
|
19
|
-
body {
|
|
20
|
-
font-family: system-ui, -apple-system, sans-serif;
|
|
21
|
-
max-width: 600px;
|
|
22
|
-
margin: 2rem auto;
|
|
23
|
-
padding: 0 1rem;
|
|
24
|
-
background: #f5f5f5;
|
|
25
|
-
}
|
|
26
|
-
h1 {
|
|
27
|
-
text-align: center;
|
|
28
|
-
color: #333;
|
|
29
|
-
}
|
|
30
|
-
</style>
|
|
31
|
-
</head>
|
|
32
|
-
<body>
|
|
33
|
-
<h1>📝 Todo App</h1>
|
|
34
|
-
|
|
35
|
-
<todo-app></todo-app>
|
|
36
|
-
|
|
37
|
-
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
38
|
-
|
|
39
|
-
<template b-id="todo-app">
|
|
40
|
-
<style>
|
|
41
|
-
self {
|
|
42
|
-
display: block;
|
|
43
|
-
background: white;
|
|
44
|
-
border-radius: 8px;
|
|
45
|
-
padding: 1.5rem;
|
|
46
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.input-group {
|
|
50
|
-
display: flex;
|
|
51
|
-
gap: 0.5rem;
|
|
52
|
-
margin-bottom: 1.5rem;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
input[type="text"] {
|
|
56
|
-
flex: 1;
|
|
57
|
-
padding: 0.75rem;
|
|
58
|
-
font-size: 1rem;
|
|
59
|
-
border: 2px solid #e0e0e0;
|
|
60
|
-
border-radius: 4px;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
input[type="text"]:focus {
|
|
64
|
-
outline: none;
|
|
65
|
-
border-color: #4CAF50;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.btn {
|
|
69
|
-
padding: 0.75rem 1.5rem;
|
|
70
|
-
font-size: 1rem;
|
|
71
|
-
border: none;
|
|
72
|
-
border-radius: 4px;
|
|
73
|
-
cursor: pointer;
|
|
74
|
-
font-weight: 600;
|
|
75
|
-
transition: background 0.2s;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.btn-primary {
|
|
79
|
-
background: #4CAF50;
|
|
80
|
-
color: white;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.btn-primary:hover {
|
|
84
|
-
background: #45a049;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.filters {
|
|
88
|
-
display: flex;
|
|
89
|
-
gap: 0.5rem;
|
|
90
|
-
margin-bottom: 1rem;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
.filter-btn {
|
|
94
|
-
padding: 0.5rem 1rem;
|
|
95
|
-
background: #f0f0f0;
|
|
96
|
-
border: none;
|
|
97
|
-
border-radius: 4px;
|
|
98
|
-
cursor: pointer;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
.filter-btn.active {
|
|
102
|
-
background: #4CAF50;
|
|
103
|
-
color: white;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
ul {
|
|
107
|
-
list-style: none;
|
|
108
|
-
padding: 0;
|
|
109
|
-
margin: 0;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
li {
|
|
113
|
-
display: flex;
|
|
114
|
-
align-items: center;
|
|
115
|
-
gap: 0.75rem;
|
|
116
|
-
padding: 0.75rem;
|
|
117
|
-
border-bottom: 1px solid #f0f0f0;
|
|
118
|
-
transition: background 0.2s;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
li:hover {
|
|
122
|
-
background: #f9f9f9;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
input[type="checkbox"] {
|
|
126
|
-
width: 20px;
|
|
127
|
-
height: 20px;
|
|
128
|
-
cursor: pointer;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.todo-text {
|
|
132
|
-
flex: 1;
|
|
133
|
-
font-size: 1rem;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.todo-text.done {
|
|
137
|
-
text-decoration: line-through;
|
|
138
|
-
color: #999;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.delete-btn {
|
|
142
|
-
padding: 0.25rem 0.5rem;
|
|
143
|
-
background: #f44336;
|
|
144
|
-
color: white;
|
|
145
|
-
border: none;
|
|
146
|
-
border-radius: 4px;
|
|
147
|
-
cursor: pointer;
|
|
148
|
-
font-size: 0.875rem;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
.delete-btn:hover {
|
|
152
|
-
background: #da190b;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
.stats {
|
|
156
|
-
margin-top: 1rem;
|
|
157
|
-
padding-top: 1rem;
|
|
158
|
-
border-top: 2px solid #f0f0f0;
|
|
159
|
-
display: flex;
|
|
160
|
-
justify-content: space-between;
|
|
161
|
-
color: #666;
|
|
162
|
-
font-size: 0.875rem;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.clear-completed {
|
|
166
|
-
background: none;
|
|
167
|
-
border: none;
|
|
168
|
-
color: #f44336;
|
|
169
|
-
cursor: pointer;
|
|
170
|
-
text-decoration: underline;
|
|
171
|
-
}
|
|
172
|
-
</style>
|
|
173
|
-
|
|
174
|
-
<div class="input-group">
|
|
175
|
-
<input
|
|
176
|
-
type="text"
|
|
177
|
-
b-sync="newTodo"
|
|
178
|
-
placeholder="What needs to be done?"
|
|
179
|
-
@keyup="event.key === 'Enter' && addTodo()">
|
|
180
|
-
<button class="btn btn-primary" @click="addTodo()">Add</button>
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
<div class="filters">
|
|
184
|
-
<button
|
|
185
|
-
class="filter-btn [[ filter === 'all' ? 'active' : '' ]]"
|
|
186
|
-
@click="filter = 'all'">
|
|
187
|
-
All
|
|
188
|
-
</button>
|
|
189
|
-
<button
|
|
190
|
-
class="filter-btn [[ filter === 'active' ? 'active' : '' ]]"
|
|
191
|
-
@click="filter = 'active'">
|
|
192
|
-
Active
|
|
193
|
-
</button>
|
|
194
|
-
<button
|
|
195
|
-
class="filter-btn [[ filter === 'completed' ? 'active' : '' ]]"
|
|
196
|
-
@click="filter = 'completed'">
|
|
197
|
-
Completed
|
|
198
|
-
</button>
|
|
199
|
-
</div>
|
|
200
|
-
|
|
201
|
-
<ul>
|
|
202
|
-
<li b-for="todo in filteredTodos()">
|
|
203
|
-
<input type="checkbox" b-sync="todo.done">
|
|
204
|
-
<span class="todo-text [[ todo.done ? 'done' : '' ]]">
|
|
205
|
-
[[ todo.text ]]
|
|
206
|
-
</span>
|
|
207
|
-
<button class="delete-btn" @click="deleteTodo(todo)">Delete</button>
|
|
208
|
-
</li>
|
|
209
|
-
</ul>
|
|
210
|
-
|
|
211
|
-
<div class="stats">
|
|
212
|
-
<span>[[ remaining() ]] item[[ remaining() === 1 ? '' : 's' ]] left</span>
|
|
213
|
-
<button
|
|
214
|
-
class="clear-completed"
|
|
215
|
-
b-show="completedCount() > 0"
|
|
216
|
-
@click="clearCompleted()">
|
|
217
|
-
Clear completed ([[ completedCount() ]])
|
|
218
|
-
</button>
|
|
219
|
-
</div>
|
|
220
|
-
</template>
|
|
221
|
-
|
|
222
|
-
<script>
|
|
223
|
-
Lego.define('todo-app',
|
|
224
|
-
document.querySelector('template[b-id="todo-app"]').innerHTML,
|
|
225
|
-
{
|
|
226
|
-
newTodo: '',
|
|
227
|
-
filter: 'all',
|
|
228
|
-
todos: [],
|
|
229
|
-
|
|
230
|
-
mounted() {
|
|
231
|
-
// Load from localStorage
|
|
232
|
-
const saved = localStorage.getItem('legojs-todos');
|
|
233
|
-
if (saved) {
|
|
234
|
-
this.todos = JSON.parse(saved);
|
|
235
|
-
}
|
|
236
|
-
},
|
|
237
|
-
|
|
238
|
-
updated() {
|
|
239
|
-
// Save to localStorage
|
|
240
|
-
localStorage.setItem('legojs-todos', JSON.stringify(this.todos));
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
addTodo() {
|
|
244
|
-
if (this.newTodo.trim()) {
|
|
245
|
-
this.todos.push({
|
|
246
|
-
id: Date.now(),
|
|
247
|
-
text: this.newTodo,
|
|
248
|
-
done: false
|
|
249
|
-
});
|
|
250
|
-
this.newTodo = '';
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
|
|
254
|
-
deleteTodo(todo) {
|
|
255
|
-
const index = this.todos.indexOf(todo);
|
|
256
|
-
if (index > -1) {
|
|
257
|
-
this.todos.splice(index, 1);
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
|
|
261
|
-
filteredTodos() {
|
|
262
|
-
if (this.filter === 'active') {
|
|
263
|
-
return this.todos.filter(t => !t.done);
|
|
264
|
-
} else if (this.filter === 'completed') {
|
|
265
|
-
return this.todos.filter(t => t.done);
|
|
266
|
-
}
|
|
267
|
-
return this.todos;
|
|
268
|
-
},
|
|
269
|
-
|
|
270
|
-
remaining() {
|
|
271
|
-
return this.todos.filter(t => !t.done).length;
|
|
272
|
-
},
|
|
273
|
-
|
|
274
|
-
completedCount() {
|
|
275
|
-
return this.todos.filter(t => t.done).length;
|
|
276
|
-
},
|
|
277
|
-
|
|
278
|
-
clearCompleted() {
|
|
279
|
-
this.todos = this.todos.filter(t => !t.done);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
);
|
|
283
|
-
</script>
|
|
284
|
-
</body>
|
|
285
|
-
</html>
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## Features Demonstrated
|
|
289
|
-
|
|
290
|
-
### ✅ Reactivity
|
|
291
|
-
- Auto-updates when todos change
|
|
292
|
-
- Two-way binding with `b-sync`
|
|
293
|
-
- Computed values (`remaining()`, `completedCount()`)
|
|
294
|
-
|
|
295
|
-
### ✅ List Rendering
|
|
296
|
-
- `b-for` to iterate over todos
|
|
297
|
-
- Dynamic filtering based on status
|
|
298
|
-
|
|
299
|
-
### ✅ Event Handling
|
|
300
|
-
- Add on Enter key
|
|
301
|
-
- Click to complete/delete
|
|
302
|
-
- Filter buttons
|
|
303
|
-
|
|
304
|
-
### ✅ Lifecycle Hooks
|
|
305
|
-
- `mounted()` - Load from localStorage
|
|
306
|
-
- `updated()` - Save to localStorage
|
|
307
|
-
|
|
308
|
-
### ✅ Conditional Rendering
|
|
309
|
-
- Show/hide "Clear completed" button
|
|
310
|
-
- Different styles for completed items
|
|
311
|
-
|
|
312
|
-
### ✅ Methods
|
|
313
|
-
- `addTodo()` - Add new item
|
|
314
|
-
- `deleteTodo()` - Remove item
|
|
315
|
-
- `filteredTodos()` - Filter logic
|
|
316
|
-
- `clearCompleted()` - Batch delete
|
|
317
|
-
|
|
318
|
-
## Key Concepts
|
|
319
|
-
|
|
320
|
-
### Local Storage Persistence
|
|
321
|
-
|
|
322
|
-
```js
|
|
323
|
-
mounted() {
|
|
324
|
-
const saved = localStorage.getItem('legojs-todos');
|
|
325
|
-
if (saved) {
|
|
326
|
-
this.todos = JSON.parse(saved);
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
|
|
330
|
-
updated() {
|
|
331
|
-
localStorage.setItem('legojs-todos', JSON.stringify(this.todos));
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### Filtering
|
|
336
|
-
|
|
337
|
-
```js
|
|
338
|
-
filteredTodos() {
|
|
339
|
-
if (this.filter === 'active') {
|
|
340
|
-
return this.todos.filter(t => !t.done);
|
|
341
|
-
} else if (this.filter === 'completed') {
|
|
342
|
-
return this.todos.filter(t => t.done);
|
|
343
|
-
}
|
|
344
|
-
return this.todos;
|
|
345
|
-
}
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
### Array Manipulation
|
|
349
|
-
|
|
350
|
-
```js
|
|
351
|
-
// Add
|
|
352
|
-
this.todos.push({ ... });
|
|
353
|
-
|
|
354
|
-
// Remove
|
|
355
|
-
this.todos.splice(index, 1);
|
|
356
|
-
|
|
357
|
-
// Filter (reassign)
|
|
358
|
-
this.todos = this.todos.filter(t => !t.done);
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
## Try It Yourself
|
|
362
|
-
|
|
363
|
-
1. Copy the code above
|
|
364
|
-
2. Save as `todo.html`
|
|
365
|
-
3. Open in a browser
|
|
366
|
-
4. Add todos, mark as complete, filter, delete
|
|
367
|
-
5. Refresh—todos persist!
|
|
368
|
-
|
|
369
|
-
## Extensions
|
|
370
|
-
|
|
371
|
-
Try adding these features:
|
|
372
|
-
|
|
373
|
-
- **Edit mode** - Double click to edit todo text
|
|
374
|
-
- **Due dates** - Add date picker and sort by date
|
|
375
|
-
- **Categories** - Organize todos into lists
|
|
376
|
-
- **Drag & drop** - Reorder todos
|
|
377
|
-
- **Export/Import** - Download/upload todo list
|
|
378
|
-
|
|
379
|
-
## Next Steps
|
|
380
|
-
|
|
381
|
-
- See [Routing Example](/examples/routing)
|
|
382
|
-
- Learn about [Form Validation](/examples/form)
|
|
383
|
-
- Explore [SFC Showcase](/examples/sfc-showcase)
|