Skip to content

AppLayout ​

AppLayout は管理画面のシェル全体です: グラデーションのトップバー(検索、メッセージ、通知、言語、カラーモード、ユーザーメニュー)、アクティブな階層を示す多階層のサイドメニュー、ユーザープロフィール、設定パネル、ページヘッダー、フッター。config.layout で vertical、mini、horizontal を切り替えます。

プレビュー ​

プレビュー
vue
<div class="layout-frame"><iframe src="http://localhost:5182/" title="Vue playground" loading="lazy"></iframe><p class="layout-frame__hint">Live Vue playground (run <code>npm run dev:vue</code>). Open the ⚙ settings panel to switch skin, layout, dark mode and language.</p></div>
tsx
import { AppLayout, Page } from '@thl-ui/react';
import { Link, useLocation } from 'react-router';

<AppLayout menu={menu} currentPath={loc.pathname} user={{ ...user, onSelect: (k) => k === 'logout' && logout() }}
  onSearch={(q) => nav(`/search?q=${q}`)}
  renderLink={(item, children, className) => <Link to={item.href!} className={className}>{children}</Link>}
  topbarRight={<TopbarMessages items={messages} icon="mail" />}
  sidebarFooter={<Button variant="success" block>Upgrade</Button>}>
  <Page title="Dashboard" breadcrumb={[{ label: 'Home', href: '/' }, { label: 'Dashboard' }]}>…</Page>
</AppLayout>
html
<thl-app-layout [menu]="menu" [currentPath]="path()" [user]="user" searchable (search)="search($event)" (userSelect)="onUser($event)">
  <ng-template thlMenuLink let-item let-cls="cls" let-content="content">
    <a [routerLink]="item.href" [class]="cls"><ng-container [ngTemplateOutlet]="content" /></a>
  </ng-template>
  <ng-container thlTopbarRight><thl-topbar-messages [items]="messages" icon="mail" /></ng-container>
  <div thlSidebarFooter><button thl-button variant="success" block>Upgrade</button></div>
  <router-outlet />
</thl-app-layout>

Vue ​

vue
<ThlAppLayout :menu="menu" :current-path="route.path" :user="user" searchable @search="onSearch" @user-select="onUser">
  <template #topbar-right><ThlTopbarMessages :items="messages" icon="mail" /></template>
  <template #link="{ item, content, class: cls }"><RouterLink :to="item.href" :class="cls"><component :is="() => content" /></RouterLink></template>
  <template #sidebar-footer><ThlButton variant="success" block>アップグレード</ThlButton></template>
  <ThlPage title="Dashboard" :breadcrumb="[{ label: 'ホーム', href: '/' }, { label: 'Dashboard' }]">…</ThlPage>
</ThlAppLayout>

メニュー ​

ts
import type { MenuItem } from '@thl-ui/core';

export const menu: MenuItem[] = [
  { key: 'dash', label: 'menu.dashboard', icon: 'layout-dashboard', badge: { text: 4, color: 'danger' }, children: [
    { key: 'd1', label: 'menu.dashboard1', href: '/' },
    { key: 'd2', label: 'menu.dashboard2', href: '/dashboard-2' },
  ] },
  { key: 'h', label: 'menu.apps', heading: true },
  { key: 'inbox', label: 'menu.inbox', icon: 'mail', href: '/inbox' },
];

label には i18n キー(自動的に翻訳されます)または文字列リテラルを指定できます。アクティブな階層は currentPath から計算されます。

水平レイアウト ​

layout: 'horizontal' にすると、メニューはサイドからトップバー下のバーに移動します(Cubic-horizontal と同じ)。サブメニューはホバーまたはキーボードフォーカスでドロップダウンとして開きます。メニューは常に 1 行に収まり、入りきらない項目は もっと見る ドロップダウンにまとめられ、ウィンドウを広げると元に戻ります。768px 未満では通常のオフキャンバスサイドバーになります。同じ menu 配列をすべてのレイアウトで使えます。

tsx
// main.tsx: 水平モードで起動
<ThlProvider config={{ layout: 'horizontal' }}>
  <AppLayout menu={menu} currentPath={loc.pathname} renderLink={renderLink}>…</AppLayout>
</ThlProvider>

// 実行時に切り替え(⚙ 設定パネルも同じ処理)
const [, setConfig] = useThlConfig();
setConfig({ layout: 'horizontal' });
ts
// main.ts: 水平モードで起動
app.use(ThlUI, { layout: 'horizontal' });

// 実行時に切り替え(⚙ 設定パネルも同じ処理)
const { set } = useThlConfig();
set({ layout: 'horizontal' });
ts
// main.ts: 水平モードで起動
bootstrapApplication(AppComponent, { providers: [provideThlUI({ layout: 'horizontal' })] });

// 実行時に切り替え(⚙ 設定パネルも同じ処理)
inject(ThlConfigService).set({ layout: 'horizontal' });

プレイグラウンドで試す: localhost:5182/?layout=horizontal。?layout=mini、?theme=red-dark、?lang=ja、?mode=dark も指定できます。

レスポンシブな動作 ​

  • ≥ 1170px: フルサイドバー(または layout に応じて mini / horizontal)
  • 768 – 1169px: 自動的にミニサイドバー
  • < 768px: 背景付きのオフキャンバスサイドバー。トップバーから開閉

ブレークポイントは components.Sidebar.breakpoint で設定できます。

API ​

AppLayout

<ThlAppLayout> · import { ThlAppLayout } from '@thl-ui/vue'

Prop型デフォルト
menu*array—
currentPathstring—
brandstring"thl-ui"
brandHrefstring"/"
userobject—
searchableboolean—
settingsbooleantrue
footerstring | boolean—

イベント: searchuser-select

スロット: brandtopbar-lefttopbar-rightlinksidebar-footerdefaultfooter

SideMenu

<ThlSideMenu> · import { ThlSideMenu } from '@thl-ui/vue'

Prop型デフォルト
items*array—
currentPathstring—
accordionbooleantrue
horizontalboolean—

スロット: link

TopbarMessages

<ThlTopbarMessages> · import { ThlTopbarMessages } from '@thl-ui/vue'

Prop型デフォルト
items*array—
iconstring"mail"
titlestring—
footerstring—
footerHrefstring—

SettingsPanel

<ThlSettingsPanel> · import { ThlSettingsPanel } from '@thl-ui/vue'

Prop型デフォルト
openboolean—

イベント: update:open

Page

<ThlPage> · import { ThlPage } from '@thl-ui/vue'

Prop型デフォルト
titlestring—
breadcrumbarray—

スロット: actionslinkdefault