lego-dom 0.0.3 โ 0.0.4
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/.ignore/auto.html +135 -0
- package/.ignore/test.html +73 -0
- package/about.md +523 -0
- package/index.js +26 -0
- package/main.js +459 -0
- package/main.test.js +86 -0
- package/package.json +14 -8
- package/README.md +0 -177
- package/dist/dom/index.js +0 -1
- package/dist/index.js +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/traverser.js +0 -1
- package/dist/veyors/basket.js +0 -2
- package/dist/veyors/brick.js +0 -1
- package/dist/veyors/index.js +0 -1
- package/dist/veyors/router.js +0 -1
- package/example/blocks/banner.lego +0 -0
- package/example/blocks/card.lego +0 -40
- package/example/blocks/form.lego +0 -31
- package/example/bricks/index.html +0 -50
- package/src/dom/index.ts +0 -0
- package/src/index.ts +0 -0
- package/src/utils/index.ts +0 -0
- package/src/utils/traverser.ts +0 -0
- package/src/veyors/basket.ts +0 -5
- package/src/veyors/brick.ts +0 -0
- package/src/veyors/index.ts +0 -0
- package/src/veyors/router.ts +0 -0
- package/tsconfig.json +0 -69
package/about.md
ADDED
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
# Lego JS Library
|
|
2
|
+
|
|
3
|
+
Lego JS is a surgical, zero-dependency reactive library for building native Web Components. It skips the virtual DOM overhead, leveraging Proxies and Shadow DOM to provide a lightweight (<5KB) alternative to the heavy-duty framework status quo.
|
|
4
|
+
|
|
5
|
+
## ๐ Core Concepts
|
|
6
|
+
|
|
7
|
+
### 1. Reactive State (`studs`)
|
|
8
|
+
|
|
9
|
+
Lego components use a reactive state object called `studs`. State mutations trigger efficient, batched DOM updates via `requestAnimationFrame`โminimizing reflows without a complex reconciliation engine.
|
|
10
|
+
|
|
11
|
+
### 2. Shadow DOM Encapsulation
|
|
12
|
+
|
|
13
|
+
Styles and logic are scoped by default. Use the `self` selector inside a component's `<style>` tag to target the host element without worrying about CSS leakage or global collisions.
|
|
14
|
+
|
|
15
|
+
### 3. Directives (`b-`)
|
|
16
|
+
|
|
17
|
+
Native-feeling attributes (`b-if`, `b-for`, `b-sync`) bridge your data to the DOM. No JSX, no compilation required for core featuresโjust standard HTML.
|
|
18
|
+
|
|
19
|
+
## ๐ Quickstart
|
|
20
|
+
|
|
21
|
+
### ๐ฆ Installation
|
|
22
|
+
|
|
23
|
+
Drop the script and start building. No build step, no `npm install` fatigue.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
<script src="path/to/main.js"></script>
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### ๐ Creating your first Component
|
|
31
|
+
|
|
32
|
+
Define logic and layout in a standard `<template>`.
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
<!-- Define -->
|
|
36
|
+
<template b-id="greeting-card">
|
|
37
|
+
<style>
|
|
38
|
+
self { display: block; padding: 20px; border-radius: 8px; background: #f0f4f8; }
|
|
39
|
+
</style>
|
|
40
|
+
|
|
41
|
+
<h2>Hello, {{ name }}!</h2>
|
|
42
|
+
<button @click="showBio = !showBio">Toggle Bio</button>
|
|
43
|
+
<p b-if="showBio">{{ bio }}</p>
|
|
44
|
+
</template>
|
|
45
|
+
|
|
46
|
+
<!-- Execute -->
|
|
47
|
+
<greeting-card b-data="{ name: 'Alex', bio: 'Dev', showBio: false }"></greeting-card>
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## ๐ Directives Deep Dive
|
|
52
|
+
|
|
53
|
+
Directive
|
|
54
|
+
|
|
55
|
+
Type
|
|
56
|
+
|
|
57
|
+
Description
|
|
58
|
+
|
|
59
|
+
Example
|
|
60
|
+
|
|
61
|
+
`b-id`
|
|
62
|
+
|
|
63
|
+
Definition
|
|
64
|
+
|
|
65
|
+
Registers the custom element tag name.
|
|
66
|
+
|
|
67
|
+
`<template b-id="my-tag">`
|
|
68
|
+
|
|
69
|
+
`b-data`
|
|
70
|
+
|
|
71
|
+
Initialization
|
|
72
|
+
|
|
73
|
+
Sets the initial reactive state.
|
|
74
|
+
|
|
75
|
+
`<my-tag b-data="{ count: 0 }">`
|
|
76
|
+
|
|
77
|
+
`b-sync`
|
|
78
|
+
|
|
79
|
+
Two-way
|
|
80
|
+
|
|
81
|
+
Bi-directional binding for form inputs.
|
|
82
|
+
|
|
83
|
+
`<input b-sync="query">`
|
|
84
|
+
|
|
85
|
+
`b-for`
|
|
86
|
+
|
|
87
|
+
Structural
|
|
88
|
+
|
|
89
|
+
High-performance array looping.
|
|
90
|
+
|
|
91
|
+
`<li b-for="u in users">{{ u.name }}</li>`
|
|
92
|
+
|
|
93
|
+
`b-if`
|
|
94
|
+
|
|
95
|
+
Structural
|
|
96
|
+
|
|
97
|
+
Toggles presence based on truthiness.
|
|
98
|
+
|
|
99
|
+
`<div b-if="isAdmin">Admin</div>`
|
|
100
|
+
|
|
101
|
+
`b-text`
|
|
102
|
+
|
|
103
|
+
Binding
|
|
104
|
+
|
|
105
|
+
Escaped text binding (one-way).
|
|
106
|
+
|
|
107
|
+
`<span b-text="title"></span>`
|
|
108
|
+
|
|
109
|
+
`@event`
|
|
110
|
+
|
|
111
|
+
Event
|
|
112
|
+
|
|
113
|
+
Standard DOM event listeners.
|
|
114
|
+
|
|
115
|
+
`<button @click="run()">`
|
|
116
|
+
|
|
117
|
+
## ๐ Advanced Example: Todo List
|
|
118
|
+
|
|
119
|
+
Demonstrating `b-for`, event handling, and two-way binding in a single block.
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
<template b-id="todo-app">
|
|
123
|
+
<style>
|
|
124
|
+
.done { text-decoration: line-through; opacity: 0.6; }
|
|
125
|
+
ul { list-style: none; padding: 0; }
|
|
126
|
+
</style>
|
|
127
|
+
|
|
128
|
+
<h3>Tasks ({{ tasks.filter(t => !t.done).length }} left)</h3>
|
|
129
|
+
|
|
130
|
+
<input b-sync="newTask" placeholder="Add task...">
|
|
131
|
+
<button @click="tasks.push({text: newTask, done: false}); newTask=''">Add</button>
|
|
132
|
+
|
|
133
|
+
<ul>
|
|
134
|
+
<li b-for="task in tasks">
|
|
135
|
+
<input type="checkbox" b-sync="task.done">
|
|
136
|
+
<span class="{{ task.done ? 'done' : '' }}">{{ task.text }}</span>
|
|
137
|
+
</li>
|
|
138
|
+
</ul>
|
|
139
|
+
</template>
|
|
140
|
+
|
|
141
|
+
<script>
|
|
142
|
+
export default {
|
|
143
|
+
tasks: [{ text: 'Native Components', done: true }, { text: 'Profit', done: false }],
|
|
144
|
+
newTask: ''
|
|
145
|
+
}
|
|
146
|
+
</script>
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## ๐ Tooling & Ecosystem
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# ๐ฆ Lego Single File Components (.lego)
|
|
154
|
+
|
|
155
|
+
Single File Components (SFCs) are the professional standard for building with Lego JS. They allow you to co-locate your markup, scoped CSS, and reactive logic in a single `.lego` file, providing a clean separation of concerns without the mental overhead of switching between multiple files.
|
|
156
|
+
|
|
157
|
+
## ๐ Anatomy of a .lego File
|
|
158
|
+
|
|
159
|
+
A `.lego` file is composed of three top-level blocks: `<template>`, `<style>`, and `<script>`.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
<!-- user-profile.lego -->
|
|
163
|
+
<template>
|
|
164
|
+
<div class="profile-card">
|
|
165
|
+
<img src="{{ avatar }}" alt="{{ name }}">
|
|
166
|
+
<h2>{{ name }}</h2>
|
|
167
|
+
<p>{{ bio }}</p>
|
|
168
|
+
<button @click="poke">Poke {{ name }}</button>
|
|
169
|
+
</div>
|
|
170
|
+
</template>
|
|
171
|
+
|
|
172
|
+
<style>
|
|
173
|
+
self {
|
|
174
|
+
display: block;
|
|
175
|
+
border: 1px solid #ddd;
|
|
176
|
+
border-radius: 8px;
|
|
177
|
+
padding: 1rem;
|
|
178
|
+
text-align: center;
|
|
179
|
+
}
|
|
180
|
+
img {
|
|
181
|
+
width: 80px;
|
|
182
|
+
height: 80px;
|
|
183
|
+
border-radius: 50%;
|
|
184
|
+
}
|
|
185
|
+
h2 { color: #333; }
|
|
186
|
+
</style>
|
|
187
|
+
|
|
188
|
+
<script>
|
|
189
|
+
export default {
|
|
190
|
+
// Initial data state
|
|
191
|
+
avatar: 'default.png',
|
|
192
|
+
name: 'Anonymous',
|
|
193
|
+
bio: 'No bio provided.',
|
|
194
|
+
|
|
195
|
+
// Logic methods
|
|
196
|
+
poke() {
|
|
197
|
+
console.log(`${this.name} was poked!`);
|
|
198
|
+
this.$emit('poked', { name: this.name });
|
|
199
|
+
},
|
|
200
|
+
|
|
201
|
+
// Lifecycle hooks
|
|
202
|
+
mounted() {
|
|
203
|
+
console.log('Profile component is now in the DOM');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
</script>
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## ๐จ Scoped Styling
|
|
211
|
+
|
|
212
|
+
Styles defined inside a `.lego` file are automatically scoped to that component using the **Shadow DOM**.
|
|
213
|
+
|
|
214
|
+
- **The `self` selector**: Use `self` to target the host element of the component itself (the custom tag). In the final build, this is converted to the `:host` CSS selector.
|
|
215
|
+
|
|
216
|
+
- **No Leakage**: Styles defined here will not leak out to the parent page, and global styles (except CSS variables) will not leak into the component.
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
## โ๏ธ Component Logic (`export default`)
|
|
220
|
+
|
|
221
|
+
The `<script>` block must `export default` a plain JavaScript object. This object defines the component's state and behavior.
|
|
222
|
+
|
|
223
|
+
### 1. Reactive Data
|
|
224
|
+
|
|
225
|
+
Any property defined in the exported object becomes part of the reactive `data` proxy. When you change `this.username = 'NewName'`, the template updates automatically.
|
|
226
|
+
|
|
227
|
+
### 2. Lifecycle Hooks
|
|
228
|
+
|
|
229
|
+
Lego JS provides specific hooks to manage the component's existence:
|
|
230
|
+
|
|
231
|
+
Hook
|
|
232
|
+
|
|
233
|
+
Description
|
|
234
|
+
|
|
235
|
+
`mounted()`
|
|
236
|
+
|
|
237
|
+
Called after the component is attached to the DOM and its shadow root is initialized.
|
|
238
|
+
|
|
239
|
+
`updated()`
|
|
240
|
+
|
|
241
|
+
Called after the state changes and the DOM has been patched via the batcher.
|
|
242
|
+
|
|
243
|
+
`unmounted()`
|
|
244
|
+
|
|
245
|
+
Called just before the component is removed from the DOM. Use for cleanup (e.g., clearing timers).
|
|
246
|
+
|
|
247
|
+
## โจ Magic Helpers ($)
|
|
248
|
+
|
|
249
|
+
Lego JS provides several "magic" variables available directly in your templates and event handlers to speed up development.
|
|
250
|
+
|
|
251
|
+
### `$element`
|
|
252
|
+
|
|
253
|
+
Refers to the host custom element itself (the root of the component).
|
|
254
|
+
|
|
255
|
+
### `$refs`
|
|
256
|
+
|
|
257
|
+
Provides quick access to DOM elements within the component's Shadow DOM that have a `ref` attribute.
|
|
258
|
+
|
|
259
|
+
### `$emit(eventName, detail)`
|
|
260
|
+
|
|
261
|
+
A shorthand for dispatching custom events. By default, these events have `bubbles: true` and `composed: true`, allowing them to pass through multiple levels of Shadow DOM.
|
|
262
|
+
|
|
263
|
+
### `$ancestors(id)`
|
|
264
|
+
|
|
265
|
+
Searches up the DOM tree for the nearest component matching the provided tag name or `b-id`.
|
|
266
|
+
|
|
267
|
+
### `$event` and `$self`
|
|
268
|
+
|
|
269
|
+
- `$event`: The native DOM event object.
|
|
270
|
+
|
|
271
|
+
- `$self`: The specific element that triggered the event (alias for `event.target`).
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
## ๐ก The "One Way" Pattern (Data Flow)
|
|
275
|
+
|
|
276
|
+
While Lego JS allows deep tree access, the **only** recommended way to handle state updates in large apps is **Data Down, Events Up**. This prevents "mutant state" where you don't know which child changed a value.
|
|
277
|
+
|
|
278
|
+
### โ The "Bad" Way (Direct Mutation)
|
|
279
|
+
|
|
280
|
+
Avoid having children directly change an ancestor's data. It makes debugging impossible.
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
<!-- child.lego: DON'T DO THIS -->
|
|
284
|
+
<button @click="$ancestors('app-shell').user.age++">Update Age</button>
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### โ
The "Lego" Way (Generic Update Pattern)
|
|
289
|
+
|
|
290
|
+
If you have many fields, you don't need unique event handlers for each. Use a single generic update event.
|
|
291
|
+
|
|
292
|
+
1. **Child** sends the field name and the new value:
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
<!-- settings-child.lego -->
|
|
296
|
+
<input type="text"
|
|
297
|
+
value="{{ $ancestors('app-shell').user.name }}"
|
|
298
|
+
@input="$emit('update-field', { key: 'name', value: $self.value })">
|
|
299
|
+
|
|
300
|
+
<input type="number"
|
|
301
|
+
value="{{ $ancestors('app-shell').user.age }}"
|
|
302
|
+
@input="$emit('update-field', { key: 'age', value: $self.value })">
|
|
303
|
+
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
2. **Ancestor** handles all updates in one function:
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
<!-- grand-parent.lego -->
|
|
310
|
+
<template>
|
|
311
|
+
<div @update-field="handleFieldUpdate">
|
|
312
|
+
<settings-child></settings-child>
|
|
313
|
+
</div>
|
|
314
|
+
</template>
|
|
315
|
+
|
|
316
|
+
<script>
|
|
317
|
+
export default {
|
|
318
|
+
user: { name: 'John', age: 30 },
|
|
319
|
+
handleFieldUpdate(event) {
|
|
320
|
+
const { key, value } = event.detail;
|
|
321
|
+
// One place to validate everything
|
|
322
|
+
if (this.user.hasOwnProperty(key)) {
|
|
323
|
+
this.user[key] = value;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
</script>
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
## ๐ The Build Process (Vite)
|
|
333
|
+
|
|
334
|
+
To use `.lego` files, you must use the `Lego.vitePlugin()`. This plugin transforms your HTML-like file into a standard JavaScript module that registers the component with the `Lego.define` API.
|
|
335
|
+
|
|
336
|
+
### Configuration
|
|
337
|
+
|
|
338
|
+
In your `vite.config.js`:
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
import { defineConfig } from 'vite';
|
|
342
|
+
import { Lego } from './path/to/lego.js';
|
|
343
|
+
|
|
344
|
+
export default defineConfig({
|
|
345
|
+
plugins: [Lego.vitePlugin()]
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## ๐ก Best Practices
|
|
351
|
+
|
|
352
|
+
1. **Naming**: Use multi-word names for components to avoid collisions.
|
|
353
|
+
|
|
354
|
+
2. **Read-Only Ancestors**: Use `$ancestors()` primarily for **reading** values.
|
|
355
|
+
|
|
356
|
+
3. **Intent-based Events**: For complex logic (e.g., `submit-order`), use a specific event. For simple data syncing, use a generic `update-field` event.
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
# ๐ฃ Lego JS Routing Guide
|
|
361
|
+
|
|
362
|
+
The Lego JS router is a lightweight client-side routing solution that leverages the browser's History API. It allows you to build Single Page Applications (SPAs) by mapping URL paths to specific Web Components (Blocks).
|
|
363
|
+
|
|
364
|
+
## ๐งฉ The Router Viewport
|
|
365
|
+
|
|
366
|
+
To use routing, you must place the `<lego-router>` element in your HTML. This acts as the container where the matched component will be rendered.
|
|
367
|
+
|
|
368
|
+
```
|
|
369
|
+
<body>
|
|
370
|
+
<nav>
|
|
371
|
+
<a href="/" b-link>Home</a>
|
|
372
|
+
<a href="/profile/123" b-link>Profile</a>
|
|
373
|
+
</nav>
|
|
374
|
+
|
|
375
|
+
<!-- Routed components appear here -->
|
|
376
|
+
<lego-router></lego-router>
|
|
377
|
+
</body>
|
|
378
|
+
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## ๐ Basic Route Definition
|
|
382
|
+
|
|
383
|
+
Routes are defined using `Lego.route(path, componentName)`.
|
|
384
|
+
|
|
385
|
+
```
|
|
386
|
+
// Map the root path to 'home-page' block
|
|
387
|
+
Lego.route('/', 'home-page');
|
|
388
|
+
|
|
389
|
+
// Map /about to 'about-page' block
|
|
390
|
+
Lego.route('/about', 'about-page');
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## ๅจๆ Dynamic Route Parameters
|
|
395
|
+
|
|
396
|
+
You can define dynamic segments in your paths using the `:` prefix. These parameters are automatically parsed and injected into `Lego.globals.params`.
|
|
397
|
+
|
|
398
|
+
### Definition
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
Lego.route('/user/:id', 'user-profile');
|
|
402
|
+
Lego.route('/post/:category/:slug', 'blog-post');
|
|
403
|
+
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Usage inside a Component
|
|
407
|
+
|
|
408
|
+
Any component can access these parameters via the `global` object.
|
|
409
|
+
|
|
410
|
+
```
|
|
411
|
+
<template b-id="user-profile">
|
|
412
|
+
<div>
|
|
413
|
+
<h2>User Profile</h2>
|
|
414
|
+
<p>Viewing ID: {{ global.params.id }}</p>
|
|
415
|
+
</div>
|
|
416
|
+
</template>
|
|
417
|
+
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
## ๐ก Navigation Middleware (Authentication)
|
|
421
|
+
|
|
422
|
+
Middleware allows you to guard routes. The middleware function is executed before the component is rendered. If it returns `false`, the navigation is cancelled.
|
|
423
|
+
|
|
424
|
+
### Example: Auth Guard
|
|
425
|
+
|
|
426
|
+
```
|
|
427
|
+
Lego.route('/admin', 'admin-dashboard', async (params, globals) => {
|
|
428
|
+
const isAuthorized = globals.user && globals.user.role === 'admin';
|
|
429
|
+
|
|
430
|
+
if (!isAuthorized) {
|
|
431
|
+
// Redirect to login or home
|
|
432
|
+
history.pushState({}, '', '/login');
|
|
433
|
+
// We must manually trigger the router check after pushState
|
|
434
|
+
Lego.init();
|
|
435
|
+
return false; // Prevent 'admin-dashboard' from loading
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return true; // Proceed to load the component
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
## ๐ Internal Navigation (`b-link`)
|
|
444
|
+
|
|
445
|
+
To navigate without a full page refresh, use the `b-link` directive on anchor tags. This intercepts the click, updates the URL via `pushState`, and tells the Lego router to swap the view.
|
|
446
|
+
|
|
447
|
+
```
|
|
448
|
+
<!-- This will trigger the router logic -->
|
|
449
|
+
<a href="/dashboard" b-link>Go to Dashboard</a>
|
|
450
|
+
|
|
451
|
+
<!-- This will trigger a standard browser reload -->
|
|
452
|
+
<a href="/external-site.com">External Link</a>
|
|
453
|
+
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## ๐ Programmatic Navigation
|
|
457
|
+
|
|
458
|
+
Sometimes you need to navigate via JavaScript (e.g., after a successful form submission). Use the standard `history.pushState` but remember that the library listens for the `popstate` event. To trigger a render manually, you can call the internal route matcher or simply use a helper:
|
|
459
|
+
|
|
460
|
+
```
|
|
461
|
+
// In your component logic
|
|
462
|
+
submitForm() {
|
|
463
|
+
// Save data...
|
|
464
|
+
history.pushState({}, '', '/success');
|
|
465
|
+
// Dispatch popstate so the router hears it
|
|
466
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
## ๐ Large Scale Structure
|
|
472
|
+
|
|
473
|
+
For larger projects, define your routes in a dedicated initialization file and ensure your page components are registered before the router starts.
|
|
474
|
+
|
|
475
|
+
```
|
|
476
|
+
// router-config.js
|
|
477
|
+
import './views/home.lego';
|
|
478
|
+
import './views/login.lego';
|
|
479
|
+
import './views/profile.lego';
|
|
480
|
+
|
|
481
|
+
export const setupRouter = () => {
|
|
482
|
+
Lego.route('/', 'home-view');
|
|
483
|
+
Lego.route('/login', 'login-view');
|
|
484
|
+
|
|
485
|
+
// Nested logic for clean organization
|
|
486
|
+
Lego.route('/profile/:username', 'profile-view', (params) => {
|
|
487
|
+
return !!params.username; // Basic validation
|
|
488
|
+
});
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## ๐ Router State Summary
|
|
494
|
+
|
|
495
|
+
Feature
|
|
496
|
+
|
|
497
|
+
Syntax
|
|
498
|
+
|
|
499
|
+
Description
|
|
500
|
+
|
|
501
|
+
**Viewport**
|
|
502
|
+
|
|
503
|
+
`<lego-router>`
|
|
504
|
+
|
|
505
|
+
Where the content renders.
|
|
506
|
+
|
|
507
|
+
**Directive**
|
|
508
|
+
|
|
509
|
+
`b-link`
|
|
510
|
+
|
|
511
|
+
Intercepts link clicks.
|
|
512
|
+
|
|
513
|
+
**Globals**
|
|
514
|
+
|
|
515
|
+
`global.params`
|
|
516
|
+
|
|
517
|
+
Object containing URL variables.
|
|
518
|
+
|
|
519
|
+
**Middleware**
|
|
520
|
+
|
|
521
|
+
`(params, globals) => boolean`
|
|
522
|
+
|
|
523
|
+
Logic to permit/block access.
|
package/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
async function init() {
|
|
9
|
+
const targetDir = process.argv[2] || 'my-lego-app';
|
|
10
|
+
const templateDir = path.resolve(__dirname, 'template');
|
|
11
|
+
|
|
12
|
+
console.log(`Building your Lego app in ${targetDir}...`);
|
|
13
|
+
|
|
14
|
+
await fs.copy(templateDir, targetDir);
|
|
15
|
+
|
|
16
|
+
// Customizing package.json name
|
|
17
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
18
|
+
const pkg = await fs.readJson(pkgPath);
|
|
19
|
+
pkg.name = targetDir;
|
|
20
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
21
|
+
|
|
22
|
+
console.log('\nDone! Now run:\n');
|
|
23
|
+
console.log(` cd ${targetDir}\n npm install\n npm run dev`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
init();
|