diff --git a/nextjs-app/app/about/team/page.tsx b/nextjs-app/app/about/team/page.tsx index 9c3fa29..0011af4 100644 --- a/nextjs-app/app/about/team/page.tsx +++ b/nextjs-app/app/about/team/page.tsx @@ -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 (
- - + + +
); } diff --git a/nextjs-app/components/common/Button/RegisterNavigatorButton.tsx b/nextjs-app/components/common/Button/RegisterNavigatorButton.tsx index 1d6dcb7..68c1b42 100644 --- a/nextjs-app/components/common/Button/RegisterNavigatorButton.tsx +++ b/nextjs-app/components/common/Button/RegisterNavigatorButton.tsx @@ -18,6 +18,7 @@ const RegisterNavigatorButton: FC<{ className: string }> = ({ className }) => (
icon-navigator = ({ className }) => (
icon-navigator = ({ + name, + quote, + title, + subTitle, + imageUrl, + hashTags = [], + team, +}) => { + const hasTags = hashTags.length > 0; + const { zhGroupName, enGroupName } = teamDisplayTextMap[team]; + + return ( +
+
+

{zhGroupName}

+

{enGroupName}

+
+ +
+
+ {name} +
+
+ +
+
+

{title}

+
+ {subTitle.map((sub) => ( +

+ {sub} +

+ ))} +
+
+ +

+ {name} +

+ +

{quote}

+ + {hasTags && ( +
+ {hashTags.map((tag) => ( +

+ {"#" + tag} +

+ ))} +
+ )} +
+
+ ); +}; + +export default ProfileCard; diff --git a/nextjs-app/components/common/ReviewCard.tsx b/nextjs-app/components/common/ReviewCard.tsx index 0100f7e..a367388 100644 --- a/nextjs-app/components/common/ReviewCard.tsx +++ b/nextjs-app/components/common/ReviewCard.tsx @@ -11,6 +11,7 @@ const ReviewCard: FC = ({ imageSrc, name, team, role, review }) => ( src={imageSrc} alt="profile" fill + sizes="42px" className="w-full h-full object-cover" />
diff --git a/nextjs-app/components/pages/faq/ContentWithFilter.tsx b/nextjs-app/components/pages/faq/ContentWithFilter.tsx index 9dc5706..d2cfc72 100644 --- a/nextjs-app/components/pages/faq/ContentWithFilter.tsx +++ b/nextjs-app/components/pages/faq/ContentWithFilter.tsx @@ -19,7 +19,7 @@ const ContentWithFilter = () => { }; return ( -
+
{ src={avatar} alt={`${lastName} ${firstName}`} fill + sizes="319px" />
diff --git a/nextjs-app/components/pages/team/ContentWithFilter.tsx b/nextjs-app/components/pages/team/ContentWithFilter.tsx new file mode 100644 index 0000000..c75f233 --- /dev/null +++ b/nextjs-app/components/pages/team/ContentWithFilter.tsx @@ -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/team"; +import { ExecutionGroupType } from "@/types/filter-option"; + +type FilterOptionType = ExecutionGroupType | "all"; + +const ContentWithFilter = () => { + const [selectedFilter, setSelectedFilter] = useState("all"); + + const filteredOptions = EXECUTION_GROUP_FILTER_OPTIONS.filter(({ key }) => + selectedFilter === "all" ? key !== "all" : key === selectedFilter + ); + + const handleSelect = (selectedOption: FilterOptionType) => { + setSelectedFilter(selectedOption); + }; + + return ( +
+ { + handleSelect(selectedFilter as FilterOptionType); + }} + /> + + {filteredOptions.map(({ key, name: groupName }) => { + const profileList = EXECUTION_GROUP[key as ExecutionGroupType]; + + return ( +
+
+

+ {groupName} +

+
+ +
+ {profileList.map( + ({ + team, + name, + title, + subTitle, + quote, + imageUrl, + hashTags, + }) => ( + + ) + )} +
+
+ ); + })} +
+ ); +}; + +export default ContentWithFilter; diff --git a/nextjs-app/constants/header.ts b/nextjs-app/constants/header.ts index c9a3a04..2b2c325 100644 --- a/nextjs-app/constants/header.ts +++ b/nextjs-app/constants/header.ts @@ -25,7 +25,7 @@ export const navigationMenu: IMenuItem[] = [ }, { href: Routes.ABOUT.TEAM, - title: "團隊介紹", + title: "執行團隊", }, ], }, diff --git a/nextjs-app/constants/pages/faq.ts b/nextjs-app/constants/pages/faq.ts index 563f8cf..9055c12 100644 --- a/nextjs-app/constants/pages/faq.ts +++ b/nextjs-app/constants/pages/faq.ts @@ -1,4 +1,5 @@ import { FAQType } from "@/types/filter-option"; + export const FAQ_FILTER_OPTIONS: { key: FAQType | "all"; name: string; diff --git a/nextjs-app/constants/pages/team.ts b/nextjs-app/constants/pages/team.ts new file mode 100644 index 0000000..4337657 --- /dev/null +++ b/nextjs-app/constants/pages/team.ts @@ -0,0 +1,238 @@ +import { Role, Team } from "@/types"; +import { ExecutionGroupType } from "@/types/filter-option"; + +// Captain +import SteveAvatar from "@/public/images/execution-group/Steve.png"; +import BrownAvatar from "@/public/images/execution-group/Brown.png"; +import BryanAvatar from "@/public/images/execution-group/Bryan.png"; +import SidneyAvatar from "@/public/images/execution-group/Sidney.png"; +import GordonAvatar from "@/public/images/execution-group/Gordon.png"; +import DukiAvatar from "@/public/images/execution-group/Duki.png"; +// Navigator +import JoannAvatar from "@/public/images/execution-group/Joann.png"; +import MilaAvatar from "@/public/images/execution-group/Mila.png"; +import JudyAvatar from "@/public/images/execution-group/Judy.png"; +import KyleAvatar from "@/public/images/execution-group/Kyle.png"; +import AliceAvatar from "@/public/images/execution-group/Alice.png"; +import ClaireAvatar from "@/public/images/execution-group/Claire.png"; +import PattyAvatar from "@/public/images/execution-group/Patty.png"; +import HarperAvatar from "@/public/images/execution-group/Harper.png"; +// Assistant +import MartinAvatar from "@/public/images/execution-group/Martin.png"; +import LizzyAvatar from "@/public/images/execution-group/Lizzy.png"; + +import { roleDisplayTextMap } from "../role-display-text-map"; + +export const EXECUTION_GROUP_FILTER_OPTIONS: { + key: ExecutionGroupType | "all"; + name: string; +}[] = [ + { key: "all", name: "全部" }, + { key: Role.HARBOUR_PILOT, name: roleDisplayTextMap[Role.HARBOUR_PILOT] }, + { key: Role.CAPTAIN, name: roleDisplayTextMap[Role.CAPTAIN] }, + { key: Role.ASSISTANT, name: roleDisplayTextMap[Role.ASSISTANT] }, +]; + +interface IProfileInfo { + team: Team; + name: string; + title: string; + subTitle: string[]; + quote: string; + imageUrl: string; + hashTags?: string[]; +} + +export const EXECUTION_GROUP: Record = { + [Role.CAPTAIN]: [ + { + team: Team.BD, + name: "蘇書平 Steve Sue", + title: "先行智庫", + subTitle: ["董事長暨執行長"], + quote: + "現在你是誰並不重要,重要的是未來你想成為誰。 讓我們一起成為更好的自己", + imageUrl: SteveAvatar.src, + hashTags: [ + "商業開發", + "新商機挖掘", + "渠道銷售", + "直接銷售", + "客戶關係管理", + "售前技術支持", + ], + }, + { + team: Team.DATA, + name: "賴柏龍 Brown Lai", + title: "韓商電商平台", + subTitle: ["Principal Business Analyst"], + quote: + "You can’t connect the dots looking forward; you can only connect them looking backwards.", + imageUrl: BrownAvatar.src, + hashTags: [ + "產品分析", + "用戶行為分析", + "資料視覺化", + "Storytelling", + "跨團隊溝通", + "建立數據指標體系", + "跨產業經驗 (金融、社群、電商)", + ], + }, + { + team: Team.ENGINEER, + name: "楊立偉 Bryan Yang", + title: "顧職", + subTitle: ["外商技術主管 & 顧職創辦人"], + quote: "Be kind", + imageUrl: BryanAvatar.src, + hashTags: [ + "軟體架構與開發", + "後端與資料系統設計", + "DevOps", + "軟體專案管理", + ], + }, + { + team: Team.MKT, + name: "黃馨儀 Sidney Huang", + title: "TutorABC", + subTitle: ["Marketing VP"], + quote: "每天都比昨天進步一點點", + imageUrl: SidneyAvatar.src, + hashTags: [ + "資源整合", + "跨部門及產業協作", + "溝通協調", + "行銷公關", + "媒體訊息策略", + "品牌定位", + ], + }, + { + team: Team.PM, + name: "張智翔 Gordon Chang", + title: "漸強實驗室", + subTitle: ["產品長"], + quote: "Change is inevitable. Growth is optional.", + imageUrl: GordonAvatar.src, + hashTags: [ + "產品策略規劃", + "產品開發流程", + "用戶需求挖掘", + "產品規格撰寫", + "OKR 制定落實", + "領導力與團隊文化", + ], + }, + { + team: Team.UIUX, + name: "姜虹伊 Duki Chiang", + title: "Gamania", + subTitle: ["Product Design Lead"], + quote: + "以假設驗證的思維,從未知中找尋解決問題的秩序,並讓有序的事物變得有趣好玩!", + imageUrl: DukiAvatar.src, + hashTags: [ + "產品體驗設計策略", + "創意工作坊規劃", + "原型概念設計", + "介面設計與設計系統", + "跨職能設計溝通", + ], + }, + ], + [Role.HARBOUR_PILOT]: [ + { + team: Team.BD, + name: "陳孟真 Joann Chen", + title: "第七屆 BD 引水人", + subTitle: ["第六屆 BD 水手"], + quote: "世界上最大的悲哀,不是我不行,而是我本可以。", + imageUrl: JoannAvatar.src, + }, + { + team: Team.DATA, + name: "張若兪 Mila Chang ", + title: "第七屆 Data 引水人", + subTitle: ["第六屆 Data 航海士"], + quote: "學會站在別人的角度,才能成就更好的自己。", + imageUrl: MilaAvatar.src, + }, + { + team: Team.ENGINEER, + name: "蔡珮歆 Judy Tsai", + title: "第七屆 Engineering 引水人", + subTitle: ["第六屆 Engineering 水手"], + quote: "天賦決定下限,好奇心決定上限。", + imageUrl: JudyAvatar.src, + }, + { + team: Team.ENGINEER, + name: "莫力全 Kyle Mo", + title: "第七屆 Engineering 引水人", + subTitle: ["第六屆 Engineering 水手"], + quote: "如果你希望周遭環境改變,答案或許是從「改變自己」開始。", + imageUrl: KyleAvatar.src, + }, + { + team: Team.MKT, + name: "邱姵璇 Alice Chiu", + title: "第七屆 Marketing 引水人", + subTitle: ["第六屆 PM 助教", "第五屆 PM 水手"], + quote: "不怕失去才是擁有的開始。", + imageUrl: AliceAvatar.src, + }, + { + team: Team.PM, + name: "謝慧霖 Claire Hsieh", + title: "第七屆 Marketing 引水人", + subTitle: [ + "第六屆 PM 航海士 ", + "第三屆 Entrepreneurship 助教", + "第二屆 Entrepreneurship 水手", + ], + quote: "把每次挑戰都變成學習與成長的機會。", + imageUrl: ClaireAvatar.src, + }, + { + team: Team.UIUX, + name: "許珮甄 Patty Hsu", + title: "第七屆 UIUX 引水人", + subTitle: ["第六屆 UIUX 航海士", "第一屆 領導力小學堂 學員"], + quote: "用設計改變世界,用體驗溫暖人心。", + imageUrl: PattyAvatar.src, + }, + { + team: Team.LEADERSHIP, + name: "劉芷吟 Harper Liu", + title: "第七屆 領導力小學堂 引水人", + subTitle: [ + "第六屆 BD 助教", + "第五屆 BD 航海士", + "第一屆 領導力小學堂 學員", + ], + quote: "你打算怎麼渡過這瘋狂又珍貴的人生?", + imageUrl: HarperAvatar.src, + }, + ], + [Role.ASSISTANT]: [ + { + team: Team.ENGINEER, + name: "林政儀 Martin Lin", + title: "第七屆 官網組 助理", + subTitle: ["第六屆 Engineer 航海士"], + quote: "開拓視野,看見世界,貼近彼此,感受生活,這就是生活的目的。", + imageUrl: MartinAvatar.src, + }, + { + team: Team.ENGINEER, + name: "梁資芸 Lizzy Liang", + title: "第七屆 官網組 助理", + subTitle: ["第六屆 Engineer 水手"], + quote: "現在放棄的話,比賽就結束了。", + imageUrl: LizzyAvatar.src, + }, + ], +}; diff --git a/nextjs-app/constants/roleDisplayTextMap.ts b/nextjs-app/constants/role-display-text-map.ts similarity index 85% rename from nextjs-app/constants/roleDisplayTextMap.ts rename to nextjs-app/constants/role-display-text-map.ts index 1df3ce4..961447d 100644 --- a/nextjs-app/constants/roleDisplayTextMap.ts +++ b/nextjs-app/constants/role-display-text-map.ts @@ -5,4 +5,5 @@ export const roleDisplayTextMap: Record = { [Role.HARBOUR_PILOT]: "引水人", [Role.NAVIGATOR]: "航海士", [Role.SAILOR]: "水手", + [Role.ASSISTANT]: "助理/助教", }; diff --git a/nextjs-app/constants/team-display-text-map.ts b/nextjs-app/constants/team-display-text-map.ts new file mode 100644 index 0000000..b3b7014 --- /dev/null +++ b/nextjs-app/constants/team-display-text-map.ts @@ -0,0 +1,44 @@ +import { Team } from "@/types"; + +export const teamDisplayTextMap: Record< + Team, + { + zhGroupName: string; + enGroupName: string; + shortName?: string; + } +> = { + [Team.BD]: { + zhGroupName: "商業開發", + enGroupName: "Business Development", + shortName: "BD", + }, + [Team.DATA]: { + zhGroupName: "資料應用", + enGroupName: "Data Application (Data)", + shortName: "DATA", + }, + [Team.ENGINEER]: { + zhGroupName: "技術開發", + enGroupName: "Engineering", + }, + [Team.MKT]: { + zhGroupName: "行銷", + enGroupName: "Marketing", + shortName: "MKT", + }, + [Team.PM]: { + zhGroupName: "產品管理", + enGroupName: "Product Management", + shortName: "PM", + }, + [Team.UIUX]: { + zhGroupName: "使用者體驗設計", + enGroupName: "User Interface & Experience", + shortName: "UIUX", + }, + [Team.LEADERSHIP]: { + zhGroupName: "領導力小學堂", + enGroupName: "Leadership Academy", + }, +}; diff --git a/nextjs-app/public/images/execution-group/Alice.png b/nextjs-app/public/images/execution-group/Alice.png new file mode 100644 index 0000000..d2eeac4 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Alice.png differ diff --git a/nextjs-app/public/images/execution-group/Brown.png b/nextjs-app/public/images/execution-group/Brown.png new file mode 100644 index 0000000..85f790f Binary files /dev/null and b/nextjs-app/public/images/execution-group/Brown.png differ diff --git a/nextjs-app/public/images/execution-group/Bryan.png b/nextjs-app/public/images/execution-group/Bryan.png new file mode 100644 index 0000000..9f78995 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Bryan.png differ diff --git a/nextjs-app/public/images/execution-group/Claire.png b/nextjs-app/public/images/execution-group/Claire.png new file mode 100644 index 0000000..6299aeb Binary files /dev/null and b/nextjs-app/public/images/execution-group/Claire.png differ diff --git a/nextjs-app/public/images/execution-group/Duki.png b/nextjs-app/public/images/execution-group/Duki.png new file mode 100644 index 0000000..c8cfe59 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Duki.png differ diff --git a/nextjs-app/public/images/execution-group/Gordon.png b/nextjs-app/public/images/execution-group/Gordon.png new file mode 100644 index 0000000..172dabe Binary files /dev/null and b/nextjs-app/public/images/execution-group/Gordon.png differ diff --git a/nextjs-app/public/images/execution-group/Harper.png b/nextjs-app/public/images/execution-group/Harper.png new file mode 100644 index 0000000..597a2ad Binary files /dev/null and b/nextjs-app/public/images/execution-group/Harper.png differ diff --git a/nextjs-app/public/images/execution-group/Joann.png b/nextjs-app/public/images/execution-group/Joann.png new file mode 100644 index 0000000..5422e5b Binary files /dev/null and b/nextjs-app/public/images/execution-group/Joann.png differ diff --git a/nextjs-app/public/images/execution-group/Judy.png b/nextjs-app/public/images/execution-group/Judy.png new file mode 100644 index 0000000..12133a0 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Judy.png differ diff --git a/nextjs-app/public/images/execution-group/Kyle.png b/nextjs-app/public/images/execution-group/Kyle.png new file mode 100644 index 0000000..6170f69 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Kyle.png differ diff --git a/nextjs-app/public/images/execution-group/Lizzy.png b/nextjs-app/public/images/execution-group/Lizzy.png new file mode 100644 index 0000000..6c81902 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Lizzy.png differ diff --git a/nextjs-app/public/images/execution-group/Martin.png b/nextjs-app/public/images/execution-group/Martin.png new file mode 100644 index 0000000..0980fd2 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Martin.png differ diff --git a/nextjs-app/public/images/execution-group/Mila.png b/nextjs-app/public/images/execution-group/Mila.png new file mode 100644 index 0000000..949c520 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Mila.png differ diff --git a/nextjs-app/public/images/execution-group/Patty.png b/nextjs-app/public/images/execution-group/Patty.png new file mode 100644 index 0000000..eb7a9f5 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Patty.png differ diff --git a/nextjs-app/public/images/execution-group/Sidney.png b/nextjs-app/public/images/execution-group/Sidney.png new file mode 100644 index 0000000..115295b Binary files /dev/null and b/nextjs-app/public/images/execution-group/Sidney.png differ diff --git a/nextjs-app/public/images/execution-group/Steve.png b/nextjs-app/public/images/execution-group/Steve.png new file mode 100644 index 0000000..30a6729 Binary files /dev/null and b/nextjs-app/public/images/execution-group/Steve.png differ diff --git a/nextjs-app/tailwind.config.ts b/nextjs-app/tailwind.config.ts index d969b25..cb431e7 100644 --- a/nextjs-app/tailwind.config.ts +++ b/nextjs-app/tailwind.config.ts @@ -29,7 +29,7 @@ export default { container: { center: true, screens: { - xl: "1440px", + xl: "1156px", }, }, fontFamily: { diff --git a/nextjs-app/types/filter-option.ts b/nextjs-app/types/filter-option.ts index 9919233..1b15214 100644 --- a/nextjs-app/types/filter-option.ts +++ b/nextjs-app/types/filter-option.ts @@ -1,6 +1,13 @@ +import { Role } from "."; + export interface IFilterOption { key: string; name: string; } export type FAQType = "registration" | "monthlyMeeting" | "lecture" | "payment"; + +export type ExecutionGroupType = + | Role.CAPTAIN + | Role.HARBOUR_PILOT + | Role.ASSISTANT; diff --git a/nextjs-app/types/index.ts b/nextjs-app/types/index.ts index 032f133..b8c6442 100644 --- a/nextjs-app/types/index.ts +++ b/nextjs-app/types/index.ts @@ -13,4 +13,5 @@ export enum Role { NAVIGATOR = "Navigator", SAILOR = "Sailor", HARBOUR_PILOT = "HarbourPilot", + ASSISTANT = "Assistant", }