lego-dom 0.0.8 → 1.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.
- package/CHANGELOG.md +44 -0
- package/README.md +49 -432
- package/cdn.html +124 -0
- package/docs/.vitepress/config.js +43 -5
- package/docs/api/directives.md +3 -3
- package/docs/api/globals.md +1 -1
- package/docs/api/index.md +3 -3
- package/docs/api/vite-plugin.md +1 -1
- package/docs/contributing/01-welcome.md +36 -0
- package/docs/contributing/02-registry.md +99 -0
- package/docs/contributing/03-batcher.md +110 -0
- package/docs/contributing/04-reactivity.md +87 -0
- package/docs/contributing/05-caching.md +59 -0
- package/docs/contributing/06-init.md +125 -0
- package/docs/contributing/07-observer.md +69 -0
- package/docs/contributing/08-snap.md +126 -0
- package/docs/contributing/09-diffing.md +69 -0
- package/docs/contributing/10-studs.md +76 -0
- package/docs/contributing/11-scanner.md +104 -0
- package/docs/contributing/12-render.md +116 -0
- package/docs/contributing/13-directives.md +225 -0
- package/docs/contributing/14-events.md +57 -0
- package/docs/contributing/15-router.md +9 -0
- package/docs/contributing/16-state.md +48 -0
- package/docs/contributing/17-legodom.md +55 -0
- package/docs/contributing/index.md +5 -0
- package/docs/examples/form.md +2 -2
- package/docs/examples/index.md +4 -4
- package/docs/examples/routing.md +8 -8
- package/docs/examples/sfc-showcase.md +4 -4
- package/docs/examples/todo-app.md +3 -3
- package/docs/guide/cdn-usage.md +16 -8
- package/docs/guide/components.md +34 -16
- package/docs/guide/contributing.md +2 -2
- package/docs/guide/directives.md +23 -23
- package/docs/guide/getting-started.md +41 -16
- package/docs/guide/index.md +12 -12
- package/docs/guide/lifecycle.md +1 -1
- package/docs/guide/quick-start.md +8 -5
- package/docs/guide/reactivity.md +30 -9
- package/docs/guide/routing.md +189 -289
- package/docs/guide/sfc.md +40 -40
- package/docs/guide/templating.md +4 -4
- package/docs/index.md +48 -14
- package/docs/public/logo.svg +17 -38
- package/docs/router/basic-routing.md +103 -0
- package/docs/router/cold-entry.md +91 -0
- package/docs/router/history.md +69 -0
- package/docs/router/index.md +73 -0
- package/docs/router/resolver.md +74 -0
- package/docs/router/surgical-swaps.md +134 -0
- package/examples/vite-app/README.md +2 -2
- package/examples/vite-app/index.html +9 -13
- package/examples/vite-app/package.json +4 -2
- package/examples/vite-app/src/app.css +3 -0
- package/examples/vite-app/src/app.js +29 -0
- package/examples/vite-app/src/components/app-navbar.lego +34 -0
- package/examples/vite-app/src/components/customers/customer-details.lego +24 -0
- package/examples/vite-app/src/components/customers/customer-orders.lego +21 -0
- package/examples/vite-app/src/components/customers/order-list.lego +55 -0
- package/examples/vite-app/src/components/greeting-card.lego +26 -26
- package/examples/vite-app/src/components/sample-component.lego +58 -58
- package/examples/vite-app/src/components/shells/customers-shell.lego +21 -0
- package/examples/vite-app/src/components/todo-list.lego +239 -0
- package/examples/vite-app/src/components/widgets/user-card.lego +27 -0
- package/examples/vite-app/vite.config.js +7 -2
- package/lego.js +2 -0
- package/main.js +280 -83
- package/package.json +8 -3
- package/parse-lego.js +17 -8
- package/parse-lego.test.js +1 -1
- package/{main.test.js → tests/main.test.js} +34 -17
- package/tests/parse-lego.test.js +65 -0
- package/vite-plugin.js +62 -24
- package/docs/.vitepress/dist/404.html +0 -22
- package/docs/.vitepress/dist/api/define.html +0 -35
- package/docs/.vitepress/dist/api/directives.html +0 -32
- package/docs/.vitepress/dist/api/globals.html +0 -27
- package/docs/.vitepress/dist/api/index.html +0 -25
- package/docs/.vitepress/dist/api/lifecycle.html +0 -38
- package/docs/.vitepress/dist/api/route.html +0 -34
- package/docs/.vitepress/dist/api/vite-plugin.html +0 -37
- package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.js +0 -11
- package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.lean.js +0 -1
- package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.js +0 -8
- package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.lean.js +0 -1
- package/docs/.vitepress/dist/assets/api_globals.md.DOjt7AV0.js +0 -3
- package/docs/.vitepress/dist/assets/api_globals.md.DOjt7AV0.lean.js +0 -1
- package/docs/.vitepress/dist/assets/api_index.md.OS6h01ct.js +0 -1
- package/docs/.vitepress/dist/assets/api_index.md.OS6h01ct.lean.js +0 -1
- package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.js +0 -14
- package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.lean.js +0 -1
- package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.js +0 -10
- package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.lean.js +0 -1
- package/docs/.vitepress/dist/assets/api_vite-plugin.md.DNn9VhL5.js +0 -13
- package/docs/.vitepress/dist/assets/api_vite-plugin.md.DNn9VhL5.lean.js +0 -1
- package/docs/.vitepress/dist/assets/app.BG5s3B0P.js +0 -1
- package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.DQmuWC2Z.js +0 -1
- package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.BO-PSxt1.js +0 -9
- package/docs/.vitepress/dist/assets/chunks/framework.B7OFBR9X.js +0 -19
- package/docs/.vitepress/dist/assets/chunks/theme.DA-iSa9B.js +0 -2
- package/docs/.vitepress/dist/assets/examples_form.md.B3stGKbu.js +0 -34
- package/docs/.vitepress/dist/assets/examples_form.md.B3stGKbu.lean.js +0 -1
- package/docs/.vitepress/dist/assets/examples_index.md.BDEG_D4J.js +0 -30
- package/docs/.vitepress/dist/assets/examples_index.md.BDEG_D4J.lean.js +0 -1
- package/docs/.vitepress/dist/assets/examples_routing.md.bqZ9DjDK.js +0 -338
- package/docs/.vitepress/dist/assets/examples_routing.md.bqZ9DjDK.lean.js +0 -1
- package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DLXaUiop.js +0 -13
- package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DLXaUiop.lean.js +0 -1
- package/docs/.vitepress/dist/assets/examples_todo-app.md.D5RhZoo5.js +0 -297
- package/docs/.vitepress/dist/assets/examples_todo-app.md.D5RhZoo5.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CAjf03Lr.js +0 -182
- package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CAjf03Lr.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_components.md.BIFWF1Hc.js +0 -174
- package/docs/.vitepress/dist/assets/guide_components.md.BIFWF1Hc.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_contributing.md.BgbUN-Mr.js +0 -1
- package/docs/.vitepress/dist/assets/guide_contributing.md.BgbUN-Mr.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_directives.md.Bi3ynu1d.js +0 -140
- package/docs/.vitepress/dist/assets/guide_directives.md.Bi3ynu1d.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_getting-started.md.2Nr1lp2z.js +0 -107
- package/docs/.vitepress/dist/assets/guide_getting-started.md.2Nr1lp2z.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_index.md.GvZq_Yf2.js +0 -2
- package/docs/.vitepress/dist/assets/guide_index.md.GvZq_Yf2.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_lifecycle.md.B28j1OzS.js +0 -304
- package/docs/.vitepress/dist/assets/guide_lifecycle.md.B28j1OzS.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_quick-start.md.CNk3VGTF.js +0 -33
- package/docs/.vitepress/dist/assets/guide_quick-start.md.CNk3VGTF.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_reactivity.md.CVsaMaPv.js +0 -135
- package/docs/.vitepress/dist/assets/guide_reactivity.md.CVsaMaPv.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_routing.md.DSpDP25o.js +0 -193
- package/docs/.vitepress/dist/assets/guide_routing.md.DSpDP25o.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_sfc.md.CVUP66tS.js +0 -187
- package/docs/.vitepress/dist/assets/guide_sfc.md.CVUP66tS.lean.js +0 -1
- package/docs/.vitepress/dist/assets/guide_templating.md.BgCGe4aa.js +0 -119
- package/docs/.vitepress/dist/assets/guide_templating.md.BgCGe4aa.lean.js +0 -1
- package/docs/.vitepress/dist/assets/index.md.xV1taCED.js +0 -23
- package/docs/.vitepress/dist/assets/index.md.xV1taCED.lean.js +0 -1
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/docs/.vitepress/dist/assets/style.eycE2Jhw.css +0 -1
- package/docs/.vitepress/dist/examples/form.html +0 -58
- package/docs/.vitepress/dist/examples/index.html +0 -368
- package/docs/.vitepress/dist/examples/routing.html +0 -362
- package/docs/.vitepress/dist/examples/sfc-showcase.html +0 -37
- package/docs/.vitepress/dist/examples/todo-app.html +0 -321
- package/docs/.vitepress/dist/guide/cdn-usage.html +0 -206
- package/docs/.vitepress/dist/guide/components.html +0 -198
- package/docs/.vitepress/dist/guide/contributing.html +0 -25
- package/docs/.vitepress/dist/guide/directives.html +0 -164
- package/docs/.vitepress/dist/guide/getting-started.html +0 -131
- package/docs/.vitepress/dist/guide/index.html +0 -26
- package/docs/.vitepress/dist/guide/lifecycle.html +0 -328
- package/docs/.vitepress/dist/guide/quick-start.html +0 -57
- package/docs/.vitepress/dist/guide/reactivity.html +0 -159
- package/docs/.vitepress/dist/guide/routing.html +0 -217
- package/docs/.vitepress/dist/guide/sfc.html +0 -211
- package/docs/.vitepress/dist/guide/templating.html +0 -143
- package/docs/.vitepress/dist/hashmap.json +0 -1
- package/docs/.vitepress/dist/index.html +0 -47
- package/docs/.vitepress/dist/logo.svg +0 -38
- package/docs/.vitepress/dist/vp-icons.css +0 -1
- package/examples/vite-app/src/main.js +0 -11
- package/examples.js +0 -99
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Surgical Swaps: Mastering b-target
|
|
2
|
+
|
|
3
|
+
The true power of LegoJS lies in its ability to perform **Surgical Swaps**. In a traditional application, clicking a link often causes the entire page to re-render, destroying the state of your sidebar, header, or scroll position.
|
|
4
|
+
|
|
5
|
+
With `b-target` (and optionally `b-link`), we can choose to update only a specific "fragment" of the page.
|
|
6
|
+
|
|
7
|
+
## The Problem with "Nuclear" Navigation
|
|
8
|
+
|
|
9
|
+
Imagine a messaging app (like LinkedIn or Slack). You have a sidebar full of conversations. When you click a message, you want the chat window to update, but you **don't** want the sidebar to reload.
|
|
10
|
+
|
|
11
|
+
If the sidebar reloads:
|
|
12
|
+
|
|
13
|
+
1. The scroll position is lost.
|
|
14
|
+
|
|
15
|
+
2. Any search text in the sidebar is cleared.
|
|
16
|
+
|
|
17
|
+
3. The UI "flickers," making the app feel slow.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## The Solution: `b-target`
|
|
21
|
+
|
|
22
|
+
The `b-target` directive allows a link to specify exactly where the new component should be rendered. It implies `b-link` (history update) by default.
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Example: messaging-shell.html
|
|
26
|
+
|
|
27
|
+
In this SFC, we define a layout with a sidebar and a main content area. Clicking a contact updates _only_ the `<main>` area.
|
|
28
|
+
|
|
29
|
+
```html
|
|
30
|
+
<!-- messaging-shell.html -->
|
|
31
|
+
<template>
|
|
32
|
+
<div class="messaging-layout">
|
|
33
|
+
<aside class="sidebar">
|
|
34
|
+
<h2>Contacts</h2>
|
|
35
|
+
<nav>
|
|
36
|
+
<a href="/chat/alice" b-target="#chat-window">Alice</a>
|
|
37
|
+
<a href="/chat/bob" b-target="#chat-window">Bob</a>
|
|
38
|
+
</nav>
|
|
39
|
+
</aside>
|
|
40
|
+
|
|
41
|
+
<main id="chat-window">
|
|
42
|
+
<p>Select a contact to start chatting.</p>
|
|
43
|
+
</main>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<script>
|
|
48
|
+
export default {
|
|
49
|
+
mounted() {
|
|
50
|
+
console.log("Messaging shell ready.");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<style>
|
|
56
|
+
.messaging-layout {
|
|
57
|
+
display: flex;
|
|
58
|
+
height: 100vh;
|
|
59
|
+
}
|
|
60
|
+
.sidebar {
|
|
61
|
+
width: 300px;
|
|
62
|
+
border-right: 1px solid #ccc;
|
|
63
|
+
}
|
|
64
|
+
#chat-window {
|
|
65
|
+
flex: 1;
|
|
66
|
+
padding: 20px;
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 1. Targeting by ID
|
|
73
|
+
|
|
74
|
+
You can tell Lego to find a specific element by its ID and replace its contents.
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<!-- messaging-shell.html -->
|
|
78
|
+
<template>
|
|
79
|
+
<div class="layout">
|
|
80
|
+
<aside class="sidebar">
|
|
81
|
+
<div b-for="chat in threads">
|
|
82
|
+
<!-- Parent component (this shell) binds data to these links -->
|
|
83
|
+
<a href="/messaging/{{chat.id}}" b-target="#chat-window">
|
|
84
|
+
{{chat.userName}}
|
|
85
|
+
</a>
|
|
86
|
+
</div>
|
|
87
|
+
</aside>
|
|
88
|
+
|
|
89
|
+
<main id="chat-window">
|
|
90
|
+
<!-- Only this area will change when a link is clicked -->
|
|
91
|
+
<p>Select a conversation to begin.</p>
|
|
92
|
+
</main>
|
|
93
|
+
</div>
|
|
94
|
+
</template>
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 2. Targeting by Component Tag (The Web Component Way)
|
|
99
|
+
|
|
100
|
+
Because Lego is built on Custom Elements, you can target a component tag directly. The framework will find that tag and swap its internal content.
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<a href="/profile/settings" b-target="settings-view">Edit Settings</a>
|
|
104
|
+
|
|
105
|
+
<settings-view>
|
|
106
|
+
<!-- Content gets swapped here -->
|
|
107
|
+
</settings-view>
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## How the Target Resolver Works
|
|
112
|
+
|
|
113
|
+
When you click a link with a `b-target`, the LegoJS **Target Resolver** follows a specific hierarchy:
|
|
114
|
+
|
|
115
|
+
1. **Local Scope**: It looks for the target inside the current component first. This prevents "ID collisions" if you have multiple instances of a layout.
|
|
116
|
+
|
|
117
|
+
2. **Component Match**: If the target doesn't start with `#`, it treats it as a tag name (e.g., `thread-view`).
|
|
118
|
+
|
|
119
|
+
3. **Global Fallback**: If it can't find a local match, it searches the entire document.
|
|
120
|
+
|
|
121
|
+
4. **Router Fallback**: If no target is found, it defaults back to the `<lego-router>`.
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Smart History
|
|
125
|
+
|
|
126
|
+
Even though we are only swapping a small part of the DOM, LegoJS is smart enough to update the browser's address bar.
|
|
127
|
+
|
|
128
|
+
When a surgical swap happens, Lego saves the "target" information into the browser's history state (`history.state.legoTargets`). This means that when a user hits the **Back Button**, Lego knows exactly which fragment needs to be swapped back to its previous state.
|
|
129
|
+
|
|
130
|
+
## Summary
|
|
131
|
+
|
|
132
|
+
`b-target` turns your web app into a high-performance workspace. By keeping the "Shell" alive and only swapping "Fragments," you maintain state, eliminate flickers, and provide a desktop-like experience.
|
|
133
|
+
|
|
134
|
+
Next, we will tackle the most common question: **"What happens if I refresh the page while looking at a surgical fragment?"** We'll explore the **Cold Start: Self-Healing Layouts**.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Lego SFC and Vite Plugin Example
|
|
2
2
|
|
|
3
|
-
This example demonstrates how to use
|
|
3
|
+
This example demonstrates how to use Lego with Single File Components (.lego files) and the Vite plugin.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
|
+
|
|
3
4
|
<head>
|
|
4
5
|
<meta charset="UTF-8">
|
|
5
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
7
|
+
<title>Lego Vite Example</title>
|
|
7
8
|
<style>
|
|
8
9
|
body {
|
|
9
10
|
font-family: system-ui, -apple-system, sans-serif;
|
|
@@ -28,18 +29,13 @@
|
|
|
28
29
|
}
|
|
29
30
|
</style>
|
|
30
31
|
</head>
|
|
31
|
-
<body>
|
|
32
|
-
<h1>LegoJS + Vite Example</h1>
|
|
33
|
-
|
|
34
|
-
<div class="info">
|
|
35
|
-
<p><strong>✨ These components are auto-discovered from .lego files!</strong></p>
|
|
36
|
-
<p>The Vite plugin automatically finds all .lego files in <code>src/components/</code> and registers them.</p>
|
|
37
|
-
</div>
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
<
|
|
33
|
+
<body>
|
|
34
|
+
<app-navbar></app-navbar>
|
|
35
|
+
<lego-router id="app-outlet"></lego-router>
|
|
36
|
+
<aside id="outside-router"></aside>
|
|
42
37
|
|
|
43
|
-
<script type="module" src="/src/
|
|
38
|
+
<script type="module" src="/src/app.js"></script>
|
|
44
39
|
</body>
|
|
45
|
-
|
|
40
|
+
|
|
41
|
+
</html>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Import Tailwind CSS
|
|
2
|
+
import './app.css';
|
|
3
|
+
|
|
4
|
+
// Import Lego core
|
|
5
|
+
import { Lego } from 'lego-dom/main.js';
|
|
6
|
+
|
|
7
|
+
// Import virtual module that auto-discovers and registers all .lego components
|
|
8
|
+
import registerComponents from 'virtual:lego-components';
|
|
9
|
+
|
|
10
|
+
// Register all auto-discovered components
|
|
11
|
+
registerComponents();
|
|
12
|
+
|
|
13
|
+
// 10. Define SPA Routes
|
|
14
|
+
Lego.route('/', 'sample-component');
|
|
15
|
+
Lego.route('/todo', 'todo-list');
|
|
16
|
+
Lego.route('/card', 'user-card');
|
|
17
|
+
Lego.route('/customers/:id/orders', 'customer-orders');
|
|
18
|
+
Lego.route('/customers/:id/details', 'customer-details');
|
|
19
|
+
|
|
20
|
+
// 11. Optional: Add a middleware example
|
|
21
|
+
Lego.route('/admin', 'admin-panel', async (params, globals) => {
|
|
22
|
+
console.log('Checking permissions for', params);
|
|
23
|
+
return globals.isLoggedIn;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Initialize Lego
|
|
27
|
+
await Lego.init(document.body, {
|
|
28
|
+
tailwind: ['/src/app.css']
|
|
29
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
self {
|
|
3
|
+
display: block;
|
|
4
|
+
padding: 1rem;
|
|
5
|
+
background: #f9fafb;
|
|
6
|
+
border-bottom: 1px solid #e0e0e0;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
nav {
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
align-items: center;
|
|
13
|
+
}
|
|
14
|
+
</style>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<nav>
|
|
18
|
+
<ul>
|
|
19
|
+
<li><a href="/" b-target="#outside-router" b-link="true">Home</a></li>
|
|
20
|
+
<li><a href="/todo" b-target>Todo</a></li>
|
|
21
|
+
<li><a href="/card" b-target>Card</a></li>
|
|
22
|
+
<li><a href="/customers/1/orders">Customers</a></li>
|
|
23
|
+
</ul>
|
|
24
|
+
</nav>
|
|
25
|
+
</template>
|
|
26
|
+
|
|
27
|
+
<script>
|
|
28
|
+
export default {
|
|
29
|
+
name: 'AppNavbar',
|
|
30
|
+
mounted() {
|
|
31
|
+
console.log('This is mounted');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
</script>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<customers-shell>
|
|
3
|
+
<div style="padding: 1rem; border: 1px dashed #4f46e5;">
|
|
4
|
+
<h3>👤 Customer Profile</h3>
|
|
5
|
+
<p>Details for Customer ID: <strong>{{ global.$route.params.id }}</strong></p>
|
|
6
|
+
|
|
7
|
+
<div style="display: grid; gap: 0.5rem; margin-top: 1rem;">
|
|
8
|
+
<div><strong>Status:</strong> Premium Member</div>
|
|
9
|
+
<div><strong>Joined:</strong> January 2024</div>
|
|
10
|
+
<div><strong>Region:</strong> Europe</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<div style="margin-top: 1rem;">
|
|
14
|
+
<a href="/customers/{{ global.$route.params.id }}/orders" b-target="#todo-container">View Orders</a>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</customers-shell>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script>
|
|
21
|
+
export default {
|
|
22
|
+
name: 'CustomerDetails'
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<customers-shell>
|
|
3
|
+
<div style="padding: 1rem; border: 1px dashed #ccc;">
|
|
4
|
+
<h3>📦 Order History</h3>
|
|
5
|
+
<p>Viewing orders for Customer ID: <strong>{{ global.$route.params.id }}</strong></p>
|
|
6
|
+
|
|
7
|
+
<!-- Composition: Using another component inside -->
|
|
8
|
+
<order-list></order-list>
|
|
9
|
+
|
|
10
|
+
<div style="margin-top: 1rem;">
|
|
11
|
+
<a href="/customers/{{ global.$route.params.id }}/details" b-target="#todo-container">View Profile Info</a>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</customers-shell>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
export default {
|
|
19
|
+
name: 'CustomerOrders'
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
ul {
|
|
3
|
+
list-style: none;
|
|
4
|
+
padding: 0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
li {
|
|
8
|
+
padding: 0.5rem;
|
|
9
|
+
border: 1px solid #eee;
|
|
10
|
+
margin-bottom: 0.5rem;
|
|
11
|
+
border-radius: 4px;
|
|
12
|
+
display: flex;
|
|
13
|
+
justify-content: space-between;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.status {
|
|
17
|
+
font-weight: bold;
|
|
18
|
+
color: #059669;
|
|
19
|
+
}
|
|
20
|
+
</style>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<div>
|
|
24
|
+
<h4>Recent Orders</h4>
|
|
25
|
+
<p b-show="loading">Loading orders for customer...</p>
|
|
26
|
+
<ul b-show="!loading">
|
|
27
|
+
<li b-for="order in orders">
|
|
28
|
+
<span>Order #{{ order.id }}</span>
|
|
29
|
+
<span class="status">{{ order.status }}</span>
|
|
30
|
+
</li>
|
|
31
|
+
</ul>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script>
|
|
36
|
+
export default {
|
|
37
|
+
name: 'OrderList',
|
|
38
|
+
state: {
|
|
39
|
+
orders: [],
|
|
40
|
+
loading: true
|
|
41
|
+
},
|
|
42
|
+
async mounted() {
|
|
43
|
+
// Simulate API fetch using the customer ID from parent or global params
|
|
44
|
+
const customerId = Lego.globals.$route.params.id;
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
this.orders = [
|
|
47
|
+
{ id: '101', status: 'Delivered' },
|
|
48
|
+
{ id: '105', status: 'Shipped' },
|
|
49
|
+
{ id: '110', status: 'Processing' }
|
|
50
|
+
];
|
|
51
|
+
this.loading = false;
|
|
52
|
+
}, 800);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
</script>
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
1
|
+
<style>
|
|
2
|
+
self {
|
|
3
|
+
display: block;
|
|
4
|
+
padding: 1rem;
|
|
5
|
+
background: #f3f4f6;
|
|
6
|
+
border-radius: 0.5rem;
|
|
7
|
+
margin: 0.5rem 0;
|
|
8
|
+
}
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
input {
|
|
11
|
+
padding: 0.5rem;
|
|
12
|
+
border: 1px solid #d1d5db;
|
|
13
|
+
border-radius: 0.25rem;
|
|
14
|
+
margin-right: 0.5rem;
|
|
15
|
+
font-size: 1rem;
|
|
16
|
+
}
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
.greeting {
|
|
19
|
+
margin-top: 1rem;
|
|
20
|
+
padding: 1rem;
|
|
21
|
+
background: white;
|
|
22
|
+
border-radius: 0.25rem;
|
|
23
|
+
font-size: 1.25rem;
|
|
24
|
+
color: #1f2937;
|
|
25
|
+
}
|
|
26
|
+
</style>
|
|
28
27
|
|
|
28
|
+
<template>
|
|
29
29
|
<div>
|
|
30
30
|
<input b-sync="name" type="text" placeholder="Enter your name">
|
|
31
|
-
<div class="greeting" b-
|
|
31
|
+
<div class="greeting" b-show="name">
|
|
32
32
|
Hello, {{ name }}! 👋
|
|
33
33
|
</div>
|
|
34
34
|
</div>
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
1
|
+
<style>
|
|
2
|
+
self {
|
|
3
|
+
display: block;
|
|
4
|
+
padding: 1.5rem;
|
|
5
|
+
margin: 1rem 0;
|
|
6
|
+
border: 2px solid #4f46e5;
|
|
7
|
+
border-radius: 0.5rem;
|
|
8
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
9
|
+
color: white;
|
|
10
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
11
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
12
|
+
}
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
.header {
|
|
15
|
+
font-size: 1.5rem;
|
|
16
|
+
font-weight: bold;
|
|
17
|
+
margin-bottom: 0.5rem;
|
|
18
|
+
}
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
.content {
|
|
21
|
+
margin: 1rem 0;
|
|
22
|
+
line-height: 1.6;
|
|
23
|
+
}
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
button {
|
|
26
|
+
background: white;
|
|
27
|
+
color: #4f46e5;
|
|
28
|
+
border: none;
|
|
29
|
+
padding: 0.5rem 1rem;
|
|
30
|
+
border-radius: 0.25rem;
|
|
31
|
+
font-weight: 600;
|
|
32
|
+
cursor: pointer;
|
|
33
|
+
transition: transform 0.2s;
|
|
34
|
+
}
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
button:hover {
|
|
37
|
+
transform: scale(1.05);
|
|
38
|
+
}
|
|
40
39
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
40
|
+
.count {
|
|
41
|
+
display: inline-block;
|
|
42
|
+
background: rgba(255, 255, 255, 0.2);
|
|
43
|
+
padding: 0.25rem 0.75rem;
|
|
44
|
+
border-radius: 0.25rem;
|
|
45
|
+
margin-left: 0.5rem;
|
|
46
|
+
}
|
|
47
|
+
</style>
|
|
49
48
|
|
|
49
|
+
<template>
|
|
50
50
|
<div class="header">{{ title }}</div>
|
|
51
51
|
<div class="content">
|
|
52
|
-
<p>This is a sample
|
|
52
|
+
<p class="gobe">This is a sample Lego component loaded from a .lego file!</p>
|
|
53
53
|
<p>Message: {{ message }}</p>
|
|
54
54
|
</div>
|
|
55
55
|
<button @click="incrementCount()">
|
|
56
|
-
Click me!
|
|
56
|
+
Click me!
|
|
57
57
|
<span class="count">{{ count }}</span>
|
|
58
58
|
</button>
|
|
59
59
|
</template>
|
|
60
60
|
|
|
61
61
|
<script>
|
|
62
|
-
export default {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
export default {
|
|
63
|
+
title: 'Sample Component',
|
|
64
|
+
message: 'Hello from .lego file!',
|
|
65
|
+
count: 0,
|
|
66
|
+
|
|
67
|
+
incrementCount() {
|
|
68
|
+
this.count++;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
mounted() {
|
|
72
|
+
console.log('Sample component mounted!');
|
|
73
|
+
}
|
|
73
74
|
}
|
|
74
|
-
|
|
75
|
-
</script>
|
|
75
|
+
</script>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
self {
|
|
3
|
+
display: block;
|
|
4
|
+
padding: 1rem;
|
|
5
|
+
background: #f9fafb;
|
|
6
|
+
border-bottom: 1px solid #e0e0e0;
|
|
7
|
+
}
|
|
8
|
+
</style>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div>
|
|
12
|
+
<h2>Customers Shell</h2>
|
|
13
|
+
<slot></slot>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
export default {
|
|
19
|
+
name: 'CustomersShell'
|
|
20
|
+
}
|
|
21
|
+
</script>
|