開発アクティブ
CompanyHeaderコンポーネント共通化計画
進捗状況(2026-01-05確認): 未着手
- ❌
CompanyHeader.vueコンポーネント未作成- ❌
proportional-animation.vueで直接テンプレート展開のまま- ❌
ExportContainer.vueで直接テンプレート展開のまま
背景・課題
proportional-animation-qqq.vueでは、企業情報(企業名・セクター・単位ラベル)を2箇所で表示している:
- メイン表示 (
.company-header): 通常のブラウザ表示用 - エクスポートコンテナ (
.export-header): 動画ダウンロード用(1920x1080)
現状、同じ情報を2箇所で管理しているため、片方を変更するともう片方の変更を忘れやすい。
解決策
企業ヘッダー部分を共通コンポーネント CompanyHeader.vue として切り出す。
新規作成ファイル
apps/web/app/components/financial-quiz/CompanyHeader.vue
<template>
<div class="company-header" :class="sizeClass">
<h2 :id="company.ticker">
{{ company.name }}
</h2>
<div class="sector-row">
<p v-if="company.sector" class="sector-label">
{{ company.sector }}
<span v-if="company.industry"> / {{ company.industry }}</span>
</p>
<span class="unit-label">(単位: ${{ unitSuffix }})</span>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
interface Company {
ticker: string
name: string
sector?: string
industry?: string
}
interface Props {
company: Company
unitSuffix: string // 'B' or 'M'
size?: 'normal' | 'large' // large = エクスポート用
}
const props = withDefaults(defineProps<Props>(), {
size: 'normal'
})
const sizeClass = computed(() => `size-${props.size}`)
</script>
<style scoped>
.company-header {
text-align: center;
}
/* 通常サイズ(メイン表示用) */
.company-header.size-normal h2 {
font-size: 1.3rem;
margin: 0;
color: #333;
}
.company-header.size-normal .sector-row {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
margin-top: 0.25rem;
}
.company-header.size-normal .sector-label {
font-size: 0.8rem;
color: #888;
margin: 0;
}
.company-header.size-normal .unit-label {
font-size: 0.75rem;
color: #666;
font-weight: normal;
}
/* 大サイズ(エクスポート用) */
.company-header.size-large {
margin-bottom: 16px;
}
.company-header.size-large h2 {
font-size: 36px;
font-weight: 700;
margin: 0;
color: #1a1a1a;
}
.company-header.size-large .sector-row {
display: flex;
justify-content: center;
align-items: center;
gap: 1rem;
margin-top: 8px;
}
.company-header.size-large .sector-label {
font-size: 18px;
color: #666;
margin: 0;
}
.company-header.size-large .unit-label {
font-size: 16px;
color: #666;
font-weight: normal;
}
</style>
修正ファイル
apps/web/app/pages/financial-quiz/proportional-animation-qqq.vue
変更前(メイン表示)
<!-- 企業情報 -->
<div class="company-header">
<h2 :id="selectedCompany.ticker">
{{ selectedCompany.name }}
</h2>
<div class="sector-row">
<p v-if="selectedCompany.sector" class="sector-label">
{{ selectedCompany.sector }}
<span v-if="selectedCompany.industry"> / {{ selectedCompany.industry }}</span>
</p>
<span class="unit-label">(単位: ${{ unitSuffix }})</span>
</div>
</div>
変更後(メイン表示)
<!-- 企業情報 -->
<CompanyHeader
:company="selectedCompany"
:unit-suffix="unitSuffix"
size="normal"
/>
変更前(エクスポートコンテナ)
<!-- ヘッダー: 企業情報 -->
<div class="export-header">
<h2>{{ selectedCompany.name }}</h2>
<div class="sector-row">
<p v-if="selectedCompany.sector" class="export-sector">
{{ selectedCompany.sector }}
<span v-if="selectedCompany.industry"> / {{ selectedCompany.industry }}</span>
</p>
<span class="unit-label">(単位: ${{ unitSuffix }})</span>
</div>
</div>
変更後(エクスポートコンテナ)
<!-- ヘッダー: 企業情報 -->
<CompanyHeader
:company="selectedCompany"
:unit-suffix="unitSuffix"
size="large"
/>
CSS削除対象
以下のCSSは CompanyHeader.vue に移動するため、ページから削除:
/* 削除: 企業ヘッダー関連 */
.company-header { ... }
.company-header h2 { ... }
.sector-row { ... }
.sector-label { ... }
.unit-label { ... }
/* 削除: エクスポートヘッダー関連 */
.export-header { ... }
.export-header h2 { ... }
.export-sector { ... }
.export-header .sector-row { ... }
.export-header .unit-label { ... }
実装手順
CompanyHeader.vueを新規作成proportional-animation-qqq.vueのメイン表示部分を<CompanyHeader>に置換- エクスポートコンテナ部分を
<CompanyHeader size="large">に置換 - 不要になったCSSを削除
- ブラウザで表示確認
- 動画エクスポートで表示確認
メリット
- 変更が1箇所で済む(DRY原則)
- 今後の表示項目追加も1箇所で対応可能
- テストしやすい
- 他のページでも再利用可能
注意点
unitSuffixは親コンポーネントで計算して渡す(現状通り)sizepropで表示サイズを切り替えh2のid属性はアンカーリンク用に保持