Skip to content

Commit 6395d22

Browse files
SoliEstreclaude
andcommitted
docs(Q7): mermaid 식 라이브 tile 데모 (estreuv-demo 코드펜스)
코드 블록이 실제 컴포넌트로 렌더되는 형태 (mermaid 처럼): - .vitepress/config.js: estreuv-demo fence → live HTML + 소스 동시 출력, vue isCustomElement(estreuv-*) 로 SSR 통과 - .vitepress/theme/index.js: client-only 로 estreuv tile 등록(hydration 후 업그레이드) + custom.css 데모 박스 - tiles.md: tile 예제 4종 → estreuv-demo (라이브) - estreuv/lit 는 docs 가 선언 안 해도 root 워크스페이스 호이스트에서 Vite 해소 (docs 에 dep 추가 시 install 불안정 → 미선언 채택) 빌드 클린(9p), npm ci 일관, estreuv 38/38 회귀 0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 35234f5 commit 6395d22

4 files changed

Lines changed: 77 additions & 4 deletions

File tree

packages/docs/.vitepress/config.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,36 @@ export default defineConfig({
99
cleanUrls: true,
1010
lastUpdated: true,
1111

12+
// Treat <estreuv-*> as custom elements so Vue's compiler leaves them
13+
// intact (they upgrade client-side once registered in theme/index.js).
14+
vue: {
15+
template: {
16+
compilerOptions: {
17+
isCustomElement: (tag) => tag.startsWith('estreuv-'),
18+
},
19+
},
20+
},
21+
22+
markdown: {
23+
// mermaid-style live demo: an ```estreuv-demo fenced block renders the
24+
// markup live (registered custom elements) AND shows the source.
25+
config: (md) => {
26+
const fence = md.renderer.rules.fence;
27+
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
28+
const token = tokens[idx];
29+
if (token.info.trim() === 'estreuv-demo') {
30+
const raw = token.content;
31+
const asHtml = fence([{ ...token, info: 'html' }], 0, options, env, self);
32+
return `<div class="estreuv-demo">
33+
<div class="estreuv-demo__live">\n${raw}\n</div>
34+
<div class="estreuv-demo__code">${asHtml}</div>
35+
</div>\n`;
36+
}
37+
return fence(tokens, idx, options, env, self);
38+
};
39+
},
40+
},
41+
1242
themeConfig: {
1343
nav: [
1444
{ text: 'Guide', link: '/guide/getting-started' },
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* Live demo block (```estreuv-demo) — live render above, source below. */
2+
.estreuv-demo {
3+
border: 1px solid var(--vp-c-divider);
4+
border-radius: 12px;
5+
margin: 18px 0;
6+
overflow: hidden;
7+
}
8+
9+
.estreuv-demo__live {
10+
display: flex;
11+
flex-wrap: wrap;
12+
gap: 12px;
13+
align-items: flex-start;
14+
padding: 24px;
15+
background: var(--vp-c-bg-soft);
16+
}
17+
18+
.estreuv-demo__code [class*='language-'] {
19+
margin: 0;
20+
border-radius: 0;
21+
}
22+
23+
.estreuv-demo__code [class*='language-']::before {
24+
display: none; /* hide the lang label inside the demo frame */
25+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import DefaultTheme from 'vitepress/theme';
2+
import './custom.css';
3+
4+
// Register the EstreUV tile custom elements on the client so that
5+
// ```estreuv-demo blocks render live. Browser-only (web components have
6+
// no SSR); the markup is emitted during SSR and upgrades after hydration.
7+
export default {
8+
extends: DefaultTheme,
9+
enhanceApp() {
10+
if (typeof window !== 'undefined') {
11+
import('estreuv/dark-mode-tile.js');
12+
import('estreuv/clock-tile.js');
13+
import('estreuv/notif-count-tile.js');
14+
import('estreuv/notelle-sidebar.js');
15+
import('estreuv/notelle-item.js');
16+
}
17+
},
18+
};

packages/docs/tiles.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ A theme toggle cycling **auto → light → dark**, persisted to `localStorage`
99
`body[data-dark-mode]` (delegates to `estreUi.setDarkMode` when EstreUI is present). Pattern:
1010
local-state + global-API delegation.
1111

12-
```html
12+
```estreuv-demo
1313
<estreuv-dark-mode-tile></estreuv-dark-mode-tile>
1414
<estreuv-dark-mode-tile text="Theme" color="#2a8"></estreuv-dark-mode-tile>
1515
```
@@ -27,7 +27,7 @@ Method: `.cycle()` — advance to the next state.
2727
A timer-driven clock. Starts its interval on `onShow`, stops on `onHide` — a clean example of
2828
**resource lifecycle** tied to visibility (and `onClose`/`onRelease`/`disconnectedCallback` cleanup).
2929

30-
```html
30+
```estreuv-demo
3131
<estreuv-clock-tile></estreuv-clock-tile>
3232
<estreuv-clock-tile format="12h" text="12h"></estreuv-clock-tile>
3333
```
@@ -38,7 +38,7 @@ A badge counter driven by **external / intent** state. `bump(by)` and `clear()`
3838
`requestIntentUpdate` (no direct mutation); `onShow` syncs from `intent.notifCount`. Shows `N+` past
3939
`maxDisplay`.
4040

41-
```html
41+
```estreuv-demo
4242
<estreuv-notif-count-tile></estreuv-notif-count-tile>
4343
<estreuv-notif-count-tile count="128" max="99" text="badge cap"></estreuv-notif-count-tile>
4444
```
@@ -50,7 +50,7 @@ Methods: `.bump(by = 1)`, `.clear()`.
5050
A nested-container prototype — a sidebar with light-DOM `<estreuv-notelle-item>` children. Demonstrates
5151
**nested lifecycle** (children receive hooks via the flat dispatch) and host-level event bubbling.
5252

53-
```html
53+
```estreuv-demo
5454
<estreuv-notelle-sidebar title="Notelle">
5555
<estreuv-notelle-item label="Inbox" icon="📥"></estreuv-notelle-item>
5656
<estreuv-notelle-item label="Archive" icon="🗄"></estreuv-notelle-item>

0 commit comments

Comments
 (0)