Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ProfileCard component & Team Page #106

Merged
merged 10 commits into from
Jan 27, 2025
Merged
8 changes: 5 additions & 3 deletions nextjs-app/app/about/team/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import Breadcrumb from "@/components/common/Breadcrumb";
import MarqueeTitle from "@/components/common/MarqueeTitle";
import ContentWithFilter from "@/components/pages/team/ContentWithFilter";
import type { Metadata } from "next";

export const metadata: Metadata = {
title: "團隊成員",
title: "執行團隊",
};

export default async function TeamPage() {
return (
<div>
<Breadcrumb items={["HOME", "關於曼陀號", "團隊成員"]} />
<MarqueeTitle zhTitle="團隊成員" enTitle="Team" />
<Breadcrumb items={["HOME", "關於曼陀號", "執行團隊"]} />
<MarqueeTitle zhTitle="執行團隊" enTitle="Team" />
<ContentWithFilter />
</div>
);
}
84 changes: 84 additions & 0 deletions nextjs-app/components/common/ProfileCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import Image from "next/image";
import { Team } from "@/types";
import { teamDisplayTextMap } from "@/constants/teamDisplayTextMap";
import type { FC } from "react";

interface IProfileCardProps {
team: Team;
name: string;
title: string;
subTitle: string[];
quote: string;
imageUrl: string;
hashTags?: string[];
}

const ProfileCard: FC<IProfileCardProps> = ({
name,
quote,
title,
subTitle,
imageUrl,
hashTags = [],
team,
}) => {
const hasTags = hashTags.length > 0;
const { zhGroupName, enGroupName } = teamDisplayTextMap[team];

return (
<div className="px-5 py-9 rounded-3 bg-blue-1 flex flex-col gap-7 text-center">
<div>
<p className="text-neutral-10 text-h5">{zhGroupName}</p>
<p className="text-neutral-10 text-subtitle-lg">{enGroupName}</p>
</div>

<div className="px-2">
<div className="w-full h-[330px] rounded-circle relative overflow-hidden">
<Image
src={imageUrl}
alt={name}
fill
className="object-cover object-center"
/>
</div>
</div>

<div className="flex flex-col gap-3">
<div>
<p className="text-h5 text-neutral-10">{title}</p>
<div className="flex flex-col">
{subTitle.map((sub) => (
<p
key={`${name}-${sub}`}
className="text-subtitle-lg text-neutral-10"
>
{sub}
</p>
))}
</div>
</div>

<p className="py-3 border-t-[1px] border-b-[1px] border-yellow-6 text-h3 text-yellow-6">
{name}
</p>

<p className="px-5 py-2 text-subtitle-lg text-yellow-6">{quote}</p>

{hasTags && (
<div className="pt-3 flex flex-wrap justify-center items-center gap-3">
{hashTags.map((tag) => (
<p
key={`${name}-${tag}`}
className="px-4 py-2 rounded-pill bg-blue-2 text-body-sm"
>
{"#" + tag}
</p>
))}
</div>
)}
</div>
</div>
);
};

export default ProfileCard;
2 changes: 1 addition & 1 deletion nextjs-app/components/pages/faq/ContentWithFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const ContentWithFilter = () => {
};

return (
<div className="container space-y-10 px-5 md:px-10 mb-10">
<div className="container space-y-10 px-5 md:px-10 xl:px-0 mb-[112px] md:mb-[120px]">
<TagFilter
filterOptions={FAQ_FILTER_OPTIONS}
selectedFilter={selectedFilter}
Expand Down
77 changes: 77 additions & 0 deletions nextjs-app/components/pages/team/ContentWithFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"use client";

import { useState } from "react";
import TagFilter from "@/components/common/TagFilter/TagFilter";
import ProfileCard from "@/components/common/ProfileCard";
import {
EXECUTION_GROUP,
EXECUTION_GROUP_FILTER_OPTIONS,
} from "@/constants/pages/teams";
import { ExecutionGroupType } from "@/types/filter-option";

type FilterOptionType = ExecutionGroupType | "all";

const ContentWithFilter = () => {
const [selectedFilter, setSelectedFilter] = useState<FilterOptionType>("all");

const filteredOptions = EXECUTION_GROUP_FILTER_OPTIONS.filter(({ key }) =>
selectedFilter === "all" ? key !== "all" : key === selectedFilter
);

const handleSelect = (selectedOption: FilterOptionType) => {
setSelectedFilter(selectedOption);
};

return (
<div className="container space-y-10 px-5 md:px-10 xl:px-0 mb-[112px] md:mb-[120px]">
<TagFilter
filterOptions={EXECUTION_GROUP_FILTER_OPTIONS}
selectedFilter={selectedFilter}
onSelect={(selectedFilter) => {
handleSelect(selectedFilter as FilterOptionType);
}}
/>

{filteredOptions.map(({ key, name: groupName }) => {
const profileList = EXECUTION_GROUP[key as ExecutionGroupType];

return (
<div key={key}>
<div className="mb-9 relative after:content-[''] after:absolute after:bottom-0 after:rounded-2 after:block after:w-[260px] after:h-[3px] after:bg-yellow-6">
<p className="py-4 text-h3 text-blue-8 border-b-[1px] border-neutral-2">
{groupName}
</p>
</div>

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-7 ">
{profileList.map(
({
team,
name,
title,
subTitle,
quote,
imageUrl,
hashTags,
}) => (
<ProfileCard
key={name}
team={team}
name={name}
title={title}
subTitle={subTitle}
quote={quote}
imageUrl={imageUrl}
hashTags={hashTags}
/>
)
)}
</div>
</div>
);
})}
</div>
);
};

export default ContentWithFilter;
2 changes: 1 addition & 1 deletion nextjs-app/constants/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const navigationMenu: IMenuItem[] = [
},
{
href: Routes.ABOUT.TEAM,
title: "團隊介紹",
title: "執行團隊",
},
],
},
Expand Down
1 change: 1 addition & 0 deletions nextjs-app/constants/pages/faq.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FAQType } from "@/types/filter-option";

export const FAQ_FILTER_OPTIONS: {
key: FAQType | "all";
name: string;
Expand Down
Loading
Loading