전 채널 브랜드 일관성 분석
+전 채널 브랜드 일관성 분석
+ > + ) : null}+
{subtitle}
) : null} diff --git a/src/features/home/constants/cta_contents.ts b/src/features/home/content/cta.ts similarity index 100% rename from src/features/home/constants/cta_contents.ts rename to src/features/home/content/cta.ts diff --git a/src/features/home/constants/hero_contents.ts b/src/features/home/content/hero.ts similarity index 100% rename from src/features/home/constants/hero_contents.ts rename to src/features/home/content/hero.ts diff --git a/src/features/home/constants/modules_contents.ts b/src/features/home/content/modules.ts similarity index 100% rename from src/features/home/constants/modules_contents.ts rename to src/features/home/content/modules.ts diff --git a/src/features/home/constants/problem_contents.ts b/src/features/home/content/problem.ts similarity index 100% rename from src/features/home/constants/problem_contents.ts rename to src/features/home/content/problem.ts diff --git a/src/features/home/constants/process_contents.ts b/src/features/home/content/process.ts similarity index 100% rename from src/features/home/constants/process_contents.ts rename to src/features/home/content/process.ts diff --git a/src/features/home/constants/solution_contents.ts b/src/features/home/content/solution.ts similarity index 100% rename from src/features/home/constants/solution_contents.ts rename to src/features/home/content/solution.ts diff --git a/src/features/home/constants/use_cases_contents.ts b/src/features/home/content/useCases.ts similarity index 100% rename from src/features/home/constants/use_cases_contents.ts rename to src/features/home/content/useCases.ts diff --git a/src/features/home/ui/CTASection.tsx b/src/features/home/ui/CTASection.tsx index 1f125ff..728c631 100644 --- a/src/features/home/ui/CTASection.tsx +++ b/src/features/home/ui/CTASection.tsx @@ -5,7 +5,7 @@ import { CTA_FOOTNOTE, CTA_HEADLINE, CTA_URL_PLACEHOLDER, -} from "@/features/home/constants/cta_contents"; +} from "@/features/home/content/cta"; import { useAnalyze } from "@/features/home/hooks/useAnalyze"; import { useInView } from "@/hooks/useInView"; diff --git a/src/features/home/ui/HeroSection.tsx b/src/features/home/ui/HeroSection.tsx index 752acef..3e6cb2e 100644 --- a/src/features/home/ui/HeroSection.tsx +++ b/src/features/home/ui/HeroSection.tsx @@ -7,7 +7,7 @@ import { HERO_LEAD_EN, HERO_LEAD_KO, HERO_URL_PLACEHOLDER, -} from "@/features/home/constants/hero_contents"; +} from "@/features/home/content/hero"; import { useAnalyze } from "@/features/home/hooks/useAnalyze"; export function HeroSection() { diff --git a/src/features/home/ui/ProblemSection.tsx b/src/features/home/ui/ProblemSection.tsx index f8e86e0..7df2d8b 100644 --- a/src/features/home/ui/ProblemSection.tsx +++ b/src/features/home/ui/ProblemSection.tsx @@ -1,4 +1,4 @@ -import { PROBLEM_CARDS, PROBLEM_CARD_STAGGER } from "@/features/home/constants/problem_contents"; +import { PROBLEM_CARDS, PROBLEM_CARD_STAGGER } from "@/features/home/content/problem"; import { useInView } from "@/hooks/useInView"; export function ProblemSection() { diff --git a/src/features/home/ui/SolutionSection.tsx b/src/features/home/ui/SolutionSection.tsx index 476dbeb..5117eaa 100644 --- a/src/features/home/ui/SolutionSection.tsx +++ b/src/features/home/ui/SolutionSection.tsx @@ -1,4 +1,4 @@ -import { SOLUTION_CARDS } from "@/features/home/constants/solution_contents"; +import { SOLUTION_CARDS } from "@/features/home/content/solution"; import { useInView } from "@/hooks/useInView"; export function SolutionSection() { diff --git a/src/features/home/ui/SystemSection.tsx b/src/features/home/ui/SystemSection.tsx index 2f027cb..c676294 100644 --- a/src/features/home/ui/SystemSection.tsx +++ b/src/features/home/ui/SystemSection.tsx @@ -1,4 +1,4 @@ -import { CORE_MODULES, MODULE_CARD_STAGGER } from "@/features/home/constants/modules_contents"; +import { CORE_MODULES, MODULE_CARD_STAGGER } from "@/features/home/content/modules"; import { useInView } from "@/hooks/useInView"; import { CoreModuleCard } from "./system/CoreModuleCard"; import { CoreModulesCenterHeading } from "./system/CoreModulesCenterHeading"; diff --git a/src/features/home/ui/UseCaseSection.tsx b/src/features/home/ui/UseCaseSection.tsx index 3dd69f6..ab3d32c 100644 --- a/src/features/home/ui/UseCaseSection.tsx +++ b/src/features/home/ui/UseCaseSection.tsx @@ -1,5 +1,5 @@ import CheckCircleIcon from "@/assets/home/check-circle.svg?react"; -import { USE_CASE_CARDS } from "@/features/home/constants/use_cases_contents"; +import { USE_CASE_CARDS } from "@/features/home/content/useCases"; import { useInView } from "@/hooks/useInView"; export function UseCaseSection() { diff --git a/src/features/home/ui/process/AgdpEngineDiagram.tsx b/src/features/home/ui/process/AgdpEngineDiagram.tsx index 01abb4d..6432a50 100644 --- a/src/features/home/ui/process/AgdpEngineDiagram.tsx +++ b/src/features/home/ui/process/AgdpEngineDiagram.tsx @@ -1,4 +1,4 @@ -import { AGDP_NODES } from "@/features/home/constants/process_contents"; +import { AGDP_NODES } from "@/features/home/content/process"; import { AgdpOrbitNode } from "./AgdpOrbitNode"; import { AgdpRewardPathLabel } from "./AgdpRewardPathLabel"; diff --git a/src/features/home/ui/process/AgdpOrbitNode.tsx b/src/features/home/ui/process/AgdpOrbitNode.tsx index eb139d0..5703f6f 100644 --- a/src/features/home/ui/process/AgdpOrbitNode.tsx +++ b/src/features/home/ui/process/AgdpOrbitNode.tsx @@ -1,5 +1,5 @@ -import type { AgdpNodeDef } from "@/features/home/constants/process_contents"; -import { AGDP_SLOT_WRAPPER_CLASS } from "@/features/home/constants/process_contents"; +import type { AgdpNodeDef } from "@/features/home/content/process"; +import { AGDP_SLOT_WRAPPER_CLASS } from "@/features/home/content/process"; type Props = { node: AgdpNodeDef }; diff --git a/src/features/home/ui/system/CoreModuleCard.tsx b/src/features/home/ui/system/CoreModuleCard.tsx index c0dc52a..198131f 100644 --- a/src/features/home/ui/system/CoreModuleCard.tsx +++ b/src/features/home/ui/system/CoreModuleCard.tsx @@ -1,4 +1,4 @@ -import type { CoreModule } from "@/features/home/constants/modules_contents"; +import type { CoreModule } from "@/features/home/content/modules"; type Props = { mod: CoreModule; diff --git a/src/features/plan/config/planSections.ts b/src/features/plan/config/planSections.ts new file mode 100644 index 0000000..8175e6a --- /dev/null +++ b/src/features/plan/config/planSections.ts @@ -0,0 +1,14 @@ +/** + * SubNav·IntersectionObserver와 각 섹션 `id`가 일치해야 합니다. + * (`DEMO/src/pages/MarketingPlanPage.tsx`의 PLAN_SECTIONS와 동일) + */ +export const PLAN_SECTIONS = [ + { id: "branding-guide", label: "브랜딩 가이드" }, + { id: "channel-strategy", label: "채널 전략" }, + { id: "content-strategy", label: "콘텐츠 전략" }, + { id: "content-calendar", label: "콘텐츠 캘린더" }, + { id: "asset-collection", label: "에셋 수집" }, + { id: "my-asset-upload", label: "My Assets" }, +] as const; + +export type PlanSectionId = (typeof PLAN_SECTIONS)[number]["id"]; diff --git a/src/features/plan/hooks/useCurrentMarketingPlan.ts b/src/features/plan/hooks/useCurrentMarketingPlan.ts new file mode 100644 index 0000000..916290b --- /dev/null +++ b/src/features/plan/hooks/useCurrentMarketingPlan.ts @@ -0,0 +1,11 @@ +import { useParams } from "react-router-dom"; +import { useMarketingPlan } from "@/features/plan/hooks/useMarketingPlan"; + +/** + * 현재 `plan/:id` 라우트의 마케팅 플랜. + * Zustand 등 전역 소스로 바꿀 때는 이 훅만 수정하면 섹션들은 그대로 둘 수 있습니다. + */ +export function useCurrentMarketingPlan() { + const { id } = useParams<{ id: string }>(); + return useMarketingPlan(id); +} diff --git a/src/features/plan/hooks/useMarketingPlan.ts b/src/features/plan/hooks/useMarketingPlan.ts new file mode 100644 index 0000000..35c0b5e --- /dev/null +++ b/src/features/plan/hooks/useMarketingPlan.ts @@ -0,0 +1,20 @@ +import { useMemo } from "react"; +import { MOCK_PLAN } from "@/features/plan/mocks/plan"; +import type { MarketingPlan } from "@/features/plan/types/marketingPlan"; + +type UseMarketingPlanResult = { + data: MarketingPlan | null; + isLoading: boolean; + error: string | null; +}; + +/** + * Phase 1: 항상 `MOCK_PLAN` 반환. + * `_planRouteId`는 `plan/:id`·추후 API 조회에 사용 예정(현재 목만 반환). + */ +export function useMarketingPlan(_planRouteId: string | undefined): UseMarketingPlanResult { + return useMemo( + () => ({ data: MOCK_PLAN, isLoading: false, error: null }), + [], + ); +} diff --git a/src/features/plan/hooks/usePlanSubNav.ts b/src/features/plan/hooks/usePlanSubNav.ts new file mode 100644 index 0000000..efd36f3 --- /dev/null +++ b/src/features/plan/hooks/usePlanSubNav.ts @@ -0,0 +1,52 @@ +import { useEffect, useMemo, useState } from "react"; +import { useMainSubNav } from "@/layouts/MainSubNavLayout"; +import type { SubNavItem } from "@/layouts/SubNav"; +import { PLAN_SECTIONS } from "@/features/plan/config/planSections"; + +export function usePlanSubNav() { + const { setSubNav } = useMainSubNav(); + const [activeId, setActiveId] = useState+ INFINITH가 브랜딩부터 콘텐츠 제작, 채널 배포까지 자동화합니다. +
+ +{asset.description}
+ + {asset.repurposingSuggestions.length > 0 ? ( ++ Repurposing → +
+Repurpose As:
+{ch.channel}
+ + {brandingChannelStatusLabel(ch.currentStatus)} + +Profile Photo
+{ch.profilePhoto}
+Banner Spec
+{ch.bannerSpec}
+Bio Template
+{ch.bioTemplate}
+{tone.communicationStyle}
+{example}
+{example}
+{swatch.hex}
+{swatch.name}
+{swatch.usage}
+{spec.family}
++ {spec.sampleText} +
++ {spec.weight} + {" · "} + {spec.usage} +
+{rule.rule}
+{rule.description}
+{ch.postingFrequency}
+{ch.tone}
+ +{week.label}
+{entry.title}
+{pillar.description}
+{output.format}
+{output.channel}
+{output.description}
+{step.description}
++ Marketing Execution Plan +
+ +{clinicNameEn}
+ +파일을 드래그하거나 클릭하여 업로드
++ Image, Video, Text 파일 지원 (JPG, PNG, MP4, MOV, TXT, PDF, DOC 등) +
+ +{asset.name}
+{asset.size}
+