Skip to content

Commit

Permalink
πŸ’„ ν•™μƒνšŒ UI qa 반영 (#321)
Browse files Browse the repository at this point in the history
  • Loading branch information
Limchansol authored Mar 8, 2025
1 parent 488d544 commit bbf7282
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 134 deletions.
17 changes: 15 additions & 2 deletions app/[locale]/community/council/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import MajorCategoryPageLayout from '@/components/layout/pageLayout/MajorCategoryPageLayout';
import Header from '@/components/layout/header/Header';
import CategoryGrid from '@/components/layout/pageLayout/CategoryGrid';
import PageTitle from '@/components/layout/pageLayout/PageTitle';
import { council } from '@/constants/segmentNode';
import { getMetadata } from '@/utils/metadata';

Expand All @@ -11,5 +13,16 @@ export async function generateMetadata(props: { params: Promise<{ locale: string
}

export default async function CouncilPage() {
return <MajorCategoryPageLayout theme="light" />;
return (
<div className="bg-neutral-850">
<Header />
<PageTitle
title={council.name}
currentPage={council}
titleType="big"
margin="mb-6 sm:mb-11"
/>
<CategoryGrid currentPage={council} theme="light" />
</div>
);
}
140 changes: 140 additions & 0 deletions components/layout/pageLayout/CategoryGrid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
'use client';

import { useTranslations } from 'next-intl';
import { useState } from 'react';

import { SegmentNode } from '@/constants/segmentNode';
import { useRouter } from '@/i18n/routing';
import { getPath } from '@/utils/page';

import ENG_NAMES from '../../../messages/en.json';

// TODO: RootItem을 ν΄λ¦­ν–ˆμ„ λ•Œ LeafItem이 보이도둝 μžλ™ 슀크둀
export default function CategoryGrid({
currentPage,
theme,
}: {
currentPage: SegmentNode;
theme: 'light' | 'dark';
}) {
const t = useTranslations('Nav');

// 학사 및 ꡐ과 λ“±μ—μ„œ μ†ŒλΆ„λ₯˜ 선택 처리용 state
const [selectedCategory, setSelectedCategory] = useState<SegmentNode | null>(null);
const router = useRouter();

return (
<div
className={`${theme === 'light' ? 'bg-white' : 'bg-neutral-900'} px-5 py-7 sm:px-[6.25rem] sm:pb-[11.25rem] sm:pt-20`}
>
<div className="mb-5 grid grid-cols-[repeat(2,_1fr)] gap-9 sm:mb-10 sm:grid-cols-[repeat(auto-fill,_300px)] sm:gap-9">
{currentPage.children!.map((subpage, index) => (
<RootItem
key={index}
title={t(subpage.name)}
onClick={() =>
subpage.isPage ? router.push(getPath(subpage)) : setSelectedCategory(subpage)
}
isSelected={selectedCategory == subpage}
isLight={theme === 'light'}
isPage={subpage.isPage}
/>
))}
</div>

{selectedCategory && !selectedCategory.isPage && (
<div className="grid grid-cols-[repeat(2,_1fr)] gap-5 sm:mb-10 sm:grid-cols-[repeat(auto-fill,_300px)] sm:gap-10">
{selectedCategory.children!.map((subpage, index) => (
<LeafItem
key={index}
title={subpage.name}
onClick={() => router.push(getPath(subpage))}
/>
))}
</div>
)}
</div>
);
}

interface RootItemProps {
title: string;
isPage: boolean;
isSelected?: boolean;
onClick: () => void;
isLight?: boolean;
}

function RootItem({ title, isPage, isSelected, isLight, onClick }: RootItemProps) {
const bgColor = isSelected ? 'bg-main-orange-dark' : isLight ? 'bg-neutral-50' : 'bg-neutral-100';

return (
<DetailItem
title={title}
onClick={onClick}
hasArrow={isPage}
bgColor={bgColor}
hoverColor={isLight ? 'bg-neutral-200' : 'bg-main-orange-dark'}
borderColor={isLight ? 'border-neutral-200' : undefined}
/>
);
}
interface LeafItemProps {
title: string;
onClick: () => void;
}

function LeafItem({ title, onClick }: LeafItemProps) {
return (
<DetailItem
title={title}
onClick={onClick}
hasArrow
bgColor="bg-neutral-400"
hoverColor="bg-neutral-500"
/>
);
}

interface DetailItemProps {
title: string;
hasArrow: boolean;
bgColor: string;
hoverColor?: string;
borderColor?: string;
onClick: () => void;
}

function DetailItem({
title,
hasArrow,
bgColor,
hoverColor,
borderColor,
onClick,
}: DetailItemProps) {
const hoverBgColor = hoverColor ? `hover:${hoverColor}` : 'hover:bg-main-orange-dark';

return (
<div
className={`group h-[96px] sm:h-[160px] ${bgColor} ${borderColor && `border ${borderColor}`} px-[14px] py-[13px] sm:px-7 sm:py-6 ${hoverBgColor} flex cursor-pointer flex-col justify-between duration-300`}
onClick={onClick}
>
<div>
<h3 className="mb-[0.625rem] text-md font-medium text-neutral-800 sm:mb-2.5 sm:text-[20px]">
{title}
</h3>
<p className="text-[11px] text-neutral-800 sm:text-base">
{ENG_NAMES.Nav[title as keyof typeof ENG_NAMES.Nav] ?? ''}
</p>
</div>
{hasArrow && (
<div className="text-end">
<span className="material-symbols-outlined text-[18px] font-extralight text-neutral-800 duration-300 group-hover:translate-x-[10px] sm:text-[32px]">
arrow_forward
</span>
</div>
)}
</div>
);
}
133 changes: 5 additions & 128 deletions components/layout/pageLayout/MajorCategoryPageLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,30 @@
'use client';

import { useTranslations } from 'next-intl';
import { useState } from 'react';

import HTMLViewer from '@/components/form/html/HTMLViewer';
import { SegmentNode } from '@/constants/segmentNode';
import { useRouter } from '@/i18n/routing';
import useCurrentSegmentNode from '@/utils/hooks/useCurrentSegmentNode';
import { getPath } from '@/utils/page';

import ENG_NAMES from '../../../messages/en.json';
import Header from '../header/Header';
import CategoryGrid from './CategoryGrid';

interface GuidePageLayoutProps {
title?: string;
subtitle?: string;
description?: string;
theme?: 'light' | 'dark';
}

// TODO: RootItem을 ν΄λ¦­ν–ˆμ„ λ•Œ LeafItem이 보이도둝 μžλ™ 슀크둀
export default function MajorCategoryPageLayout({
title,
subtitle = '',
description = '',
theme = 'dark',
}: GuidePageLayoutProps) {
const t = useTranslations('Nav');
const currentPage = useCurrentSegmentNode();

// TODO: messages.json에 λ²ˆμ—­ 파일 μΆ”κ°€
title ||= t(currentPage.name);

// 학사 및 ꡐ과 λ“±μ—μ„œ μ†ŒλΆ„λ₯˜ 선택 처리용 state
const [selectedCategory, setSelectedCategory] = useState<SegmentNode | null>(null);
const router = useRouter();

return (
<div className="bg-neutral-850">
<Header />
Expand All @@ -45,48 +34,18 @@ export default function MajorCategoryPageLayout({
{title}
</div>
{description && (
// 웹버전 description
<HTMLViewer
htmlContent={description}
wrapperClassName="mb-6 mt-8 hidden sm:block"
// contentClassName={{ color: '#f5f5f5', maxWidth: 960 }}
contentClassName="!text-[#f5f5f5] max-w-[960px]"
/>
)}
</div>
<div
className={`${theme === 'light' ? 'bg-white' : 'bg-neutral-900'} px-5 pt-7 ${
!description && 'pb-16'
} sm:px-[6.25rem] sm:pb-[11.25rem] sm:pt-20`}
>
<div className="mb-5 grid grid-cols-[repeat(2,_1fr)] gap-9 sm:mb-10 sm:grid-cols-[repeat(auto-fill,_300px)] sm:gap-9">
{currentPage.children!.map((subpage, index) => (
<RootItem
key={index}
title={t(subpage.name)}
onClick={() =>
subpage.isPage ? router.push(getPath(subpage)) : setSelectedCategory(subpage)
}
isSelected={selectedCategory == subpage}
isLight={theme === 'light'}
isPage={subpage.isPage}
/>
))}
</div>

{selectedCategory && !selectedCategory.isPage && (
<div className="grid grid-cols-[repeat(2,_1fr)] gap-5 sm:mb-10 sm:grid-cols-[repeat(auto-fill,_300px)] sm:gap-10">
{selectedCategory.children!.map((subpage, index) => (
<LeafItem
key={index}
title={subpage.name}
onClick={() => router.push(getPath(subpage))}
/>
))}
</div>
)}
</div>
<CategoryGrid currentPage={currentPage} theme="dark" />
{description && (
<div className="px-5 pb-24 pt-6 sm:hidden">
// λͺ¨λ°”일 버전 description
<div className="px-5 pb-14 pt-7 sm:hidden">
<HTMLViewer
htmlContent={description}
contentClassName="!text-[#a3a3a3] font-light text-[13px]"
Expand All @@ -96,85 +55,3 @@ export default function MajorCategoryPageLayout({
</div>
);
}

interface RootItemProps {
title: string;
isPage: boolean;
isSelected?: boolean;
onClick: () => void;
isLight?: boolean;
}

function RootItem({ title, isPage, isSelected, isLight, onClick }: RootItemProps) {
const bgColor = isSelected ? 'bg-main-orange-dark' : isLight ? 'bg-neutral-50' : 'bg-neutral-100';

return (
<DetailItem
title={title}
onClick={onClick}
hasArrow={isPage}
bgColor={bgColor}
hoverColor={isLight ? 'bg-neutral-200' : 'bg-main-orange-dark'}
borderColor={isLight ? 'border-neutral-200' : undefined}
/>
);
}
interface LeafItemProps {
title: string;
onClick: () => void;
}

function LeafItem({ title, onClick }: LeafItemProps) {
return (
<DetailItem
title={title}
onClick={onClick}
hasArrow
bgColor="bg-neutral-400"
hoverColor="bg-neutral-500"
/>
);
}

interface DetailItemProps {
title: string;
hasArrow: boolean;
bgColor: string;
hoverColor?: string;
borderColor?: string;
onClick: () => void;
}

function DetailItem({
title,
hasArrow,
bgColor,
hoverColor,
borderColor,
onClick,
}: DetailItemProps) {
const hoverBgColor = hoverColor ? `hover:${hoverColor}` : 'hover:bg-main-orange-dark';

return (
<div
className={`group h-[96px] sm:h-[160px] ${bgColor} ${borderColor && `border ${borderColor}`} px-[14px] py-[13px] sm:px-7 sm:py-6 ${hoverBgColor} flex cursor-pointer flex-col justify-between duration-300`}
onClick={onClick}
>
<div>
<h3 className="mb-[0.625rem] text-md font-medium text-neutral-800 sm:mb-2.5 sm:text-[20px]">
{title}
</h3>
<p className="text-[11px] text-neutral-800 sm:text-base">
{ENG_NAMES.Nav[title as keyof typeof ENG_NAMES.Nav] ?? ''}
</p>
</div>
{hasArrow && (
<div className="text-end">
<span className="material-symbols-outlined text-[18px] font-extralight text-neutral-800 duration-300 group-hover:translate-x-[10px] sm:text-[32px]">
arrow_forward
</span>
</div>
)}
</div>
);
}
6 changes: 4 additions & 2 deletions components/layout/pageLayout/SubNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useTranslations } from 'next-intl';

import { CurvedVerticalNode } from '@/components/common/Nodes';
import NavLabel from '@/components/layout/navbar/NavLabel';
import { SegmentNode } from '@/constants/segmentNode';
import { council, SegmentNode } from '@/constants/segmentNode';
import { Link } from '@/i18n/routing';
import useStyle from '@/utils/hooks/useStyle';
import { getAllSubTabs, getDepth, getPath, getRootTab } from '@/utils/page';
Expand All @@ -20,7 +20,9 @@ const INDENTATION = 16;
export default function SubNavbar({ currentTab }: { currentTab: TreeNode }) {
const t = useTranslations('Nav');
const rootTab = getRootTab(currentTab as SegmentNode);
const subTabs = getAllSubTabs(rootTab);
// ν•™μƒνšŒ ν•˜μœ„ 탭은 μ„œλΈŒλ‚΄λΉ„ λ…ΈμΆœ X
const subTabs = getAllSubTabs(rootTab).filter((tab) => tab.parent !== council);

const height = `${(subTabs.length + 1) * ITEM_HEIGHT}px`;

return (
Expand Down
2 changes: 0 additions & 2 deletions utils/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ export const getRootTab = (currTab: SegmentNode): SegmentNode => {
};

export const getAllSubTabs = (rootTab: SegmentNode): SegmentNode[] => {
if (!rootTab.children) return [];

const subtabs: SegmentNode[] = [];
for (const subtab of rootTab.children) {
subtabs.push(subtab);
Expand Down

0 comments on commit bbf7282

Please sign in to comment.