124 lines
4.7 KiB
TypeScript
124 lines
4.7 KiB
TypeScript
import { type ComponentType } from 'react';
|
|
import { motion } from 'motion/react';
|
|
import {
|
|
YoutubeFilled,
|
|
InstagramFilled,
|
|
FacebookFilled,
|
|
GlobeFilled,
|
|
VideoFilled,
|
|
MessageFilled,
|
|
CalendarFilled,
|
|
TiktokFilled,
|
|
} from '../icons/FilledIcons';
|
|
import { SectionWrapper } from '../report/ui/SectionWrapper';
|
|
import type { ChannelStrategyCard } from '../../types/plan';
|
|
|
|
interface ChannelStrategyProps {
|
|
channels: ChannelStrategyCard[];
|
|
}
|
|
|
|
const channelIconMap: Record<string, ComponentType<{ size?: number; className?: string }>> = {
|
|
youtube: YoutubeFilled,
|
|
instagram: InstagramFilled,
|
|
facebook: FacebookFilled,
|
|
globe: GlobeFilled,
|
|
video: VideoFilled,
|
|
messagesquare: MessageFilled,
|
|
tiktok: TiktokFilled,
|
|
};
|
|
|
|
function getChannelIcon(icon: string) {
|
|
return channelIconMap[icon.toLowerCase()] ?? GlobeFilled;
|
|
}
|
|
|
|
const priorityStyle: Record<string, string> = {
|
|
P0: 'bg-[#FFF0F0] text-[#7C3A4B] border border-[#F5D5DC] shadow-[2px_3px_8px_rgba(212,136,154,0.15)]',
|
|
P1: 'bg-[#FFF6ED] text-[#7C5C3A] border border-[#F5E0C5] shadow-[2px_3px_8px_rgba(212,168,114,0.15)]',
|
|
P2: 'bg-[#F3F0FF] text-[#4A3A7C] border border-[#D5CDF5] shadow-[2px_3px_8px_rgba(155,138,212,0.15)]',
|
|
};
|
|
|
|
export default function ChannelStrategy({ channels }: ChannelStrategyProps) {
|
|
return (
|
|
<SectionWrapper
|
|
id="channel-strategy"
|
|
title="Channel Strategy"
|
|
subtitle="채널별 커뮤니케이션 전략"
|
|
dark
|
|
>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{channels.map((ch, index) => {
|
|
const Icon = getChannelIcon(ch.icon);
|
|
|
|
return (
|
|
<motion.div
|
|
key={ch.channelId}
|
|
className="bg-white rounded-2xl p-6 shadow-[3px_4px_12px_rgba(0,0,0,0.06)] hover:shadow-[4px_6px_16px_rgba(0,0,0,0.09)] transition-shadow"
|
|
initial={{ opacity: 0, y: 20 }}
|
|
whileInView={{ opacity: 1, y: 0 }}
|
|
viewport={{ once: true }}
|
|
transition={{ duration: 0.5, delay: index * 0.1 }}
|
|
>
|
|
{/* Header */}
|
|
<div className="flex items-center gap-3 mb-4">
|
|
<div className="w-10 h-10 rounded-xl bg-[#F3F0FF] flex items-center justify-center">
|
|
<Icon size={20} className="text-[#9B8AD4]" />
|
|
</div>
|
|
<h4 className="text-lg font-bold text-[#0A1128] flex-1">{ch.channelName}</h4>
|
|
<span
|
|
className={`text-xs font-semibold px-3 py-1 rounded-full ${
|
|
priorityStyle[ch.priority] ?? 'bg-slate-100 text-slate-600'
|
|
}`}
|
|
>
|
|
{ch.priority}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Current → Target */}
|
|
<div className="flex items-center gap-2 mb-4 flex-wrap">
|
|
<span className="bg-[#FFF0F0] text-[#7C3A4B] rounded-full px-3 py-1 text-xs font-medium border border-[#F5D5DC] shadow-[2px_3px_6px_rgba(212,136,154,0.12)]">
|
|
{ch.currentStatus}
|
|
</span>
|
|
<span className="text-slate-400 text-sm">→</span>
|
|
<span className="bg-[#F3F0FF] text-[#4A3A7C] rounded-full px-3 py-1 text-xs font-medium border border-[#D5CDF5] shadow-[2px_3px_6px_rgba(155,138,212,0.12)]">
|
|
{ch.targetGoal}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Content Types */}
|
|
<div className="flex flex-wrap gap-2 mb-4">
|
|
{ch.contentTypes.map((type) => (
|
|
<span
|
|
key={type}
|
|
className="bg-slate-50 border border-slate-100 rounded-full px-3 py-1 text-xs text-slate-600 font-medium shadow-[2px_3px_6px_rgba(0,0,0,0.04)]"
|
|
>
|
|
{type}
|
|
</span>
|
|
))}
|
|
</div>
|
|
|
|
{/* Posting Frequency */}
|
|
<div className="flex items-center gap-2 mb-3">
|
|
<CalendarFilled size={14} className="text-[#9B8AD4] shrink-0" />
|
|
<p className="text-sm text-slate-600">{ch.postingFrequency}</p>
|
|
</div>
|
|
|
|
{/* Tone */}
|
|
<p className="text-sm italic text-[#6C5CE7]/70 mb-4">{ch.tone}</p>
|
|
|
|
{/* Format Guidelines */}
|
|
<ul className="space-y-2">
|
|
{ch.formatGuidelines.map((guideline, i) => (
|
|
<li key={i} className="flex items-start gap-2">
|
|
<span className="shrink-0 w-2 h-2 rounded-full bg-[#6C5CE7] mt-2" />
|
|
<span className="text-sm text-slate-700">{guideline}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</div>
|
|
</SectionWrapper>
|
|
);
|
|
}
|