tkeron 4.0.0-beta.8 → 4.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/{readme.md → README.md} +36 -4
- package/bun.lock +23 -21
- package/changelog.md +292 -8
- package/docs/best-practices.md +127 -101
- package/docs/cli-reference.md +58 -38
- package/docs/components-html.md +30 -24
- package/docs/components-typescript.md +110 -79
- package/docs/getting-started.md +24 -18
- package/docs/mcp-server.md +19 -36
- package/docs/overview.md +16 -10
- package/docs/pre-rendering.md +163 -157
- package/docs/testing.md +331 -0
- package/examples/basic_build/src/index.ts +5 -5
- package/examples/with_assets/src/index.ts +5 -5
- package/examples/with_com_html_priority/src/admin/admin-panel.com.html +1 -1
- package/examples/with_com_html_priority/src/admin/dashboard.html +16 -16
- package/examples/with_com_html_priority/src/admin/nested-stat.com.html +1 -1
- package/examples/with_com_html_priority/src/admin/site-header.com.html +1 -1
- package/examples/with_com_html_priority/src/blog/comment-item.com.html +1 -1
- package/examples/with_com_html_priority/src/blog/comment-section.com.html +1 -1
- package/examples/with_com_html_priority/src/blog/post.html +22 -19
- package/examples/with_com_html_priority/src/index.html +15 -15
- package/examples/with_com_html_priority/src/info-box.com.html +1 -1
- package/examples/with_com_html_priority/src/site-header.com.html +1 -1
- package/examples/with_com_mixed_priority/src/dashboard/main.html +17 -17
- package/examples/with_com_mixed_priority/src/dashboard/stats-widget.com.ts +1 -1
- package/examples/with_com_mixed_priority/src/footer-info.com.html +3 -1
- package/examples/with_com_mixed_priority/src/index.html +16 -16
- package/examples/with_com_mixed_priority/src/page-header.com.html +8 -1
- package/examples/with_com_mixed_priority/src/settings/config.html +16 -16
- package/examples/with_com_mixed_priority/src/settings/priority-test.com.html +3 -1
- package/examples/with_com_mixed_priority/src/users/profiles/activity-feed.com.ts +7 -3
- package/examples/with_com_mixed_priority/src/users/profiles/page-header.com.html +8 -1
- package/examples/with_com_mixed_priority/src/users/profiles/profile-actions.com.html +45 -4
- package/examples/with_com_mixed_priority/src/users/profiles/user-profile.com.ts +1 -1
- package/examples/with_com_mixed_priority/src/users/profiles/view.html +17 -17
- package/examples/with_com_ts/src/index.html +15 -11
- package/examples/with_com_ts_priority/src/analytics/chart-widget.com.ts +7 -5
- package/examples/with_com_ts_priority/src/analytics/report.html +16 -16
- package/examples/with_com_ts_priority/src/analytics/user-stats.com.ts +1 -1
- package/examples/with_com_ts_priority/src/data-table.com.ts +7 -4
- package/examples/with_com_ts_priority/src/index.html +15 -15
- package/examples/with_com_ts_priority/src/sales/regional/data-table.com.ts +8 -5
- package/examples/with_com_ts_priority/src/sales/regional/overview.html +16 -16
- package/examples/with_com_ts_priority/src/sales/regional/sales-summary.com.ts +7 -4
- package/examples/with_com_ts_priority/src/user-stats.com.ts +1 -1
- package/examples/with_component_iteration/src/card-list.com.ts +40 -12
- package/examples/with_component_iteration/src/engagement-meter.com.ts +11 -6
- package/examples/with_component_iteration/src/index.html +108 -51
- package/examples/with_component_iteration/src/index.ts +1 -1
- package/examples/with_component_iteration/src/note-box.com.html +12 -2
- package/examples/with_component_iteration/src/status-badge.com.ts +14 -7
- package/examples/with_component_iteration/src/user-card.com.ts +10 -9
- package/examples/with_pre/src/contact.pre.ts +3 -3
- package/examples/with_pre/src/index.ts +5 -5
- package/examples/with_pre/src/section/index.pre.ts +2 -4
- package/index.ts +31 -40
- package/mcp-server.ts +168 -445
- package/package.json +19 -8
- package/src/banner.ts +5 -4
- package/src/build.ts +29 -29
- package/src/buildDir.ts +36 -18
- package/src/buildEntrypoints.ts +17 -6
- package/src/buildWrapper.ts +21 -0
- package/src/cleanupOrphanedTempDirs.ts +31 -0
- package/src/createTestLogger.ts +24 -0
- package/src/develop.ts +47 -46
- package/src/getBuildResult.ts +146 -0
- package/src/index.ts +7 -0
- package/src/init.ts +39 -42
- package/src/initWrapper.ts +39 -26
- package/src/logger.ts +4 -11
- package/src/loggerObj.ts +13 -0
- package/src/processCom.ts +137 -110
- package/src/processComTs.ts +174 -153
- package/src/processPre.ts +24 -27
- package/src/promptUser.ts +15 -0
- package/src/setupSigintHandler.ts +6 -0
- package/src/silentLogger.ts +8 -0
- package/tests/test-helpers.ts +30 -0
- package/funciones.md +0 -63
package/docs/testing.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# Testing Tkeron Projects
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Tkeron provides a `getBuildResult()` function that lets you test your built projects programmatically. This is useful for verifying that your components, pre-rendering scripts, and build output work correctly.
|
|
6
|
+
|
|
7
|
+
**Important:** These tests validate YOUR project's build output — not tkeron internals. You're testing that your HTML, components, and scripts produce the expected result after the build.
|
|
8
|
+
|
|
9
|
+
## Setup
|
|
10
|
+
|
|
11
|
+
Install tkeron as a dependency in your project:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add -d tkeron
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## API
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { getBuildResult, type BuildResult } from "tkeron";
|
|
21
|
+
|
|
22
|
+
const result: BuildResult = await getBuildResult("./websrc");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### BuildResult
|
|
26
|
+
|
|
27
|
+
`getBuildResult()` returns a `Record<string, FileInfo>` indexed by relative path:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
type BuildResult = Record<string, FileInfo>;
|
|
31
|
+
|
|
32
|
+
interface FileInfo {
|
|
33
|
+
fileName: string; // "index.html"
|
|
34
|
+
filePath: string; // "styles" or "" for root files
|
|
35
|
+
path: string; // "styles/main.css" (the key)
|
|
36
|
+
type: string; // MIME type: "text/html", "text/css", etc.
|
|
37
|
+
size: number; // size in bytes
|
|
38
|
+
fileHash: string; // SHA-256 hash
|
|
39
|
+
getContentAsString?: () => string; // text files only
|
|
40
|
+
dom?: Document; // HTML files only - parsed DOM
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- `dom` is only present on `.html` files. It provides full DOM API: `querySelector()`, `getElementById()`, `querySelectorAll()`, etc.
|
|
45
|
+
- `getContentAsString()` is only present on text files (html, css, js, json, txt, svg, xml, ts, mjs, cjs, md, map).
|
|
46
|
+
- Binary files (images, fonts) only have metadata — no `dom` or `getContentAsString`.
|
|
47
|
+
|
|
48
|
+
## Test Structure
|
|
49
|
+
|
|
50
|
+
### Single Build with beforeAll
|
|
51
|
+
|
|
52
|
+
**Always** build once and share the result across tests. This is:
|
|
53
|
+
|
|
54
|
+
- Concurrent-safe (`bun test --concurrent`)
|
|
55
|
+
- Efficient (1 build instead of N builds)
|
|
56
|
+
- Reliable (no race conditions)
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { describe, it, expect, beforeAll } from "bun:test";
|
|
60
|
+
import { getBuildResult, type BuildResult } from "tkeron";
|
|
61
|
+
import { join } from "path";
|
|
62
|
+
|
|
63
|
+
describe("my project", () => {
|
|
64
|
+
const sourcePath = join(import.meta.dir, "src");
|
|
65
|
+
let result: BuildResult;
|
|
66
|
+
|
|
67
|
+
beforeAll(async () => {
|
|
68
|
+
result = await getBuildResult(sourcePath);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("should generate index.html", () => {
|
|
72
|
+
expect(result?.["index.html"]).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Never** call `getBuildResult()` inside each `it()` — this causes race conditions in concurrent mode.
|
|
78
|
+
|
|
79
|
+
## Testing Patterns
|
|
80
|
+
|
|
81
|
+
### 1. Verify File Existence
|
|
82
|
+
|
|
83
|
+
Check that expected output files exist:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
it("should generate expected files", () => {
|
|
87
|
+
expect(result?.["index.html"]).toBeDefined();
|
|
88
|
+
expect(result?.["index.js"]).toBeDefined();
|
|
89
|
+
expect(result?.["styles/main.css"]).toBeDefined();
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2. Verify Element Existence (Always Check First)
|
|
94
|
+
|
|
95
|
+
**Rule:** Always verify an element exists BEFORE checking its properties.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// ✅ CORRECT: check existence first, then properties
|
|
99
|
+
it("should have login button", () => {
|
|
100
|
+
const dom = result?.["index.html"]?.dom;
|
|
101
|
+
|
|
102
|
+
const button = dom?.querySelector("#login-button");
|
|
103
|
+
expect(button).toBeDefined();
|
|
104
|
+
expect(button!.textContent).toBe("Log In");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ❌ WRONG: accessing properties without checking existence
|
|
108
|
+
it("should have login button", () => {
|
|
109
|
+
const dom = result?.["index.html"]?.dom;
|
|
110
|
+
expect(dom!.querySelector("#login-button")!.textContent).toBe("Log In");
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 3. Verify Bounded Content
|
|
115
|
+
|
|
116
|
+
Test specific, short, predictable values — not full output strings.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// ✅ GOOD: specific, bounded values
|
|
120
|
+
it("should have correct title", () => {
|
|
121
|
+
const dom = result?.["index.html"]?.dom;
|
|
122
|
+
|
|
123
|
+
const title = dom?.querySelector("title");
|
|
124
|
+
expect(title).toBeDefined();
|
|
125
|
+
expect(title!.textContent).toBe("My App");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// ✅ GOOD: keyword presence in compiled JS
|
|
129
|
+
it("should contain event handling logic", () => {
|
|
130
|
+
const js = result?.["index.js"]?.getContentAsString!();
|
|
131
|
+
expect(js).toContain("addEventListener");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// ❌ BAD: comparing full minified JS output (fragile, breaks on any optimization change)
|
|
135
|
+
it("should match exact JS", () => {
|
|
136
|
+
const js = result?.["index.js"]?.getContentAsString!();
|
|
137
|
+
expect(js).toBe('var t=0,e=document.querySelector("button")...');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ❌ BAD: comparing full HTML output
|
|
141
|
+
it("should match exact HTML", () => {
|
|
142
|
+
const html = result?.["index.html"]?.getContentAsString!();
|
|
143
|
+
expect(html).toBe("<!doctype html><html>...");
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Why bounded:** Build output changes with optimizations, minification, and bundling. Test the **meaning**, not the **exact format**.
|
|
148
|
+
|
|
149
|
+
### 4. Verify DOM Elements (Specific Queries)
|
|
150
|
+
|
|
151
|
+
Test specific elements that matter to your project:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
it("should have navigation with correct links", () => {
|
|
155
|
+
const dom = result?.["index.html"]?.dom;
|
|
156
|
+
|
|
157
|
+
const homeLink = dom?.querySelector('nav a[href="/"]');
|
|
158
|
+
expect(homeLink).toBeDefined();
|
|
159
|
+
expect(homeLink!.textContent).toBe("Home");
|
|
160
|
+
|
|
161
|
+
const aboutLink = dom?.querySelector('nav a[href="/about"]');
|
|
162
|
+
expect(aboutLink).toBeDefined();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should have user profile section", () => {
|
|
166
|
+
const dom = result?.["index.html"]?.dom;
|
|
167
|
+
|
|
168
|
+
const profile = dom?.querySelector("#user-profile");
|
|
169
|
+
expect(profile).toBeDefined();
|
|
170
|
+
|
|
171
|
+
const avatar = profile?.querySelector("img.avatar");
|
|
172
|
+
expect(avatar).toBeDefined();
|
|
173
|
+
expect(avatar!.getAttribute("alt")).toBe("User avatar");
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 5. Verify Tkeron Transformations
|
|
178
|
+
|
|
179
|
+
Test that tkeron's build features work correctly in your project:
|
|
180
|
+
|
|
181
|
+
**Script injection (TypeScript → JavaScript):**
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
it("should have compiled script in head", () => {
|
|
185
|
+
const dom = result?.["index.html"]?.dom;
|
|
186
|
+
|
|
187
|
+
const script = dom?.querySelector('script[type="module"]');
|
|
188
|
+
expect(script).toBeDefined();
|
|
189
|
+
expect(script!.getAttribute("src")).toBe("./index.js");
|
|
190
|
+
expect(script!.parentElement!.tagName).toBe("HEAD");
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Component substitution (.com.html):**
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
it("should have processed nav component", () => {
|
|
198
|
+
const dom = result?.["index.html"]?.dom;
|
|
199
|
+
|
|
200
|
+
// The <nav-menu> tag should be replaced by its .com.html content
|
|
201
|
+
const nav = dom?.querySelector("nav");
|
|
202
|
+
expect(nav).toBeDefined();
|
|
203
|
+
|
|
204
|
+
const links = dom?.querySelectorAll("nav a");
|
|
205
|
+
expect(links).toBeDefined();
|
|
206
|
+
expect(links!.length).toBeGreaterThan(0);
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**TypeScript component (.com.ts):**
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
it("should have dynamically generated list", () => {
|
|
214
|
+
const dom = result?.["index.html"]?.dom;
|
|
215
|
+
|
|
216
|
+
const list = dom?.querySelector("#item-list");
|
|
217
|
+
expect(list).toBeDefined();
|
|
218
|
+
|
|
219
|
+
const items = list?.querySelectorAll("li");
|
|
220
|
+
expect(items).toBeDefined();
|
|
221
|
+
expect(items!.length).toBe(5);
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Pre-rendering (.pre.ts):**
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
it("should have pre-rendered content", () => {
|
|
229
|
+
const dom = result?.["index.html"]?.dom;
|
|
230
|
+
|
|
231
|
+
const generated = dom?.querySelector("#generated-content");
|
|
232
|
+
expect(generated).toBeDefined();
|
|
233
|
+
expect(generated!.textContent).not.toBe("");
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### 6. Verify File Metadata
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
it("should have correct metadata", () => {
|
|
241
|
+
expect(result?.["index.html"]?.type).toBe("text/html");
|
|
242
|
+
expect(result?.["index.html"]?.size).toBeGreaterThan(0);
|
|
243
|
+
expect(result?.["index.html"]?.fileHash).toBeDefined();
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should not have DOM on non-HTML files", () => {
|
|
247
|
+
expect(result?.["index.js"]?.dom).toBeUndefined();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("should have correct path info for nested files", () => {
|
|
251
|
+
expect(result?.["pages/about.html"]?.fileName).toBe("about.html");
|
|
252
|
+
expect(result?.["pages/about.html"]?.filePath).toBe("pages");
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Complete Example
|
|
257
|
+
|
|
258
|
+
Here's a complete test file for a tkeron project with components:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { describe, it, expect, beforeAll } from "bun:test";
|
|
262
|
+
import { getBuildResult, type BuildResult } from "tkeron";
|
|
263
|
+
import { join } from "path";
|
|
264
|
+
|
|
265
|
+
describe("my-website build", () => {
|
|
266
|
+
const sourcePath = join(import.meta.dir, "websrc");
|
|
267
|
+
let result: BuildResult;
|
|
268
|
+
|
|
269
|
+
beforeAll(async () => {
|
|
270
|
+
result = await getBuildResult(sourcePath);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should generate expected files", () => {
|
|
274
|
+
expect(result?.["index.html"]).toBeDefined();
|
|
275
|
+
expect(result?.["index.js"]).toBeDefined();
|
|
276
|
+
expect(result?.["about.html"]).toBeDefined();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("should have page title", () => {
|
|
280
|
+
const dom = result?.["index.html"]?.dom;
|
|
281
|
+
|
|
282
|
+
const title = dom?.querySelector("title");
|
|
283
|
+
expect(title).toBeDefined();
|
|
284
|
+
expect(title!.textContent).toBe("My Website");
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it("should have navigation from component", () => {
|
|
288
|
+
const dom = result?.["index.html"]?.dom;
|
|
289
|
+
|
|
290
|
+
const nav = dom?.querySelector("nav");
|
|
291
|
+
expect(nav).toBeDefined();
|
|
292
|
+
|
|
293
|
+
const homeLink = dom?.querySelector('nav a[href="/"]');
|
|
294
|
+
expect(homeLink).toBeDefined();
|
|
295
|
+
expect(homeLink!.textContent).toBe("Home");
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("should have footer from component", () => {
|
|
299
|
+
const dom = result?.["index.html"]?.dom;
|
|
300
|
+
|
|
301
|
+
const footer = dom?.querySelector("footer");
|
|
302
|
+
expect(footer).toBeDefined();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("should have compiled JavaScript", () => {
|
|
306
|
+
const js = result?.["index.js"]?.getContentAsString!();
|
|
307
|
+
|
|
308
|
+
expect(js).toBeDefined();
|
|
309
|
+
expect(js!.length).toBeGreaterThan(0);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it("should have script injected in head", () => {
|
|
313
|
+
const dom = result?.["index.html"]?.dom;
|
|
314
|
+
|
|
315
|
+
const script = dom?.querySelector('head script[type="module"]');
|
|
316
|
+
expect(script).toBeDefined();
|
|
317
|
+
expect(script!.getAttribute("src")).toBe("./index.js");
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Rules Summary
|
|
323
|
+
|
|
324
|
+
1. **Build once** with `beforeAll()` — never inside individual tests
|
|
325
|
+
2. **Check existence first** — always `expect(element).toBeDefined()` before accessing properties
|
|
326
|
+
3. **Use optional chaining** (`?.`) for safe property access on result entries
|
|
327
|
+
4. **Test bounded content** — specific values, keywords, attributes; not full output strings
|
|
328
|
+
5. **Test specific elements** — query for elements that matter to your project
|
|
329
|
+
6. **Verify transformations** — components processed, scripts injected, pre-rendering applied
|
|
330
|
+
7. **Don't test the parser** — you're testing your project, not tkeron internals
|
|
331
|
+
8. **Concurrent-safe** — tests must work with `bun test --concurrent`
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Simple click counter
|
|
2
2
|
let clickCount = 0;
|
|
3
3
|
|
|
4
|
-
const button = document.querySelector(
|
|
5
|
-
const heading = document.querySelector(
|
|
4
|
+
const button = document.querySelector("button") as HTMLButtonElement;
|
|
5
|
+
const heading = document.querySelector("h1") as HTMLHeadingElement;
|
|
6
6
|
|
|
7
|
-
button.addEventListener(
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
button.addEventListener("click", () => {
|
|
8
|
+
clickCount++;
|
|
9
|
+
heading.textContent = `Clicks: ${clickCount}`;
|
|
10
10
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Simple click counter
|
|
2
2
|
let clickCount = 0;
|
|
3
3
|
|
|
4
|
-
const button = document.querySelector(
|
|
5
|
-
const heading = document.querySelector(
|
|
4
|
+
const button = document.querySelector("button") as HTMLButtonElement;
|
|
5
|
+
const heading = document.querySelector("h1") as HTMLHeadingElement;
|
|
6
6
|
|
|
7
|
-
button.addEventListener(
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
button.addEventListener("click", () => {
|
|
8
|
+
clickCount++;
|
|
9
|
+
heading.textContent = `Clicks: ${clickCount}`;
|
|
10
10
|
});
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
</body>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Admin Dashboard</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Admin Dashboard</h1>
|
|
10
|
+
|
|
11
|
+
<section>
|
|
12
|
+
<h2>Local Components Override Root</h2>
|
|
13
|
+
<site-header></site-header>
|
|
14
|
+
<info-box></info-box>
|
|
15
|
+
<admin-panel></admin-panel>
|
|
16
|
+
</section>
|
|
17
|
+
</body>
|
|
18
18
|
</html>
|
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Blog Post</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Blog Post</h1>
|
|
10
|
+
|
|
11
|
+
<site-header></site-header>
|
|
12
|
+
|
|
13
|
+
<article>
|
|
14
|
+
<h2>Using Root Components</h2>
|
|
15
|
+
<info-box></info-box>
|
|
16
|
+
<p>
|
|
17
|
+
This page uses components from the root directory since there are no
|
|
18
|
+
local overrides.
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<comment-section></comment-section>
|
|
22
|
+
</article>
|
|
23
|
+
</body>
|
|
21
24
|
</html>
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
</body>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Component Priority - HTML Components</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>HTML Component Priority Demo</h1>
|
|
10
|
+
|
|
11
|
+
<section>
|
|
12
|
+
<h2>Root Level Components</h2>
|
|
13
|
+
<site-header></site-header>
|
|
14
|
+
<info-box></info-box>
|
|
15
|
+
</section>
|
|
16
|
+
</body>
|
|
17
17
|
</html>
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
</body>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Dashboard - Mixed Priority</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Dashboard with Mixed Priorities</h1>
|
|
10
|
+
|
|
11
|
+
<section>
|
|
12
|
+
<h2>Local Overrides and .com.ts Priority</h2>
|
|
13
|
+
<page-header></page-header>
|
|
14
|
+
<feature-card title="Dashboard Feature"></feature-card>
|
|
15
|
+
<stats-widget></stats-widget>
|
|
16
|
+
<footer-info></footer-info>
|
|
17
|
+
</section>
|
|
18
|
+
</body>
|
|
19
19
|
</html>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
</body>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Mixed Component Priority Demo</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Mixed Component Priority (.com.html + .com.ts)</h1>
|
|
10
|
+
|
|
11
|
+
<section>
|
|
12
|
+
<h2>Root Level - Both Component Types</h2>
|
|
13
|
+
<page-header></page-header>
|
|
14
|
+
<feature-card title="Feature 1"></feature-card>
|
|
15
|
+
<footer-info></footer-info>
|
|
16
|
+
</section>
|
|
17
|
+
</body>
|
|
18
18
|
</html>
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
<header
|
|
1
|
+
<header
|
|
2
|
+
style="
|
|
3
|
+
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
|
|
4
|
+
color: white;
|
|
5
|
+
padding: 2rem;
|
|
6
|
+
text-align: center;
|
|
7
|
+
"
|
|
8
|
+
>
|
|
2
9
|
<h2>Root Header (HTML Component)</h2>
|
|
3
10
|
<p>This is a static HTML component from root</p>
|
|
4
11
|
</header>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
</body>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Settings - Priority Showcase</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<h1>Settings Page</h1>
|
|
10
|
+
|
|
11
|
+
<section>
|
|
12
|
+
<h2>Both .com.ts and .com.html in Same Directory</h2>
|
|
13
|
+
<priority-test></priority-test>
|
|
14
|
+
<feature-card title="Settings Feature"></feature-card>
|
|
15
|
+
<footer-info></footer-info>
|
|
16
|
+
</section>
|
|
17
|
+
</body>
|
|
18
18
|
</html>
|