グリッドベースのサイネージシステム。iframeを使用して複数のアプレットをグリッドレイアウトで配置・管理します。
- ランタイム: Bun
- ビルドツール: Vite
- 言語: TypeScript
- スタイリング: Tailwind CSS v4.1
- バリデーション: Zod
- アーキテクチャ: Monorepo (Bun Workspaces)
- Bun がインストールされていること
bun installbun run dev開発サーバーは http://localhost:5173 で起動します。
bun run buildbun run previewbun run type-checkgrid-signage/
├── apps/
│ └── signage-host/ # メインアプリ
│ ├── applets/ # ローカルアプレット
│ │ └── sample/ # サンプルアプレット
│ ├── src/
│ │ ├── main.ts # エントリーポイント
│ │ ├── types.ts # 型定義
│ │ ├── AppletFrames.ts # アプレット管理クラス
│ │ └── lib/
│ │ ├── constants.ts # 定数定義
│ │ ├── grid.ts # グリッドサイズ計算
│ │ ├── applets/ # アプレット読み込み・管理
│ │ ├── config/ # 設定適用
│ │ ├── events/ # イベントハンドリング
│ │ ├── iframe/ # iframe関連処理
│ │ └── utils/ # ユーティリティ(エラーハンドリング等)
│ ├── apps.json # アプレット設定
│ └── package.json
├── packages/
│ └── core/ # 共有コアライブラリ(将来用)
└── package.json # ルート設定
すべてのアプレット(ローカルアプレットと外部URL)はapps/signage-host/apps.jsonで管理します。
[
{
"src": "applets/sample/index.html",
"name": "sample",
"id": "item1"
},
{
"src": "https://www.example.com/",
"name": "external-app",
"id": "item2"
}
]src: アプレットのURLまたはローカルパス(applets/で始まる)name: アプレット名(識別用)id: iframe要素のID(オプション)
apps/signage-host/applets/配下に新しいディレクトリを作成index.htmlファイルを作成apps.jsonにエントリを追加
apps.jsonに外部URLを直接指定できます。
アプレットはpostMessageを使用してグリッド配置とサイズを指定します。
const config = {
grid_column: 3, // グリッド列位置
grid_row: 9, // グリッド行位置
width: 2, // グリッドセル幅
height: 2, // グリッドセル高さ
cell_size: 200, // アプレット内のセルサイズ(ピクセル)
};
window.addEventListener("load", () => {
window.parent.postMessage({
type: "config",
content: config
});
});TypeScriptを使用する場合、型定義は以下の通りです:
interface AppletConfig {
grid_column: number; // 正の整数
grid_row: number; // 正の整数
width: number; // 正の数
height: number; // 正の数
cell_size: number; // 正の数
}- Zodを使用したランタイムバリデーション
- TypeScriptによる型チェック
- カスタムエラークラスによるエラーハンドリング
@/エイリアスを使用してsrc/ディレクトリからの絶対パスでインポートできます:
import { AppletFrames } from '@/AppletFrames'
import { loadApplets } from '@/lib/applets'すべての定数はlib/constants.tsに集約されています。
統一されたエラーハンドリングシステム:
AppletErrorクラス: カスタムエラークラスlogError()/logWarning(): 統一されたログ出力関数