dido-frontend-nuxt について
Dido の Nuxt 4 フロントエンド向けコーディング規約スキルで、Claude Code による実装や保守を対象とします。Vue、SCSS、コンポーネント、i18n、設定を扱い、Dido の Nuxt starter kit を実装の基準にします。
主な機能
- 01Nuxt フロントエンド規約
- 02Vue とコンポーネント構成
- 03SCSS とデザインシステムの規則
- 04i18n と設定のガイド
- 05Figma デザインの確認手順
活用シーン
- 01Dido の starter kit からサイトを構築
- 02Vue コンポーネントを統一した規則で作成
- 03Figma デザインをレスポンシブ UI に反映
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ didomarchet/ dido-skills --skill dido-frontend-nuxtインストール後、Claude Code で/dido-frontend-nuxtを入力して読み込まれたか確認します。
同梱ファイルriferimento/chiamate-al-backend.mdriferimento/skill-di-terzi.md
詳細
Dido の Nuxt フロントエンド
Dido の Nuxt フロントエンドの進め方です。必要なスキル: dido-code-style。すべてのスタックに共通する原則が記載されています。ここではフロントエンド固有の内容だけを扱います。
参照実装: Dido の Nuxt 4 ボイラープレート(GitHub の DidoMarchet/starter-kit-nuxt-webapp)。新しいサイトはここを起点とし、composable、plugin、設定のコードもここで確認します。ボイラープレートの内容(すでに接続されているもの、モジュール、レンダリング、SCSS システム)は、docs/project-architecture.md と docs/scss-system.md に記載されています。
ボイラープレートを起点とするプロジェクトでは、機械で確認できるルールは lint(eslint.starter.mjs、stylelint.starter.mjs)で確認します。Claude Code がファイルを書くたび、およびすべての commit の前に実行してください。プロジェクト(コードではなく、その CLAUDE.md やドキュメント)にこのスキルと異なる記述がある場合は、プロジェクトの記述を優先し、その違いをレポートで報告してください。どちらかの情報源を修正する必要があります。
| 変更しようとしているもの | 読むもの |
|---|---|
| Dido のバックエンドへの呼び出し:ログイン、トークン、エラー | riferimento/chiamate-al-backend.md |
| admin(Tailwind を使用する SPA) | 末尾の「Admin」セクション |
dido-* 以外のスキル(デザイン、GSAP、DatoCMS、Vue、FormKit など) | riferimento/skill-di-terzi.md |
原則
- デザインシステムを組み合わせて使います。 マージンと padding にはユーティリティクラス、gap にはトークン、幅には行(
.row-*)を使います。既存のタイポグラフィ、ボタン、カードを再利用し、独自のスペーシングは使いません。 - 実用的なトークンを使います。 トークンは番号付きクラスとして公開される SCSS 変数であり、形式的なデザイントークンシステムではありません。一度しか使わない値は使う箇所に記述し、繰り返し使う値だけをトークンにします。
- 値のルールを守ります。 レイアウト寸法を含む数値は整数または5の倍数、フォントサイズは2または4の倍数にします。プロジェクトに Figma がある場合は、値をそこから取得し、独自に作らず、丸めます。スケールのトークンでも5の倍数でもない値は、近いほうに丸めます(67 → 65、17 → 16)。このスキルのルールはレイアウトより優先されるため、それによってフレームと差が生じてもエラーではありません。
- Figma を使います。 Figma がある場合は、実装前に MCP で確認し(構造、値、該当ノードのスクリーンショット)、コンテンツボックス、gap、padding を計測します。記憶に頼ってはいけません。
- テキストは行から離します。 テキスト、見出し、CTA を、画面上に見える行(背景グリッドの行、縦の区切り線)に接する位置に配置してはいけません。Figma で行に揃えてある場合でも、プロジェクトのトークンをクラスで適用し、行から最低限の padding を確保します。画像は行に接してもかまいません。
- 落ちるのではなく、段階的に機能を制限します。 データや設定がない場合は、フォールバック、メッセージ、セクションの非表示など、適切に処理された状態にします。ページ全体をエラーにしてはいけません。例外はページの主要コンテンツです。CMS が応答しない場合、ページは 500 を返し、コンテンツがない場合は 404 を返します。SSR では、存在しない可能性があるオブジェクトのプロパティを読み取るとページ全体が失敗するため、読み取り箇所で安全な値を指定します(
config?.chiave ?? default)。
JS と Vue
- Arrow function を使い、名前は省略せず、
console.logは使いません。dido-code-style の「コードの形式」を参照してください。 - 常に
<script setup>を使い、Options API は使いません。コンポーネント名は Nuxt がパスから決めます(components/widget/media-text/index.vueはWidgetMediaText)。そのため、defineOptions({ name })は使いません。 - DOM、スクロール、アニメーションに関するエフェクトは composable(
app/composables/、useX)に置きます。composable は状態とアクションを公開し、マークアップは含めません。純粋なロジックはテストとともにapp/utils/に置きます。クエリと呼び出しは専用のフォルダーに置き、コンポーネント内には書きません。 - template に静的なテキストを記述しません。ブランド名は config(
siteName)、ラベルは i18n、コンテンツは CMS から取得します。
命名
- ファイルとフォルダー名は常に kebab-case にします(
widget/media-text)。テンプレート内のタグは PascalCase のままにします(<WidgetMediaText>)。自動インポートがパスを連結するためです。 - Composable は
useX、ユーティリティには動作を表す名前(buildTrack、isLightHex)、必要に応じてプラグインには環境を示すサフィックス(*.client.js)を付けます。 - BEM クラス:ブロックは
.componente、要素は__elemento、修飾子は--modificatoreです。バリエーションにはセクション名またはブランド名を使い、色名は使いません(--darkではなく--footer)。 - 番号付きタイポグラフィスケールは一つだけにします(
.title-1…4、.text-1…3)。異なる命名規則を併用してはいけません。 - 色はファミリーごとにスケール化します(
$black-1、$grey-2)。意味ベースの色名にはしません。ID は必要な場合(アンカー、aria-*、JS)に限り、kebab-case にします。大文字表示にはtext-transformを使い、テキスト自体を大文字にしてはいけません。
コンポーネント
- コンポーネントは
components/<area>/<nome>/に配置するフォルダーで、index.vue、style.scss、そのアセットを含みます。ドメイン別(article/、navigation/)にまとめます。 widget/に置くのは、特定の用途に依存せず再利用可能なコンポーネントだけです。すべてを prop で受け取り、slot を公開します。カルーセルのように繰り返し使うパターンは、widget として一つだけ作ります。特定のセクション専用のコンポーネントは、そのエリアに置きます。- 同じ種類の要素は、サイト全体で同じ動作にします。繰り返し使うパターンは一つだけにし、ページごとに独自の操作方法を持たせてはいけません。カルーセルや横スクロールする行は、内容にかかわらず、同じ方法でドラッグ、スクロール、矢印キーへの応答を行います。カード、下線、ホバー、フェード、画像の切り替えもすべて、同じイージングと押下時の状態で同じように動作します。コンポーネントのファイルには、そのコンポーネント固有のものだけを含めます。繰り返し使うもの(動作、ホバー、下線、ポインター、モーションの値)は、それを担う widget、composable、mixin、またはグローバルクラスに一度だけ定義し、コンポーネント側ではそれを使用します。
.vue内の順序は、<template>、<script setup>、<style lang="scss" src="./style.scss"></style>です。スタイルは scoped にしません。- コンポーネントが使用するのは、自身のブロックとデザインシステムのクラスだけです。他のコンポーネントとは prop、イベント、slot、またはストアを介して連携し、相手の DOM を検索してはいけません。スタイルはコンポーネントと一緒に読み込まれます。他のコンポーネントのクラスは、そのコンポーネントを削除したとき、またはそのコンポーネントが存在しないページでは適用されません。
- 恒久的なアセットは
app/assets/img/に、SEO を意識した説明的な kebab-case の名前(<azienda>-logo.svg)で配置し、プレースホルダーは別のフォルダーに置きます。<img>ではパスをsrcに指定し、importは URL が JS で終わる場合にのみ使用します。アイコンは画像として使う SVG とし、別ファイルまたはmaskで色を変更します。
SCSS
- 各
style.scssと各 partial の先頭には、CSS を出力せずにトークンと mixin を提供する toolbox を記述します:@use "~/assets/styles/scss/core" as *;。これはadditionalDataからも読み込まれますが、先頭に記述するとファイル単体で内容を把握しやすくなります。 coreが@forwardしていないトークンは、それを使うファイルでは利用できません。新しいファイルをvars/またはmixins/に追加した場合は、_index.scssにも追加する必要があります。- 流動的な値には
slamp(min, max)を使います。ビューポートの範囲はプロジェクトごとに一度設定し、異なる範囲を使う場合に限り明示的に渡します。 - フォントサイズと大きな余白は常に流動的にします:スケール内の見出し、コンポーネントに直接記述する 40px 以上のフォントサイズ、80px 以上の margin、padding、gap、
top、bottomが対象です。最大値は Figma のデスクトップ版から、最小値は Figma のモバイル版で同じ要素に指定された値から取得します。モバイル版のフレームがない場合は、最小値を推定します(およそ半分にしてから丸めます)。react("large")でのみ変化していた値は、2 つの値の間を補間するslampにします。本文テキストと小さなスペースのトークンは固定値のままにします。見出しの負の字間はemで指定し、フォントサイズに合わせて縮小させます。 - コントロールとカードはモバイルからデスクトップまで一緒に拡大縮小させます。共有する流動的なトークン(コントロールの高さとテキスト、カードの padding とタイトル、CTA の高さ)は少数に絞り、Figma の 1920px での値を使って、すべてのコンポーネントで共有します。コンパクトになったコンポーネントの横に、デスクトップサイズのままのコンポーネントを残してはいけません。
- Dido の指示がある場合を除き、左右の margin と padding は固定値にしません。ページの margin は、モバイルからデスクトップまでプロジェクトのトークンを使った
slampにします(例:$side-margin: slamp($grid-gutter, $grid-margin))。また、Figma のデスクトップ版で固定幅の広いカラムは、デスクトップ未満では幅を狭めます。1920px の値を固定すると、1024px では margin と両側のカラムがコンテンツのためのスペースを圧迫します。 - メディアクエリには
@include react("chiave")(large、<medium)を使い、>=を直接記述してはいけません。hover は常にreact("pointer-and-hover")の内側に置き、タッチ操作で状態が残らないようにします。 - クリック可能な要素にはすべて hover を設定し、サイトのトランジション(トークンで指定する duration とサイト共通の easing)を使います。Figma で指定されていても、瞬時に切り替えてはいけません。「閉じる」「フィルター」やリンクなどのアクションテキストにはすべて、プロジェクト共通のアニメーション付き下線を適用します。通常時から下線があるものは、線を引き直すアニメーションにします。また hover 時にはテキストの色調を変えます。アイコンボタンは色を暗くするか背景を付け、塗りつぶしボタンは同じ色を少し暗くします。押下時(
:active)にも同じ状態を適用します。タッチ操作では、これがタップへのフィードバックになります。プロジェクトの mixin で hover と押下時の状態をまとめて指定し、塗りつぶしボタンは少し縮小します(0,97)。reduced motion では固定したままにします。基本設定として、-webkit-tap-highlight-colorは使用せず、リンクとボタンにはtouch-action: manipulationを設定し、ボタンのテキストは選択できないようにします。 - 背景に溶け込ませる画像(
mix-blend-mode)では、その画像にもコンテナにもopacity、filter、transformのアニメーションを適用してはいけません。ブラウザーがトランジション用に新しいレイヤーを作成すると、白い背景とともに画像がちらつくためです。表示時には背景色のベールを画像の上でフェードさせ、色だけをアニメーションさせます。アイコンの色はfilterではなく、maskとcurrentcolorで変更します。 - 見出しの横に置く「閉じる」「確認」などのアクションテキストは、見出しより一段小さくし、ベースラインを揃えます。そうすることで見出しと混同されません。別々のカラムで同じ行に並ぶタイトル(名前と、その横の最初のカード)は、どちらかが流動的な場合も含めてベースラインを揃えます。
- ボタンによるアクション(リンクのコピーなど)の完了通知は、そのボタンに付けたツールチップで表示し、吹き出しの先端をボタンに向けます。離れた位置に通知を表示してはいけません。
- パネル、ドロワー、モーダルは、常に最初の状態から開き直します:スクロール位置を先頭に戻し、前回の状態をリセットします。最も簡単な方法は、開くたびに
:keyを使って再マウントすることです。 - モバイルでカードから選ぶ場合は、横にスクロールする列ではなく、全幅の縦リストにします。スマートフォンでは横方向に並んでいると、何を選んでいるのか分かりにくくなります。
- mixin ではなくクラスを使います:トークンはスケールに対する
@eachで数値付きクラスに生成し、適切なレイヤー(layout/、typo/)に配置します。mixin は、レスポンシブ用ヘルパーやリンクのアニメーション付き下線などのインタラクション動作にのみ使います。 - margin と padding にはクラスを使い、
gapはコンポーネントのスタイル内でトークンを使い、幅には.row-*を使います。ページ全体の背景は、内側に row を配置したセクションとして作成します。 - Motion にはサイト共通の easing を 1 つだけ使い、期間は
vars/_timings.scssにある$speed-*トークンで指定します。
i18n
- テキストは
$tを通して取得し、テンプレート内で言語による三項演算子は使いません。 - 辞書は領域ごとに分けます。言語ごとにフォルダーを用意し、領域ごとにファイルを分け、言語のエントリーでは文字列を含めずにモジュールをまとめます。領域別ファイルのインポートには
~~エイリアスが必要です。相対パスでは@nuxtjs/i18nv10 が読み込めないためです。 - 言語間で辞書の構成をそろえます。新しい文字列は同じキー、同じ領域で、すべての言語に追加します。単一のファイルは最初のセクションで分割し、それより後で分割してはいけません。
- ローカライズされたスラッグは i18n の設定(
pages)に記述します。2つの言語でスラッグが同じ場合も、各ページをここで宣言してください。宣言しないとサイトマップに含まれません。動的スラッグには言語ごとのパラメーターを設定し、hreflang と canonical が正しいスラッグを指すようにします。
設定
nuxt.config.tsはconfiguration/の各領域の設定をスプレッドするだけにします。設定は該当する領域のファイルで変更します。設定ファイルを変更しても開発サーバーは再起動しません。- 環境変数とシークレットは
process.envから読み込むruntimeConfigで扱い、コンポーネントには直接記述しません。runtimeConfig.publicの内容はクライアントのバンドルに含まれるため、CMS の読み取り専用トークンなど、公開しても問題ない値だけを設定します。 robotsとnoindexは環境に応じて設定し、本番環境のみをインデックス対象にします。
データとサードパーティー
- CMS の読み取りには
useGraphql()だけを使用し、クエリとフラグメントはapp/graphql/<cms>/に配置します。内部では Nuxt のuseAsyncDataと@datocms/cda-clientのexecuteQueryを使います。CMS クライアントをインポートするのはuseGraphql()とサーバー側のデータソースだけです。REST の呼び出しにはuseApiFetch()を使います。ページやコンポーネントから CMS クライアントや HTTP クライアントを直接呼び出してはいけません。 - CMS エラーはページが存在しないことを意味するわけではありません。コンテンツがない場合に限り 404 を返し、それ以外のページエラーは 500 を返します。
- ページの SEO と hreflang には
useSeo()を使います。ローカライズされたスラッグにはgenerateSeoLocaleParamsとsetI18nParamsが必要です。これらがないと、alternate に存在しない URL が指定されます。 useLenis()はレイアウトまたはapp.vueでアプリごとに一度だけ初期化します。独自にスクロールする各コンテナー(モーダルのシート、ドロワー、ドロップダウンメニュー、フィルターパネル)には、ページと同じ滑らかなスクロールを設定します。専用の Lenis を GSAP のティッカーで動かします。Lenis は最初の子要素のサイズが変わるとスクロール可能な量を再計算するため、コンテナーの子要素は1つだけにします。Lenis がdata-lenis-preventを探すのは自身のコンテナー内だけです。上に開いている別のモーダルから届くイベントでスクロールが動かないようにします。- サイト全体で使うサードパーティーサービス(分析、エラートラッキング、同意管理)はプラグインにします。ページやコンポーネント単位で使うサービス(フォーム、予約ウィジェット、プレーヤー)は、処理用のコンポーザブルとマークアップ用のコンポーネントに分けます。
- サードパーティーのライブラリをインポートするのは、そのプラグインまたはコンポーザブルだけにします。対応する設定がなければ何もしない構成にします。不要になったら、これらのファイル、依存関係、使用箇所を削除すれば取り除けます。GraphQL エラーをエラートラッキングに渡すなど、サイトから情報を受け取る必要がある場合は、サードパーティー側からフック(
useGraphql()がエラー時に呼び出すgraphql:errorやvue:error)に接続します。 - 埋め込みコンテンツにはデザインシステムを適用します。サービス独自の CSS は使わず、ボタンにはプロジェクトのクラスを使います。サービスが
<iframe>で表示する場合はスタイルを適用できないため、対応を約束する前に確認します。 - サードパーティーについて説明する前に、どのドメインに接続し、どの Cookie を書き込むかを計測します。
- サイトマップなどのサーバー側の動的データソースは、
useGraphql()を使わず、サーバーから専用クライアントでサービスを呼び出します。サービスが求める場合はページネーションを行い、呼び出しに失敗してもビルドを中断しません。詳細ページを持つモデルは、各言語をクエリしてサイトマップに含めます。 - CMS のスキーマは、サンドボックスでテストしたバージョン管理対象のマイグレーションでのみ変更します。サンドボックスであっても手動で変更してはいけません。
Motion
- アニメーションにはGSAPを使います。入場と退場、モーダル、シートとドロワー、ドロップダウン、タブ、スクロール時の表示、シーケンス、マイクロインタラクションが対象です。CSSに残すのは、ボタンやリンクのホバーと押下(色、背景、下線、押したときの縮小)だけです。
- アニメーションはコンポーネント単位で作成します。繰り返し使う動きは、composable(
useXMotion)またはウィジェットに一度だけ定義し、各コンポーネントが独自のタイムラインを書くのではなく、それを再利用します。モーダルはGSAPによる入場と退場を備えた単一のウィジェットで、シート、ドロワー、検索で使います。コンテンツ間のフェードは単一のラッパー、つまりGSAPのフックを使う<Transition :css="false">にまとめます。 - コンポーネントのアニメーションは、その要素をスコープとして
gsap.context()内で作成し、アンマウント時にrevert()で解除します。アニメーションが動作するのはクライアント側だけで、onMounted以降です。 - 開くときと閉じるときは、
play()とreverse()を使う同じタイムラインを使います。キーボード(Esc)で閉じる場合も同様です。開いている途中で閉じた場合は、最初からやり直さず、現在の位置から戻ります。切り替えを構成するすべての要素(空になるヘッダーと表示される検索)は、同じタイムラインにまとめます。CSSとGSAPに分けることはありません。 - サイト全体でイージングは一種類、長さはトークンで管理します。線形にするのは、スクロールに連動する動きと、連続ループ(マーキー、ローダー)だけです。ピン留めにはJSではなく
position: stickyを使います。 - イージング、長さ、スタガーはSCSSトークン(
vars/_timings.scssの$ease-site、$speed-*、$stagger)だけに定義し、JSからはSCSSモジュールを使って読み込みます。JSに数値を重複して記述してはいけません。クライアントプラグインでGSAPのプラグインを登録し、サイトのイージングと基本の長さをgsap.defaultsに一度だけ設定します。 - スクロールに連動する動き(パララックス、テキストの点灯、隠れるヘッダー)には、Lenisに接続したScrollTriggerを使い、同じフレーム内で更新されるようにします。スクロールを制御する操作(アンカー、「トップに戻る」)には
lenis.scrollToを使い、window.scrollToや別のスクロールシステムは使いません。慣性にはGSAPを使います。 - ポップオーバーやドロップダウンは、ボタンから開くようにします(
transformOriginをボタン側に設定)。最初のツールチップが表示された後は、ポインターがその場にある間、続くツールチップは遅延なく表示します。ドラッグできる要素(シート、カルーセル)は、ジェスチャーの速度に応じて閉じるかスクロールし、端では抵抗がかかるようにします。GSAPのDraggableとInertiaPluginを使います。 - すべてのアニメーションは画面のリフレッシュレート(毎秒60または120フレーム)で動作し、カクつきがありません。
- 動かしたり拡大したりする際は
transformとopacity(x、y、scale、rotation、autoAlpha)だけを使い、width、top、margin、paddingは使いません。高さをアニメーションさせるのは、下のコンテンツを移動させる必要がある場合(アコーディオン)だけとし、小さなブロックに限ります。clip-pathとfilterは、小さな領域で、transformでは実現できない場合だけ使います。 - 動きの途中で変わらない値(
transformPerspective、transformOrigin)は、事前にgsap.setで固定します。GSAPはto()の中でこれらをゼロからアニメーションさせるため、最初のフレームで形状が跳ねます。 - GSAPはメインスレッドで動作するため、アニメーション中はスレッドに余裕を持たせます。開始前にコンテンツをマウントして計測します(読み取りをすべて行ってから書き込みを行います)。画像はあらかじめ読み込んでおき、同時にVueが大きな再描画を行わないようにします。
will-changeは動く領域にだけ設定します。同じ要素が複数ある場合はトークンでスタガーを設定し、ポインターに追従する値にはgsap.quickToを使います。- GSAPを遅くして(
gsap.globalTimeline.timeScale(0.1))、フレームを一つずつ確認します。フレーム間で形状が跳ねないことを確かめます。
- 動かしたり拡大したりする際は
- モーダルのベールは、面と同じタイムラインでアニメーションさせる要素にします。GSAPは
::backdropをアニメーションできず、透明のままだからです。シートやドロワーはフェードさせずにスライドさせ、<dialog>にはoverflow: clipを指定します。これがないと、面が外から入るときにスクロールバーが表示されます。hiddenは使いません。コードからスクロールできるためです。面とともにまだ画面外にあるコンテンツにshowModal()がフォーカスを設定すると、ダイアログがそこまでスクロールし、面はGSAPで移動中にもかかわらず、すでに本来の位置に表示されます。 - 画面を横切る動き(シート、ドロワー、パネル)の長さは、移動距離に応じて決めます。基準となるトークン(例:1000pxに対して
$speed-medium)に距離の平方根を適用し、トークンで定義された二つの長さの間に収めます。モバイルでは短く、デスクトップでは長くします。 - あるコンテンツが別のコンテンツに切り替わって表示される場合(タブ、
v-showを使うパネル)は、突然切り替えるのではなく、フェード用ラッパーでフェードインさせます。 - 入場アニメーションのあるモーダルの面には
will-change: transformを指定します。アニメーション終了時にブラウザーがそのレイヤーを破棄すると、最初の再描画(最初のホバー時)にテキストや画像がちらつくためです。 - ギャラリーでは、画像をすべて同じ枠内に重ねて配置し、現在の画像だけを表示します。切り替え時には、新しい画像がすでに読み込まれている状態にします。必ず
NuxtImgを使います。 prefers-reduced-motionは必ず尊重します。アニメーションするスケールや移動は使わず、最大でもフェードにとどめます。ナビゲーション中に設定が変わる可能性があるため、アニメーション開始時に読み取ります。- 画像のホバー時のズームは使いません。使うとしても、オーバーレイかテキストまでにとどめます。
アクセシビリティとSEO
- 装飾画像には
alt=""を、情報を伝える画像には内容を説明するaltを設定します。SEOを意識したファイル名を付け、適切な場合はloading="lazy"とdecoding="async"を使用します。 - ページごとに
<h1>は1つだけにし、見出しを順番に並べ、セマンティックなマークアップとランドマークを使用します。 - コントラスト比はWCAG AA以上(4.5:1、大きなテキストは3:1)にします。基準を満たさない組み合わせは、黙って選ぶのではなく指摘します。
:focus-visibleを使って、:focusとは区別できるフォーカス表示を設けます。- 非同期アクションの結果は、フォーカスをメッセージに移動して通知します(
tabindex="-1"と.focus())。ライブリージョンが機能するのは、コンテンツが変わる前からDOMに存在している場合だけです。 <noscript>内はテキストだけにし、補間は1つだけにして、CSSにdisplayを指定しません。JavaScriptが有効な場合、ブラウザーは内容をテキストとして読み取るため、タグを入れるとハイドレーションの不一致が発生します。- 画像のサイズは幅に合わせて調整し、高さを固定しません(
block-size: auto、または適切に選んだobject-fitを適用するボックスを使用します)。
検証
dido-code-styleで求められる内容に加えて、以下を実施します。
- 変更したファイルのJSとCSSのlintをエラーなしにします。
- 変更したページが200を返し、コンソールとログにエラーがないことを確認します。ハイドレーションの不一致も含みます。
- 変更したユーティリティのテストをすべて成功させます。
- 変更した箇所の各要素を、サイト内の類似要素と比較します(カルーセルはカルーセル、カードはカード、リンクはリンク)。ドラッグ、ホバー、押下、トランジションを含め、同じコンポーネントと動作にします。
- 変更したインターフェースを、プロジェクトのデザインスキル(存在する場合はimpeccable、design-taste-frontend、mobile-native)を使って、375、768、1024、1440、1920で確認します。コンテンツが読みやすく、バランスが取れていて、使いやすいことを確認します。壊れていないだけでは不十分です。
- サードパーティを変更した場合は、ドメインとCookieを測定します。
- 新しいサードパーティを導入した場合、その環境変数がなくてもページが200を返すようにします。
Admin
starterkit-backend-admin から作成されたAdmin(SPA、ssr: false)には、スタックが異なる箇所を除き、このスキルを適用します。
- スタイル:SCSS、
slamp、reactの代わりに、app/assets/styles/main.cssの@themeトークンとdocs/design-system.mdのパターンを使ったTailwindを使用します。色には役割を表す名前(--color-ink、--color-surface)を付け、フォントにはtitle-1…2、text-1…3のスケールを使います。クラスに色やサイズを直接記述しません。サイズはlintで指摘されます。 - 設定:
configuration/のsliceを使わず、nuxt.config.tsは1つだけにします。 - モーション:
docs/design-system.mdの指示に従い、motion-reduceを使ったTailwindのトランジションを使用します。GSAPは使いません。 - テキスト:複数の言語に対応するAdminの場合に限りi18nを使用します。1言語だけの場合、テキストはテンプレートに記述します。
- サイトと統一する点:コードの形式、
<script setup>、ブロックの順序、kebab-caseのファイル名とフォルダー名、コンポーネントごとのフォルダー、useApi()(riferimento/chiamate-al-backend.md)を使ったバックエンド呼び出し。例外として、ログインとパスワードのリセットではuseApiUrl()を使って直接fetchします。この場合、401はセッション切れではなく、認証情報が誤っていることを意味します。