Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ src/
├── patterns/ # APG パターン実装
│ └── button/ # 例: button パターン
│ ├── meta.ts # パターンメタデータ(単一の真実源)
│ ├── DemoSection.astro # 全フレームワーク統合デモ
│ ├── DemoSection.astro # 全フレームワーク統合デモ(legacy)
│ │ # ↓ または framework 別に分割(後述)
│ ├── DemoSection.react.astro # React 用デモ(split 後)
│ ├── DemoSection.vue.astro # Vue 用デモ(split 後)
│ ├── DemoSection.svelte.astro # Svelte 用デモ(split 後)
│ ├── DemoSection.web-component.astro # Astro Web Component 用(split 後)
│ ├── TestingDocs.astro # テストドキュメント
│ ├── Button.tsx # React 実装
│ ├── Button.vue # Vue 実装
Expand Down Expand Up @@ -78,8 +83,9 @@ src/
各パターンの `meta.ts` が単一の真実源(Single Source of Truth)となる。1つの `meta.ts` から 4フレームワーク × 2言語 = 8ページが動的に生成される。

- **`meta.ts`**: タイトル、説明、TOC、リソース、フレームワーク別メタデータ(ソースファイル、API Props/Events/Slots)を `PatternMeta` 型で定義。全テキストは `Record<Locale, string>` で i18n 対応
- **`DemoSection.astro`**: 4フレームワークの実装を静的 import し、`framework` prop で切り替えて表示
- **動的ルーティング**: `[pattern]/[framework]/index.astro` が `import.meta.glob()` で全パターンの `meta.ts` を検出し、`getStaticPaths()` でビルド時にページ生成
- **`DemoSection.*.astro`** (推奨): framework ごとに分割した薄い Astro。`DemoSection.{react,vue,svelte,web-component}.astro` が、それぞれ自分の framework の実装ファイルだけを静的 import する。ページ側 dispatcher が `framework` から該当ファイルを選んで呼ぶ
- **`DemoSection.astro`** (legacy): 4 framework の実装を 1 ファイルで静的 import する旧形式。dispatcher にフォールバックとして残してあり、まだ移行していない pattern で使われている。**注意**: legacy 形式は `@vitejs/plugin-react v6` + Vite 8 + Vue SFC `<script setup lang="ts">` の組み合わせで dev 限定の `$RefreshSig$` エラーを引き起こすことがあるため、Vue SFC を含むパターンは新形式に移行することを推奨
- **動的ルーティング**: `[pattern]/[framework]/index.astro` が `import.meta.glob()` で全パターンの `meta.ts` を検出し、`getStaticPaths()` でビルド時にページ生成。同じファイル内の dispatcher が `DemoSection.{framework}.astro` を優先し、無ければ legacy `DemoSection.astro` にフォールバック

**パスエイリアス**(tsconfig.json):

Expand Down
34 changes: 32 additions & 2 deletions src/pages/ja/patterns/[pattern]/[framework]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,29 @@
import type { PatternMeta } from '@/lib/pattern-meta-types';

// Glob imports for dynamic content loading
const demoModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.astro');

Check warning on line 27 in src/pages/ja/patterns/[pattern]/[framework]/index.astro

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
const demoReactModules = import.meta.glob<{ default: any }>(

Check warning on line 28 in src/pages/ja/patterns/[pattern]/[framework]/index.astro

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
'/src/patterns/*/DemoSection.react.astro'
);
const demoVueModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.vue.astro');
const demoSvelteModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.svelte.astro'
);
const demoWebComponentModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.web-component.astro'
);
const frameworkDemoModules = {
react: demoReactModules,
vue: demoVueModules,
svelte: demoSvelteModules,
astro: demoWebComponentModules,
} as const;
const frameworkDemoKey = {
react: 'react',
vue: 'vue',
svelte: 'svelte',
astro: 'web-component',
} as const;
const testingModules = import.meta.glob<{ default: any }>('/src/patterns/*/TestingDocs.astro');
const nativeHtmlModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/NativeHtmlNotice.astro'
Expand Down Expand Up @@ -78,8 +100,16 @@
const fwInfo = FRAMEWORK_INFO[framework];

// Load dynamic components
const DemoSection = (await demoModules[`/src/patterns/${pattern}/DemoSection.astro`]?.())
?.default as any;
// Prefer framework-specific DemoSection (DemoSection.{framework}.astro) if present,
// fall back to the legacy unified DemoSection.astro during migration.
const newDemoLoader =
frameworkDemoModules[framework][
`/src/patterns/${pattern}/DemoSection.${frameworkDemoKey[framework]}.astro`
];
const legacyDemoLoader = demoModules[`/src/patterns/${pattern}/DemoSection.astro`];
const DemoSection = newDemoLoader
? ((await newDemoLoader()).default as any)
: ((await legacyDemoLoader?.())?.default as any);
const TestingDocs = (await testingModules[`/src/patterns/${pattern}/TestingDocs.astro`]?.())
?.default as any;
const NativeHtmlNotice = meta.hasNativeHtmlNotice
Expand Down
34 changes: 32 additions & 2 deletions src/pages/patterns/[pattern]/[framework]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,28 @@ import type { PatternMeta } from '@/lib/pattern-meta-types';

// Glob imports for dynamic content loading
const demoModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.astro');
const demoReactModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.react.astro'
);
const demoVueModules = import.meta.glob<{ default: any }>('/src/patterns/*/DemoSection.vue.astro');
const demoSvelteModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.svelte.astro'
);
const demoWebComponentModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/DemoSection.web-component.astro'
);
const frameworkDemoModules = {
react: demoReactModules,
vue: demoVueModules,
svelte: demoSvelteModules,
astro: demoWebComponentModules,
} as const;
const frameworkDemoKey = {
react: 'react',
vue: 'vue',
svelte: 'svelte',
astro: 'web-component',
} as const;
const testingModules = import.meta.glob<{ default: any }>('/src/patterns/*/TestingDocs.astro');
const nativeHtmlModules = import.meta.glob<{ default: any }>(
'/src/patterns/*/NativeHtmlNotice.astro'
Expand Down Expand Up @@ -79,8 +101,16 @@ if (!fwMeta) {
const fwInfo = FRAMEWORK_INFO[framework];

// Load dynamic components
const DemoSection = (await demoModules[`/src/patterns/${pattern}/DemoSection.astro`]?.())
?.default as any;
// Prefer framework-specific DemoSection (DemoSection.{framework}.astro) if present,
// fall back to the legacy unified DemoSection.astro during migration.
const newDemoLoader =
frameworkDemoModules[framework][
`/src/patterns/${pattern}/DemoSection.${frameworkDemoKey[framework]}.astro`
];
const legacyDemoLoader = demoModules[`/src/patterns/${pattern}/DemoSection.astro`];
const DemoSection = newDemoLoader
? ((await newDemoLoader()).default as any)
: ((await legacyDemoLoader?.())?.default as any);
const TestingDocs = (await testingModules[`/src/patterns/${pattern}/TestingDocs.astro`]?.())
?.default as any;
const NativeHtmlNotice = meta.hasNativeHtmlNotice
Expand Down
116 changes: 0 additions & 116 deletions src/patterns/alert/DemoSection.astro

This file was deleted.

26 changes: 26 additions & 0 deletions src/patterns/alert/DemoSection.react.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import { AlertDemo as AlertDemoReact } from './AlertDemo';

interface Props {
framework?: Framework;
locale?: Locale;
}

const { locale = 'en' } = Astro.props;
const isJa = locale === 'ja';
---

<div class="border-border bg-background rounded-lg border p-6">
<div>
<p class="text-muted-foreground mb-4">
{
isJa
? 'ボタンをクリックすると、さまざまなバリアントのアラートが表示されます。ライブリージョンコンテナはページ読み込み時からDOMに存在し、コンテンツのみが変更されます。'
: 'Click the buttons below to show alerts with different variants. The live region container exists in the DOM from page load - only the content changes.'
}
</p>
<AlertDemoReact client:load />
</div>
</div>
26 changes: 26 additions & 0 deletions src/patterns/alert/DemoSection.svelte.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import AlertDemoSvelte from './AlertDemo.svelte';

interface Props {
framework?: Framework;
locale?: Locale;
}

const { locale = 'en' } = Astro.props;
const isJa = locale === 'ja';
---

<div class="border-border bg-background rounded-lg border p-6">
<div>
<p class="text-muted-foreground mb-4">
{
isJa
? 'ボタンをクリックすると、さまざまなバリアントのアラートが表示されます。ライブリージョンコンテナはページ読み込み時からDOMに存在し、コンテンツのみが変更されます。'
: 'Click the buttons below to show alerts with different variants. The live region container exists in the DOM from page load - only the content changes.'
}
</p>
<AlertDemoSvelte client:load />
</div>
</div>
26 changes: 26 additions & 0 deletions src/patterns/alert/DemoSection.vue.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import AlertDemoVue from './AlertDemo.vue';

interface Props {
framework?: Framework;
locale?: Locale;
}

const { locale = 'en' } = Astro.props;
const isJa = locale === 'ja';
---

<div class="border-border bg-background rounded-lg border p-6">
<div>
<p class="text-muted-foreground mb-4">
{
isJa
? 'ボタンをクリックすると、さまざまなバリアントのアラートが表示されます。ライブリージョンコンテナはページ読み込み時からDOMに存在し、コンテンツのみが変更されます。'
: 'Click the buttons below to show alerts with different variants. The live region container exists in the DOM from page load - only the content changes.'
}
</p>
<AlertDemoVue client:load />
</div>
</div>
68 changes: 68 additions & 0 deletions src/patterns/alert/DemoSection.web-component.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
import type { Framework } from '@/lib/frameworks';
import type { Locale } from '@/i18n/ui';
import Alert from './Alert.astro';

interface Props {
framework?: Framework;
locale?: Locale;
}

const { locale = 'en' } = Astro.props;
const isJa = locale === 'ja';
---

<div class="border-border bg-background rounded-lg border p-6">
<div>
<p class="text-muted-foreground mb-4">
{
isJa ? (
<Fragment>
Astro実装では、アラートコンテンツの更新に <code>setMessage()</code>{' '}
メソッドを提供するWeb
Componentを使用します。ライブリージョンコンテナはページ読み込み時からDOMに存在し、コンテンツのみが変更されます。
</Fragment>
) : (
<Fragment>
The Astro implementation uses a Web Component that provides a <code>setMessage()</code>{' '}
method for updating alert content. The live region container exists in the DOM from page
load - only the content changes.
</Fragment>
)
}
</p>
<div class="space-y-4">
<Alert id="demo-alert" variant="info" dismissible />
<div class="flex flex-wrap gap-2">
<button
type="button"
class="rounded-md bg-blue-100 px-4 py-2 text-sm font-medium text-blue-700 hover:bg-blue-200 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:outline-none"
onclick="document.querySelector('apg-alert').setMessage('This is an informational message.', 'info')"
>
Info
</button>
<button
type="button"
class="rounded-md bg-green-100 px-4 py-2 text-sm font-medium text-green-700 hover:bg-green-200 focus:ring-2 focus:ring-green-500 focus:ring-offset-2 focus:outline-none"
onclick="document.querySelector('apg-alert').setMessage('Operation completed successfully!', 'success')"
>
Success
</button>
<button
type="button"
class="rounded-md bg-amber-100 px-4 py-2 text-sm font-medium text-amber-700 hover:bg-amber-200 focus:ring-2 focus:ring-amber-500 focus:ring-offset-2 focus:outline-none"
onclick="document.querySelector('apg-alert').setMessage('Please review your input before proceeding.', 'warning')"
>
Warning
</button>
<button
type="button"
class="rounded-md bg-red-100 px-4 py-2 text-sm font-medium text-red-700 hover:bg-red-200 focus:ring-2 focus:ring-red-500 focus:ring-offset-2 focus:outline-none"
onclick="document.querySelector('apg-alert').setMessage('An error occurred. Please try again.', 'error')"
>
Error
</button>
</div>
</div>
</div>
</div>
Loading
Loading