外観カスタマイズ
KUKAN をフォークして自組織向けにカスタマイズする際のガイドです。 変更は段階的に行えます。軽い変更から順に試してください。
カスタマイズの範囲
Section titled “カスタマイズの範囲”フォーク側で変更するファイルは apps/web/brands/default/ 配下に限定されます。中身は次の通りです。
パス(brands/default/ 配下) |
内容 | 対応セクション |
|---|---|---|
brand-config.ts |
サイト名・説明・ロゴ・フッターリンク・OG 画像・ファビコン・GA 測定 ID | Tier 2 |
theme.css |
CSS 変数(色・サイズ)の上書き | Tier 1 |
messages/ja.json / en.json |
UI テキスト(i18n メッセージ)の上書き | i18n メッセージの上書き |
overrides/ |
Header / Footer / TopPage などのコンポーネント差し替え(スロット) | Tier 3 |
pages/ |
独自の静的ページ(利用規約・プライバシーポリシー等) | 静的ページの追加 |
public/ |
ロゴ・ファビコン・OG 画像などの静的ファイル | 静的ファイルの配置 |
index.ts / messages/index.ts |
エクスポートのまとめ(バレル)。通常は編集不要 | — |
これ以外のファイルは変更しないでください。本体の更新を取り込む際にコンフリクトが発生します。
Tier 1: 色・サイズの変更
Section titled “Tier 1: 色・サイズの変更”brands/default/theme.css に CSS 変数を記述するだけで、サイト全体の配色やサイズを変更できます。
:root { --primary: 142 64% 32%; /* メインカラー(HSL) */ --primary-foreground: 0 0% 100%; /* メインカラー上のテキスト色 */ --kukan-header-height: 72px; /* ヘッダー高さ */ --kukan-container-max-width: 1400px;}利用可能な CSS 変数
Section titled “利用可能な CSS 変数”shadcn/ui 標準の変数と KUKAN 固有の変数(--kukan-* プレフィックス)が利用できます。全一覧は apps/web/src/app/globals.css を参照してください。
上書きしてよいかの判断がしやすいよう、各変数に上書き区分を付けています。
- 推奨 — ブランドに合わせて変更する想定の変数
- 注意 — 上書き可能ですが複数のコンポーネント・状態で共有されています。「用途と主な使用箇所」を確認し、デフォルトの明暗関係(淡色・濃色)を維持してください
- 非推奨 — UI の意味(エラー・成功・警告)を伝える変数。ブランド都合での変更は推奨しません
| 変数 | 区分 | 用途と主な使用箇所 |
|---|---|---|
--primary / --primary-foreground |
推奨 | メインカラー。ボタン(default)、リンク、進捗バー、テキスト選択、チェックボックス等の選択状態 |
--highlight |
推奨 | 検索キーワードのハイライト(影響は検索結果表示のみ) |
--radius |
推奨 | 角丸の基準値(全コンポーネント) |
--kukan-* |
推奨 | ヘッダー高さ・ロゴ高さ・コンテナ幅等のレイアウト値 |
--background / --foreground |
注意 | ページ背景・基本テキスト。サイト全体に波及 |
--card / --popover(各 -foreground 付き) |
注意 | カード、およびドロップダウン・セレクト等のポップアップの背景とテキスト |
--secondary / --secondary-foreground |
注意 | secondary ボタン・バッジの背景。淡色前提 |
--muted / --muted-foreground |
注意 | 補足テキスト(サイト内で最も使用箇所が多い変数)、プレースホルダー、スケルトン、淡色背景。淡色前提 |
--accent / --accent-foreground |
注意 | ホバー・選択状態の色。outline / ghost ボタンのホバー、セレクト・ドロップダウンのフォーカス項目、ダイアログの閉じるボタン等。淡色前提 |
--border / --input |
注意 | 全コンポーネントの境界線・入力枠 |
--ring |
注意 | フォーカスリング。キーボード操作の視認性に直結するため、背景とのコントラストを確保してください |
--destructive / --destructive-foreground |
非推奨 | エラー・削除の意味色(destructive ボタン、フォームエラー、削除メニュー項目)。ベタ塗り背景と、その上のテキスト |
--success / --warning |
非推奨 | 成功・警告の意味色(アラート、パイプラインステータス、フォーム警告)。ボーダー・淡色背景・アイコンに使用 |
--success-tint-foreground / --warning-tint-foreground |
非推奨 | 成功・警告の淡色(/10〜/15)背景上のテキスト色。ベタ塗り用ではありません |
--ai / --ai-tint-foreground |
非推奨 | AI が生成したもの(抄録バッジ・検索カード等)を示す意味色。-tint-foreground は淡色背景上のテキスト |
上書き時のルール
Section titled “上書き時のルール”配色を安全に差し替えるため、以下を守ってください。
- 生トークンのみを上書きする —
--primary等をそのまま再宣言します。globals.cssの--color-*(Tailwind 連携用マッピング)は本体管理のため変更しないでください。 - HSL の裸トリプレット形式を維持する —
--primary: 142 64% 32%;のようにカンマなし・hsl()なしで記述します。hex 値やhsl(...)で包んだ値は動作しません。 - 不透明度を焼き込まない — 透過は使用側のユーティリティ(
bg-success/10等)で掛かります。トークンには不透明度 100% のベース色だけを入れてください。 - ペアはセットで更新し、コントラストを確認する —
--primaryを変えたら--primary-foregroundも更新し、コントラスト比 4.5:1 以上(WCAG AA)を確保します。--success/--warningを変えた場合、対応する-tint-foregroundは同系統の濃色にし、/15の淡色背景上で 4.5:1 以上を確認します(-foregroundと異なりベタ塗り背景用ではない点に注意)。 dark:クラスを持ち込まない — KUKAN のテーマトークンはライト専用です。override コンポーネントにdark:を書くと、OS がダーク設定のユーザーだけ表示が崩れます。- override コンポーネントでも生パレット色を書かない —
text-green-600ではなくtext-successのようにセマンティッククラスを使うと、後からの配色変更がtheme.css1 ファイルで済みます。
独自トークンの追加(--brand-*)
Section titled “独自トークンの追加(--brand-*)”デザイナー指定の配色に、公式トークンの役割(主要色・強調色など)に当てはまらない独自色が含まれる場合は、--brand- プレフィックスの独自トークンを brands/default/theme.css に追加できます。
:root { --brand-accent-green: 183 29% 87%; --brand-link: 183 79% 28%;}--brand-*はフォーク専用の名前空間です — 本体は--brand-*を定義も参照もしないため、本体更新と衝突しません。逆に--kukan-*は本体専用のため、独自トークンには使わないでください- 形式は公式トークンと同じ HSL 裸トリプレットを推奨します(使用側で
/10等の透過を掛けられます) - 使用できるのはフォーク所有のコンポーネント内のみです(
brands/default/overrides//brands/default/pages/)。本体のコンポーネントが独自トークンを参照することはありません - Tailwind のユーティリティクラスは生成されません —
theme.cssはglobals.cssと別の CSS ユニットのため@themeによるクラス生成が効きません。arbitrary value 記法で参照してください:
<a className="text-[hsl(var(--brand-link))] bg-[hsl(var(--brand-accent-green))]">...</a>本体画面の色を部分的に変えたい場合
Section titled “本体画面の色を部分的に変えたい場合”オーバーライドしていない本体画面で「このコンポーネントだけ色を変えたい」場合、上の表のとおり公式トークンの上書きでは影響範囲が広すぎることがあります。このケースでは、本体側がコンポーネントスコープのエイリアストークン(例: --kukan-header-bg。デフォルトは var(--primary) を参照し、上書きしない限り挙動は変わりません)を追加する運用としています。必要になったら本体リポジトリへ issue で追加を提案してください。
Tier 2: テキスト・メタデータの変更
Section titled “Tier 2: テキスト・メタデータの変更”brands/default/brand-config.ts を編集して、サイト名・著作権表示・メタデータを変更します。
import type { BrandConfig } from '@/types/brand'
export const brandConfig: BrandConfig = { siteName: '○○市オープンデータカタログ', siteDescription: '○○市が公開するオープンデータを検索・ダウンロードできます', copyright: '○○市.', copyrightUrl: 'https://www.city.example.lg.jp',
logo: { type: 'image', src: '/brand/logo.svg', width: 160, height: 40, alt: '○○市' },
headerNavExtra: [ { label: '市公式サイト', href: 'https://www.city.example.lg.jp', external: true }, ], footerLinks: [ { label: { ja: '利用規約', en: 'Terms of Use' }, href: '/terms' }, { label: 'お問い合わせ', href: '/contact' }, ],
ogImage: '/brand/og-image.png', faviconPath: '/brand/favicon.ico',}各フィールドの説明
Section titled “各フィールドの説明”| フィールド | 説明 |
|---|---|
siteName |
サイトタイトル(ブラウザタブ、ヘッダー等) |
siteDescription |
meta description(検索エンジン向け) |
copyright |
フッターの著作権表示テキスト(© 2026 は自動付与) |
copyrightUrl |
フッターのサイト名リンク先(省略時はリンクなし) |
logo |
ヘッダーロゴの設定(後述) |
headerNavExtra |
ヘッダーナビゲーションの追加項目 |
footerLinks |
フッターのリンク一覧 |
ogImage |
OGP 画像のパス(public/ 配下のパス) |
faviconPath |
ファビコンのパス |
noindex |
true で全ページに noindex, nofollow の robots meta タグを付与(省略時はなし) |
gaMeasurementId |
GA4 測定 ID(G-XXXXXXXXXX)。null / 省略で GA4 無効(アクセス統計) |
csp |
ページの Content-Security-Policy に足すソース(ディレクティブ → ソースの配列。例: { 'img-src': ['https://cdn.example.jp'] })。自分のホストからスクリプトや CSS を読む、別のドメインの API を呼ぶブランドが使う。足すだけで、外せない(ADR-071)。GA4 のホストは自動で入る |
テキスト系フィールド(siteName・siteDescription・copyright・logo.alt・headerNavExtra[].label・footerLinks[].label)は、文字列のほかにロケールマップ(例: { ja: '利用規約', en: 'Terms of Use' })を指定できます。文字列は全ロケール共通、マップは言語切替に追従します。指定のないロケールは英語(デフォルトロケール)→定義済みの値の順で補われます。
noindex は、検索エンジンにインデックスさせたくない検証環境や限定公開サイト向けのスイッチです。robots.txt でサイト全体のクロールを断ることはしません(断るとクローラーが meta タグ自体を読めなくなるためです)。アクセス自体を制限したい場合は、Basic 認証や IP 制限などのアクセス制御を併用してください。
検索エンジン向けの出力は、noindex に応じて次のように切り替わります。Search Console への登録は必要ありません(主要な検索エンジンは robots.txt の Sitemap: 行から sitemap を見つけます)。
| 出力 | noindex: false |
noindex: true |
|---|---|---|
/sitemap.xml(データセット・リソース・組織・カテゴリー・タグ) |
公開のものだけを、種類ごとに 1 万件ずつ /sitemap/<種類>/<番号>.xml に分けて出す |
404 |
robots.txt の Sitemap: 行 |
出す | 出さない |
データセット詳細の構造化データ(schema.org Dataset、JSON-LD) |
公開のデータセットに出す(Google Dataset Search が読む) | 出さない |
| 絞り込み・検索語の付いた一覧ページ | noindex, follow |
noindex, nofollow(全ページ) |
robots.txt は noindex に関係なく、一覧のクエリ(/dataset?・/organization?・/group?)、/api/、/odata/、/dashboard、/auth/ へのクロールを断ります。絞り込みの組み合わせは際限なく URL を生むためで、データセットへは sitemap と組織・カテゴリー・タグのページからたどれます。sitemap と robots.txt の URL は BETTER_AUTH_URL のオリジンで書かれます。
検索例チップ(検索ボックス下のクエリ例)はブランド設定ではなく、管理画面のサイト管理(/dashboard/admin/site)から設定します。人口や基準日のように更新のたびにビルドしたくない値も、同じ画面の「サイトのメタデータ」に置けます(サイトのメタデータの参照)。
logo フィールドは 2 つのモードから選択できます。
// デフォルト(KUKAN ロゴ)logo: { type: 'default' }
// 画像ファイル(推奨: 高さ 32〜40px、SVG 形式)logo: { type: 'image', src: '/brand/logo.svg', width: 160, height: 40, alt: '○○市' }i18n メッセージの上書き
Section titled “i18n メッセージの上書き”UI に表示される翻訳テキストを組織ごとに変更できます。brands/default/messages/{locale}.json に上書きしたいキーだけを記述してください。
{ "home": { "title": "○○市オープンデータカタログ", "description": "○○市のオープンデータを検索・活用できるポータル" }}{ "home": { "title": "City of Example Open Data Catalog", "description": "A portal to search and utilize open data from the City of Example" }}- 記述したキーのみ上書きされ、それ以外はデフォルト(
apps/web/messages/{locale}.json)が使われます - ネストされたオブジェクトは再帰的にマージされるため、兄弟キーを再記述する必要はありません
- 利用可能なキーの一覧は
apps/web/messages/ja.jsonを参照してください
brandConfig との使い分け
Section titled “brandConfig との使い分け”| 用途 | 設定場所 |
|---|---|
| ブランド固有の値(サイト名・ナビ項目・著作権表示等) | brand-config.ts(ロケールマップで多言語化可能) |
| 本体 UI の翻訳テキストの上書き | brands/default/messages/{locale}.json |
Tier 3: コンポーネント差し替え
Section titled “Tier 3: コンポーネント差し替え”Header や Footer の構造自体を変更したい場合は、カスタムコンポーネントを作成して差し替えます。
1. カスタムコンポーネントを作成
import { getCurrentUser } from '@/lib/server-api'import { LanguageSwitcher } from '@/components/layout/language-switcher'import { MobileNav } from '@/components/layout/mobile-nav'import { UserMenu } from '@/components/auth/user-menu'
export async function Header() { const user = await getCurrentUser()
return ( <header className="sticky top-0 z-40 bg-[hsl(var(--primary))]"> <div className="mx-auto flex h-[var(--kukan-header-height)] max-w-[var(--kukan-container-max-width)] items-center justify-between px-4"> <img src="/brand/logo.svg" alt="○○市" className="h-8" /> <div className="flex items-center gap-2"> <LanguageSwitcher /> {user && <UserMenu user={user} />} <MobileNav user={user} /> </div> </div> </header> )}2. overrides/index.ts に登録
import type { BrandOverrides } from '@/types/brand'import { Header } from './header'
export const overrides: BrandOverrides = { Header,}これだけで Header が差し替わります。
利用可能なスロット
Section titled “利用可能なスロット”| スロット名 | 差し替え対象 |
|---|---|
Header |
サイトヘッダー全体 |
Footer |
サイトフッター全体 |
TopPage |
トップページ全体 |
デフォルト部品の再利用
Section titled “デフォルト部品の再利用”カスタムコンポーネント内では、本体のデフォルト実装をインポートして部分的に再利用できます。
循環参照を避けるため、Header ではなく DefaultHeader / DefaultFooter を使用してください。
import { DefaultHeader } from '@/components/layout/header'import { DefaultFooter } from '@/components/layout/footer'ブランドテキストの参照
Section titled “ブランドテキストの参照”カスタムコンポーネントで brandConfig のテキスト系フィールド(siteName 等)を表示する場合は、resolveBrandConfig() で解決してから使います。テキスト系フィールドは LocalizedText 型(文字列またはロケールマップ)のため、{brandConfig.siteName} のような直接描画は型エラーになります。
async サーバーコンポーネントでは getLocale() を使います。
import { getLocale } from 'next-intl/server'import { resolveBrandConfig } from '@/lib/resolved-brand'
export async function CustomHeader() { const brand = resolveBrandConfig(await getLocale()) // brand.siteName は現在のロケールで解決済みの string return <span>{brand.siteName}</span>}クライアントコンポーネントでは useLocale() を使います(next-intl/server は import しないでください — server-only のためビルドに失敗します)。useLocale() は非 async のサーバーコンポーネントでも使えます。
'use client'
import { useLocale } from 'next-intl'import { resolveBrandConfig } from '@/lib/resolved-brand'
export function SiteName() { const brand = resolveBrandConfig(useLocale()) return <span>{brand.siteName}</span>}サイトのメタデータの参照
Section titled “サイトのメタデータの参照”人口・世帯数・基準日のように月に一度ほど変わる値は、ブランド設定ではなく管理画面のサイト管理(/dashboard/admin/site)の「サイトのメタデータ」に入れます。値を直すたびにビルドし直す必要はありません。各値は key・種類(数値・文字列・言語別の文字列・日付)・値の組で、どの key を何に使うかはそれを読むコンポーネントが決めます。kukan- で始まる key は本体の予約なので、ブランドではそれ以外を使ってください。
サーバーコンポーネントでは、整形の部品に key を name で渡します。key が無いときや種類が違うときは何も描きません。
import { SiteDate, SiteNumber, SiteText } from '@/components/site-metadata'
export async function PopulationBand() { return ( <dl> <dt>人口</dt> <dd> <SiteNumber name="population" /> </dd> <dt>人口動態(前月比)</dt> <dd> <SiteNumber name="population-change" signed /> </dd> <dd> <SiteDate name="population-as-of" /> </dd> <dd> <SiteText name="tagline" /> </dd> </dl> )}| 部品 | 描くもの |
|---|---|
SiteNumber |
数値を表示言語に合わせた桁区切りで描く。signed で正の値に + を付け、fractionDigits で小数桁を固定 |
SiteDate |
日付を描く。既定は日本語表示なら和暦(令和8年6月1日)、英語表示なら西暦。calendar="gregory" / "japanese" で固定 |
SiteText |
文字列を描く。言語別の文字列は表示言語で選び、無い言語はブランドのテキストと同じ順で補う |
値を組み立てて使うときは、getSiteMetadata() で読み出します。1 リクエストの中で設定を読むのは 1 回だけです。
import { getLocale } from 'next-intl/server'import { getSiteMetadata } from '@/lib/server-api'
const [metadata, locale] = await Promise.all([getSiteMetadata(), getLocale()])metadata.number('population') // number | undefinedmetadata.text('tagline', locale) // string | undefinedmetadata.date('population-as-of') // 'YYYY-MM-DD' | undefinedクライアントコンポーネントで使う
Section titled “クライアントコンポーネントで使う”ここまでの部品と getSiteMetadata() はサーバー専用で、'use client' のファイルからは使えません。タブやカルーセルのように動きのある部品で値を使うときも、サーバー側で読んでから渡します。値が最初の HTML に入るので、読み込み中に表示がちらつかず、ブラウザから設定を読み直すこともありません。
- 値を渡す: サーバーコンポーネントで取り出した値(数値や ISO の日付の文字列)を props で渡す
- 描いたものを渡す:
SiteNumberなどでサーバーが描いた要素を、childrenなどで渡す
// overrides/top-page.tsx — server componentimport { SiteDate, SiteNumber } from '@/components/site-metadata'import { StatsCarousel, StatSlide } from './stats-carousel' // 'use client'
export async function TopPage() { return ( <StatsCarousel> <StatSlide label="人口" asOf={<SiteDate name="population-as-of" />}> <SiteNumber name="population" /> </StatSlide> <StatSlide label="世帯" asOf={<SiteDate name="population-as-of" />}> <SiteNumber name="households" /> </StatSlide> </StatsCarousel> )}値は公開の GET /api/v1/site/settings の metadata に key と値の組で載ります(日付は ISO の文字列)。保存してから、ログインしていない閲覧者に届くまで、AWS では最大で約 90 秒、Docker Compose では最大 30 秒かかります。
ファイルの階層化
Section titled “ファイルの階層化”override が増えた場合、ディレクトリで整理できます。
brands/default/overrides/├── index.ts├── layout/│ ├── header.tsx│ └── footer.tsx└── pages/ └── hero-section.tsxindex.ts で全て集約すれば、内部構造は自由です。
静的ページの追加
Section titled “静的ページの追加”利用規約やプライバシーポリシーなど、組織固有の静的ページを追加できます。
初期状態ではサンプルの利用規約ページ(/terms)が含まれています。不要であれば削除してください。
1. brands/default/pages/ にページコンポーネントを作成
import type { Metadata } from 'next'
export const metadata: Metadata = { title: 'プライバシーポリシー',}
export default function PrivacyPage() { return ( <article className="mx-auto max-w-3xl px-4 py-12"> <h1 className="mb-8 text-2xl font-bold">プライバシーポリシー</h1> <p>...</p> </article> )}2. brands/default/pages/index.ts に登録
export const pages: Record<string, () => Promise<BrandPage>> = { terms: () => import('./terms'), privacy: () => import('./privacy'), // 追加}これで /privacy にアクセスするとページが表示されます。
3. 必要に応じて brand-config.ts の headerNavExtra や footerLinks にリンクを追加
headerNavExtra: [ { label: 'プライバシーポリシー', href: '/privacy' },],footerLinks: [ { label: '利用規約', href: '/terms' }, { label: 'プライバシーポリシー', href: '/privacy' },],ページの削除
Section titled “ページの削除”不要なページは brands/default/pages/index.ts のマップから削除し、対応する .tsx ファイルを削除してください。
静的ファイルの配置
Section titled “静的ファイルの配置”ロゴ、ファビコン、OG 画像などは apps/web/brands/default/public/ に配置します。
apps/web/brands/default/public/├── logo.svg├── favicon.ico└── og-image.png配置したファイルは /brand/logo.svg のような URL で参照できます。
複数ブランド(1 フォークで複数サイト)
Section titled “複数ブランド(1 フォークで複数サイト)”1 つのフォークで複数サイト(マルチサイト運用)を 運用し、サイトごとに見た目を変えたい場合は、ブランドを複数持てます(ADR-042)。
- デフォルトブランドは
apps/web/brands/default/です。新しいブランドはbrands/default/をコピーしてapps/web/brands/<name>/を作り、中身を編集します - ビルド時に
KUKAN_BRAND=<name>を渡すと@/brandの解決先がそのブランドに 切り替わります(未指定ならbrands/default/)。ビルドに入るのは選択した 1 ブランドのみです - AWS では
environments.tsの各サイトにbrand: '<name>'を指定すると、 パイプラインがサイトごとにKUKAN_BRANDを変えて web イメージをビルドします (環境設定リファレンス)。存在しない ブランドを指定するとイメージビルドが失敗します - Docker Compose では web イメージのビルド時に
--build-arg KUKAN_BRAND=<name>を 渡します(マルチサイトではdocker/multi-site/compose.site.ymlのKUKAN_BRANDのコメントを外します) BrandConfig/BrandOverridesの契約と CSS 変数のルールは全ブランド共通です。 各ブランドは値と差し替え部品だけを持ちます
本体更新の取り込み
Section titled “本体更新の取り込み”フォーク側は定期的に本体の main ブランチを取り込んでください。
git remote add upstream https://github.com/kukan-project/kukan.gitgit fetch upstreamgit merge upstream/mainカスタマイズが brands/default/(public/ 含む)に限定されていれば、コンフリクトは原則発生しません。
コンフリクトが発生した場合
Section titled “コンフリクトが発生した場合”本体側が src/types/brand.ts に型を追加した場合、brand-config.ts で新しいフィールドの追加が必要になることがあります。TypeScript の型エラーとして検出されるので、エラーメッセージに従って対応してください。
本体のユニットテストはブランド非依存に設計されており、テスト内では brands/default/ の内容が KUKAN デフォルト値に固定されます。ブランドをどうカスタマイズしても本体のテスト(CI)はそのまま通ります。
- 本体のテストファイルは変更しないでください。カスタマイズによって本体のテストが失敗する場合は、フォーク側で修正せず、本体リポジトリへ issue で報告してください
- カスタムコンポーネント自体のテストは
apps/web/brands/default/__tests__/に配置します(複数ブランドでは各ブランドのbrands/<name>/__tests__/)。*.test.ts/*.test.tsxは自動的に検出され、pnpm testで実行されます。テスト内の@/brandは常にbrands/default/を指すので、ブランドのファイルは相対パス(../overrides/headerなど)で読み込んでください。テストを書くかどうかはフォーク側の裁量です
import { describe, it, expect } from 'vitest'import { render, screen } from '@testing-library/react'import { Header } from '../overrides/header'
describe('Custom Header', () => { it('should render the organization logo', async () => { render(await Header()) expect(screen.getByAltText('○○市')).toBeInTheDocument() })})まとめ: カスタマイズの段階
Section titled “まとめ: カスタマイズの段階”| やりたいこと | 方法 | 所要時間の目安 |
|---|---|---|
| 配色を変えたい | brands/default/theme.css に CSS 変数を記述 |
5 分 |
| 公式トークンにない独自色を使いたい | brands/default/theme.css に --brand-* トークンを定義 |
5 分 |
| サイト名・テキストを変えたい | brands/default/brand-config.ts を編集 |
30 分 |
| UI の翻訳テキストを変えたい | brands/default/messages/{locale}.json に上書きキーを記述 |
10 分 |
| ロゴを差し替えたい | brands/default/public/ に配置 + config 編集 |
10 分 |
| ヘッダー/フッターの構造を変えたい | brands/default/overrides/ にコンポーネント作成 |
数時間 |
| トップページを差し替えたい | brands/default/overrides/ にコンポーネント作成 |
数時間 |
| 静的ページを追加したい | brands/default/pages/ にコンポーネント作成 + 登録 |
30 分 |