🔧 UI 개선: 푸터 정리, X 아이콘, 스케줄 디자인 개선, min-width 설정

This commit is contained in:
caadiq 2025-12-31 22:02:32 +09:00
parent e2c1a6a774
commit 12c58c622e
5 changed files with 63 additions and 73 deletions

2
.env
View file

@ -2,7 +2,7 @@
DB_HOST=mariadb DB_HOST=mariadb
DB_PORT=3306 DB_PORT=3306
DB_USER=fromis9 DB_USER=fromis9
DB_PASSWORD=Xk9#mP2$vL7@nQ4w DB_PASSWORD="Xk9#mP2\$vL7@nQ4w"
DB_NAME=fromis9 DB_NAME=fromis9
# Server # Server

View file

@ -1,20 +1,23 @@
import { Instagram, Youtube, Twitter } from 'lucide-react'; import { Instagram, Youtube } from 'lucide-react';
import { socialLinks } from '../../data/dummy'; import { socialLinks } from '../../data/dummy';
// X (Twitter)
const XIcon = ({ size = 24 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
);
function Footer() { function Footer() {
const currentYear = new Date().getFullYear();
return ( return (
<footer className="bg-gray-900 text-white py-12"> <footer className="bg-gray-900 text-white py-12">
<div className="max-w-7xl mx-auto px-6"> <div className="max-w-7xl mx-auto px-6">
<div className="grid grid-cols-3 gap-8"> <div className="grid grid-cols-3 gap-8">
{/* 로고 및 설명 */} {/* 로고 */}
<div> <div>
<h3 className="text-2xl font-bold text-primary-light mb-4">fromis_9</h3> <h3 className="text-2xl font-bold text-primary-light mb-4">fromis_9</h3>
<p className="text-gray-400 text-sm leading-relaxed">
인사드리겠습니다. , !<br />
이제는 약속해 소중히 간직해,<br />
당신의 아이돌로 성장하겠습니다!<br />
안녕하세요, 프로미스나인입니다.
</p>
</div> </div>
{/* 링크 */} {/* 링크 */}
@ -51,9 +54,9 @@ function Footer() {
href={socialLinks.twitter} href={socialLinks.twitter}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-400 hover:text-blue-400 transition-colors" className="text-gray-400 hover:text-white transition-colors"
> >
<Twitter size={24} /> <XIcon size={24} />
</a> </a>
</div> </div>
</div> </div>
@ -61,8 +64,7 @@ function Footer() {
{/* 저작권 */} {/* 저작권 */}
<div className="border-t border-gray-800 mt-8 pt-8 text-center text-sm text-gray-500"> <div className="border-t border-gray-800 mt-8 pt-8 text-center text-sm text-gray-500">
<p>© 2025 fromis_9 Fan Site. This is an unofficial fan-made website.</p> <p>© {currentYear} fromis_9 Fan Site. This is an unofficial fan-made website.</p>
<p className="mt-1">All rights belong to PLEDIS Entertainment / HYBE.</p>
</div> </div>
</div> </div>
</footer> </footer>

View file

@ -1,7 +1,14 @@
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { Instagram, Youtube, Twitter } from 'lucide-react'; import { Instagram, Youtube } from 'lucide-react';
import { socialLinks } from '../../data/dummy'; import { socialLinks } from '../../data/dummy';
// X (Twitter)
const XIcon = ({ size = 20 }) => (
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
);
function Header() { function Header() {
const navItems = [ const navItems = [
{ path: '/', label: '홈' }, { path: '/', label: '홈' },
@ -58,9 +65,9 @@ function Header() {
href={socialLinks.twitter} href={socialLinks.twitter}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="text-gray-500 hover:text-blue-500 transition-colors" className="text-gray-500 hover:text-black transition-colors"
> >
<Twitter size={20} /> <XIcon size={20} />
</a> </a>
</div> </div>
</div> </div>

View file

@ -9,6 +9,11 @@ body {
color: #1a1a1a; color: #1a1a1a;
} }
/* 최소 너비 설정 - 화면 축소시 깨짐 방지 */
#root {
min-width: 1200px;
}
/* 스크롤바 스타일 */ /* 스크롤바 스타일 */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 8px; width: 8px;

View file

@ -1,5 +1,5 @@
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { Calendar, Clock, MapPin, Users } from 'lucide-react'; import { Clock, MapPin, Users } from 'lucide-react';
import { schedules } from '../../data/dummy'; import { schedules } from '../../data/dummy';
function Schedule() { function Schedule() {
@ -45,79 +45,55 @@ function Schedule() {
</motion.p> </motion.p>
</div> </div>
{/* 스케줄 타임라인 */} {/* 스케줄 리스트 */}
<div className="max-w-4xl mx-auto"> <div className="max-w-4xl mx-auto space-y-4">
{Object.entries(groupedSchedules).map(([date, daySchedules], groupIndex) => { {Object.entries(groupedSchedules).map(([date, daySchedules], groupIndex) => {
const formatted = formatDate(date); const formatted = formatDate(date);
return ( return daySchedules.map((schedule, index) => (
<motion.div <motion.div
key={date} key={schedule.id}
initial={{ opacity: 0, x: -30 }} initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, x: 0 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: groupIndex * 0.1 }} transition={{ delay: (groupIndex * daySchedules.length + index) * 0.1 }}
className="relative pl-24 pb-12 last:pb-0" className="flex items-stretch bg-white rounded-2xl shadow-sm hover:shadow-md transition-shadow overflow-hidden"
> >
{/* 타임라인 라인 */} {/* 날짜 영역 */}
<div className="absolute left-[44px] top-0 bottom-0 w-0.5 bg-gray-200" /> <div className="w-24 bg-primary flex flex-col items-center justify-center text-white py-6">
<span className="text-sm font-medium opacity-80">{formatted.month}</span>
{/* 날짜 원 */} <span className="text-3xl font-bold">{formatted.day}</span>
<div className="absolute left-0 top-0 w-[88px] flex items-start"> <span className="text-sm font-medium opacity-80">{formatted.weekday}</span>
<div className="w-12 h-12 rounded-full bg-primary text-white flex flex-col items-center justify-center text-sm font-bold">
<span className="text-xs">{formatted.month}</span>
<span>{formatted.day}</span>
</div>
<span className="ml-2 mt-3 text-sm text-gray-400">{formatted.weekday}</span>
</div> </div>
{/* 스케줄 카드들 */} {/* 스케줄 내용 */}
<div className="space-y-4"> <div className="flex-1 p-6">
{daySchedules.map((schedule, index) => ( <h3 className="font-bold text-lg mb-3">{schedule.title}</h3>
<div
key={schedule.id}
className="bg-white rounded-2xl p-6 shadow-md hover:shadow-lg transition-shadow"
>
<h3 className="font-bold text-lg mb-3">{schedule.title}</h3>
<div className="flex flex-wrap gap-4 text-sm text-gray-500"> <div className="flex flex-wrap gap-4 text-sm text-gray-500">
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<Clock size={14} className="text-primary" /> <Clock size={14} className="text-primary" />
<span>{schedule.time}</span> <span>{schedule.time}</span>
</div>
<div className="flex items-center gap-1">
<MapPin size={14} className="text-primary" />
<span>{schedule.platform}</span>
</div>
<div className="flex items-center gap-1">
<Users size={14} className="text-primary" />
<span>{schedule.members.join(', ')}</span>
</div>
</div>
</div> </div>
))} <div className="flex items-center gap-1">
<MapPin size={14} className="text-primary" />
<span>{schedule.platform}</span>
</div>
<div className="flex items-center gap-1">
<Users size={14} className="text-primary" />
<span>{schedule.members.join(', ')}</span>
</div>
</div>
</div> </div>
</motion.div> </motion.div>
); ));
})} })}
</div> </div>
{/* 빈 스케줄 메시지 (스케줄이 없을 때) */} {/* 빈 스케줄 메시지 */}
{Object.keys(groupedSchedules).length === 0 && ( {Object.keys(groupedSchedules).length === 0 && (
<div className="text-center py-20"> <div className="text-center py-20">
<Calendar size={64} className="mx-auto text-gray-300 mb-4" />
<p className="text-gray-500">예정된 스케줄이 없습니다.</p> <p className="text-gray-500">예정된 스케줄이 없습니다.</p>
</div> </div>
)} )}
{/* 안내 */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 }}
className="mt-12 bg-gray-50 rounded-2xl p-6 text-center text-sm text-gray-500"
>
<p>스케줄은 DC Inside 갤러리에서 자동으로 수집됩니다.</p>
<p className="mt-1">일정은 변경될 있으니 공식 채널을 확인해 주세요.</p>
</motion.div>
</div> </div>
</div> </div>
); );