* chore(docs): .claude配下の再構成 * fix AGENTS.md * fix AGENTS.md * fix review * 行番号参照の除去 * docs: fix storybook note in vue reviewer agent * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix local review * fix --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
9.2 KiB
新規 / 既存 Mk* Vue コンポーネントを追加・改修する
packages/frontend/src/components/ 配下に新規の共有 Vue 3 SFC を追加する、または既存コンポーネントを大きく改修する時の手順。同じ規約をレビュー側からチェックする agent が .claude/agents/vue-component-reviewer.md。
大前提 (事故直結 / Critical)
- SPDX ヘッダー —
.vueは HTML コメント形式<!-- ... -->、.stories.impl.tsは TS コメント形式/* ... */。欠落すると CI (spdxジョブ) が落ちる Mkプレフィックス必須 — 共有コンポーネントはMkButton.vue/global/MkAvatar.vueのようにMkで始める。ページ固有 UI はMkを付けずpages/側に置くlocales/ja-JP.ymlのみ編集可 — i18n キー追加時に他言語 (en-US.yml等) を手で触ってはいけない。Crowdin の自動配信で上書きされて失われる。詳細は tasks/adding-i18n-key.md を参照- 文字列リテラルの直書き禁止 — テンプレート / JS どちらでも、ユーザーに見せる文言は必ず
i18n.ts.<key>かi18n.tsx.<key>(...)経由 → knowledge/i18n-usage.md - ブラウザ標準 UI を直接呼ばない —
alert()/confirm()/window.prompt()は禁止、必ずos.alert/os.confirm/os.popup経由 → knowledge/os-api.md
ファイル配置
| 配置先 | 用途 | 命名 |
|---|---|---|
packages/frontend/src/components/Mk<Name>.vue |
通常の共有 UI コンポーネント | Mk<Name>.vue |
packages/frontend/src/components/global/Mk<Name>.vue |
components/index.ts で Vue グローバルコンポーネント登録 (app.component) され、import 無しで全テンプレートから使える基本部品 (MkA / MkAvatar / MkAcct 等) |
Mk<Name>.vue (サブディレクトリ内でも Mk prefix 必須) |
packages/frontend/src/components/grid/Mk<Name>.vue |
テーブル/グリッド系の部品セット | 同上 |
packages/frontend/src/pages/<Name>.vue |
単一ページ専用の UI (再利用しない) | Mk prefix 不要 |
迷ったら「他の Mk*.vue から import される可能性があるか?」で判定する。Yes なら components/、No なら pages/。
ストーリーが必要 (= ほぼ常に必要) なら、同階層に Mk<Name>.stories.impl.ts も作る → knowledge/storybook.md。
SPDX ヘッダー
.vue ファイル (HTML コメント)
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
/* ... */ (TS / JS 形式) は 使わない。既存の .vue ファイルがすべて HTML コメント形式を採用しており、SFC 先頭として自然な形式に統一するため。
.stories.impl.ts ファイル (TS コメント)
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
最小テンプレート
シンプルな表示コンポーネントの最小形を示す合成例 (特定ファイルの写しではない)。実在する単純コンポーネントの例は MkInfo.vue 等を参照:
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div :class="[$style.root, $style[`variant_${variant}`]]">
<slot></slot>
<button
v-if="closable"
class="_button"
:class="$style.close"
:aria-label="i18n.ts.close"
@click="emit('close')"
>
<i class="ti ti-x"></i>
</button>
</div>
</template>
<script lang="ts" setup>
import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{
variant?: 'info' | 'warn' | 'danger';
closable?: boolean;
}>(), {
variant: 'info',
});
const emit = defineEmits<{
(ev: 'close'): void;
}>();
</script>
<style lang="scss" module>
.root {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 14px;
border-radius: var(--MI-radius);
}
.variant_info {
background: var(--MI_THEME-infoBg);
color: var(--MI_THEME-infoFg);
}
.variant_warn {
background: var(--MI_THEME-infoWarnBg);
color: var(--MI_THEME-infoWarnFg);
}
.variant_danger {
background: var(--MI_THEME-error);
color: var(--MI_THEME-fgOnAccent);
}
.close {
margin-left: auto;
}
</style>
より複雑なケース (型ジェネリック / 2 ブロック script / v-model 連動 / 名前付き slot) は → knowledge/component-conventions.md §テンプレート集。
<script> / <style> 規約サマリ
| 項目 | 規約 | 新規不可 |
|---|---|---|
<script> 開始タグ |
<script lang="ts" setup> または <script setup lang="ts"> |
<script> (lang 無し) / Options API |
| Props 定義 | defineProps<{ ... }>() (type-only) |
runtime object 形式 |
| Emits 定義 | defineEmits<{ (ev: 'click'): void }>() (type-only) |
runtime array 形式 |
<style> 開始タグ |
<style lang="scss" module>、参照は :class="$style.foo" |
<style scoped> (module なし) |
| CSS 値 | var(--MI_THEME-...) / var(--MI-...) |
#fff / rgb(...) のハードコード |
| グローバル class | _button / _panel / _selectable 等を活用 |
— |
| アイコン | Tabler icons クラス <i class="ti ti-info-circle"> |
インライン SVG / 別アイコンセット |
詳細・テンプレート集は → knowledge/component-conventions.md / knowledge/scss-modules.md。
i18n の使い分け
引数なし → i18n.ts.<key> / 引数あり → i18n.tsx.<key>(...)。詳細は → knowledge/i18n-usage.md。
新キー追加が必要なら → tasks/adding-i18n-key.md。
os.* ヘルパー
os.alert / os.confirm / os.popup / os.toast / os.popupMenu 等。詳細は → knowledge/os-api.md。
アクセシビリティ最低ライン
- クリック可能要素は
<button class="_button">を第一選択。やむを得ず<div @click>ならrole="button"+tabindex="0"+@keydown.enter/@keydown.space.preventの 4 点セット必須 - フォーム要素 (
<input>/<select>/<textarea>) は<label>接続もしくはaria-label :disabledバインドとaria-disabledを一致させる。ハンドラ側でも早期 return- キーボードのみで完結できるか確認 (Tab で focus 移動できる / Enter で確定できる)
- ARIA 属性は最小限
詳細チェックリストと既存例 (MkButton.vue / MkSwitch.vue) は → knowledge/component-conventions.md §a11y。
Storybook 併設
共有 Mk* コンポーネントには Mk<Name>.stories.impl.ts を 同階層 に併設する (サブディレクトリ含む)。詳細は → knowledge/storybook.md。
検証フロー
# 型チェック (vue-tsc)
pnpm --filter frontend typecheck
# ESLint (規約全体)
pnpm --filter frontend eslint
# 単一ファイルに ESLint --fix
pnpm exec eslint --fix packages/frontend/src/components/Mk<Name>.vue
# Storybook で目視確認
pnpm --filter frontend storybook-dev # localhost:6006
# Vitest unit test (component spec があれば)
pnpm --filter frontend test
CHANGELOG エントリ
ユーザーから見える変更 (新規コンポーネントが新しい UI として露出する、既存 UI の挙動を変える) なら、CHANGELOG.md に追記する。判定方法と書式は shipping-misskey-change スキル で確認。
既存コンポーネントとの整合性
- 似た用途の既存
Mk*を 1-2 個読んで、props 命名 (primary/danger/small等の形容詞、onCloseではなくemit('close')等) を揃える - グローバル utility class (
_button/_panel/_selectable/_gaps_m) を使えば独自スタイルを書かずに済む → knowledge/scss-modules.md - 大きな機能なら Storybook で各バリエーション (variant / size / disabled / loading) を網羅する
参照コード
- MkInfo.vue — simple SFC 例
- MkButton.vue — 汎用ボタン (a11y /
_buttonglobal class) - MkInput.vue — generic + 2 ブロック script 例
- MkSelect.vue —
defineModel+ 名前付き slot 例 - MkSwitch.vue — a11y 込みカスタム UI
- MkButton.stories.impl.ts — 複数 story Storybook 雛形
- packages/frontend/src/os.ts — UI 操作 API 一覧
- packages/frontend/src/i18n.ts —
i18n.ts/i18n.tsx実装