feat(about): add team member profile page
This commit introduces a new section to showcase team members, starting with the founder's profile. - Adds a dynamic page route `/about/` to display individual member profiles. - Creates a new `about` content collection to source profile information from Markdown files. - Adds the first profile for 'Xiaomai', including a detailed resume and background image. - Integrates a 'Teams' dropdown into the main navigation header. - Implements a `copyToClipboard` utility with a toast notification for sharing profile links.
This commit is contained in:
@@ -80,6 +80,14 @@ export const useNavLinks = () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{label: t("common.header.teams.label"),
|
||||||
|
icon: "mdi:account-group-outline",
|
||||||
|
children: [{
|
||||||
|
label: t("common.header.teams.children.xiaomai.label"),
|
||||||
|
description: t("common.header.teams.children.xiaomai.description"),
|
||||||
|
to: '/about/xiaomai'
|
||||||
|
}]
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return navLinks;
|
return navLinks;
|
||||||
|
|||||||
49
app/pages/about/[slug].vue
Normal file
49
app/pages/about/[slug].vue
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const articleLink = computed(() => `${window?.location}`);
|
||||||
|
|
||||||
|
const { data: page } = await useAsyncData(route.path, () =>
|
||||||
|
queryCollection("about").path(`/about/${route.params.slug}`).first()
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UPage>
|
||||||
|
<div
|
||||||
|
class="fixed top-0 left-0 -z-999 w-screen h-screen bg-[url('/images/xiaomai.png')] bg-cover lg:bg-contain bg-no-repeat opacity-40 animate-slide-in"
|
||||||
|
></div>
|
||||||
|
<UPageBody class="max-w-3xl mx-auto">
|
||||||
|
<ContentRenderer v-if="page?.body" :value="page" />
|
||||||
|
|
||||||
|
<div class="flex items-center justify-end gap-2 text-sm text-muted">
|
||||||
|
<UButton
|
||||||
|
size="sm"
|
||||||
|
variant="link"
|
||||||
|
color="neutral"
|
||||||
|
label="Copy link"
|
||||||
|
@click="
|
||||||
|
copyToClipboard(articleLink, 'Article link copied to clipboard')
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</UPageBody>
|
||||||
|
</UPage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@keyframes slide-in {
|
||||||
|
from {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-slide-in {
|
||||||
|
animation: slide-in 1.2s ease-out forwards;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -71,14 +71,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const { data: page } = await useLocalizedCollection("index");
|
const { data: page } = await useLocalizedCollection("index", {
|
||||||
|
throwOnMissing: false,
|
||||||
|
});
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: page.value?.seo.title,
|
title: page.value?.seo.title,
|
||||||
});
|
});
|
||||||
|
|
||||||
const colorMode = useColorMode();
|
|
||||||
|
|
||||||
const backgroundImages = [
|
const backgroundImages = [
|
||||||
"https://img.tootaio.com/i/2025/11/05/avc5ld.png",
|
"https://img.tootaio.com/i/2025/11/05/avc5ld.png",
|
||||||
"https://img.tootaio.com/i/2025/11/05/avcaff.png",
|
"https://img.tootaio.com/i/2025/11/05/avcaff.png",
|
||||||
@@ -111,67 +111,31 @@ const techIcons = computed(() => [
|
|||||||
"skill-icons:javascript",
|
"skill-icons:javascript",
|
||||||
"skill-icons:typescript",
|
"skill-icons:typescript",
|
||||||
"skill-icons:docker",
|
"skill-icons:docker",
|
||||||
colorMode.value === "dark"
|
"skill-icons:vuejs-light",
|
||||||
? "skill-icons:vuejs-dark"
|
"skill-icons:nuxtjs-light",
|
||||||
: "skill-icons:vuejs-light",
|
"skill-icons:tailwindcss-light",
|
||||||
colorMode.value === "dark"
|
"skill-icons:nodejs-light",
|
||||||
? "skill-icons:nuxtjs-dark"
|
|
||||||
: "skill-icons:nuxtjs-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:tailwindcss-dark"
|
|
||||||
: "skill-icons:tailwindcss-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:nodejs-dark"
|
|
||||||
: "skill-icons:nodejs-light",
|
|
||||||
"skill-icons:cs",
|
"skill-icons:cs",
|
||||||
colorMode.value === "dark"
|
"skill-icons:python-light",
|
||||||
? "skill-icons:python-dark"
|
|
||||||
: "skill-icons:python-light",
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const toolsIcons = ref([
|
const toolsIcons = ref([
|
||||||
"skill-icons:photoshop",
|
"skill-icons:photoshop",
|
||||||
"skill-icons:illustrator",
|
"skill-icons:illustrator",
|
||||||
"skill-icons:git",
|
"skill-icons:git",
|
||||||
colorMode.value === "dark"
|
"skill-icons:vscode-light",
|
||||||
? "skill-icons:vscode-dark"
|
"skill-icons:visualstudio-light",
|
||||||
: "skill-icons:vscode-light",
|
"skill-icons:github-light",
|
||||||
colorMode.value === "dark"
|
"skill-icons:godot-light",
|
||||||
? "skill-icons:visualstudio-dark"
|
"skill-icons:unity-light",
|
||||||
: "skill-icons:visualstudio-light",
|
"skill-icons:blender-light",
|
||||||
colorMode.value === "dark"
|
"skill-icons:androidstudio-light",
|
||||||
? "skill-icons:github-dark"
|
"skill-icons:windows-light",
|
||||||
: "skill-icons:github-light",
|
"skill-icons:linux-light",
|
||||||
colorMode.value === "dark"
|
"skill-icons:apple-light",
|
||||||
? "skill-icons:godot-dark"
|
"skill-icons:idea-light",
|
||||||
: "skill-icons:godot-light",
|
"skill-icons:pycharm-light",
|
||||||
colorMode.value === "dark"
|
"skill-icons:rider-light",
|
||||||
? "skill-icons:unity-dark"
|
|
||||||
: "skill-icons:unity-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:blender-dark"
|
|
||||||
: "skill-icons:blender-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:androidstudio-dark"
|
|
||||||
: "skill-icons:androidstudio-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:windows-dark"
|
|
||||||
: "skill-icons:windows-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:linux-dark"
|
|
||||||
: "skill-icons:linux-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:apple-dark"
|
|
||||||
: "skill-icons:apple-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:idea-dark"
|
|
||||||
: "skill-icons:idea-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:pycharm-dark"
|
|
||||||
: "skill-icons:pycharm-light",
|
|
||||||
colorMode.value === "dark"
|
|
||||||
? "skill-icons:rider-dark"
|
|
||||||
: "skill-icons:rider-light",
|
|
||||||
]);
|
]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
13
app/utils/clipboard.ts
Normal file
13
app/utils/clipboard.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
export function copyToClipboard(
|
||||||
|
toCopy: string,
|
||||||
|
message: string = "Copied to clipboard"
|
||||||
|
) {
|
||||||
|
const toast = useToast();
|
||||||
|
navigator.clipboard.writeText(toCopy).then(() => {
|
||||||
|
toast.add({
|
||||||
|
title: message,
|
||||||
|
color: "success",
|
||||||
|
icon: "i-lucide-check-circle",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -50,9 +50,7 @@ const defineWebDevSchema = () =>
|
|||||||
label: z.string().min(1),
|
label: z.string().min(1),
|
||||||
icon: z.string().optional(), // 比如 "lucide:mouse-pointer-click"
|
icon: z.string().optional(), // 比如 "lucide:mouse-pointer-click"
|
||||||
// 你原结构里通过 createService 包装,但最终是一个对象
|
// 你原结构里通过 createService 包装,但最终是一个对象
|
||||||
plans: z
|
plans: z.array(PricingPlanPropsSchema).min(1),
|
||||||
.array(PricingPlanPropsSchema)
|
|
||||||
.min(1),
|
|
||||||
// 预留扩展字段(例如:category、tags、hidden 等)
|
// 预留扩展字段(例如:category、tags、hidden 等)
|
||||||
category: z.string().optional(),
|
category: z.string().optional(),
|
||||||
tags: z.array(z.string()).optional(),
|
tags: z.array(z.string()).optional(),
|
||||||
@@ -82,5 +80,10 @@ export default defineContentConfig({
|
|||||||
source: "zh-CN/webDev.yml",
|
source: "zh-CN/webDev.yml",
|
||||||
schema: defineWebDevSchema(),
|
schema: defineWebDevSchema(),
|
||||||
}),
|
}),
|
||||||
|
about: defineCollection({
|
||||||
|
type: "page",
|
||||||
|
source: "about/*.md",
|
||||||
|
schema: z.object({}),
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
138
content/about/xiaomai.md
Normal file
138
content/about/xiaomai.md
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
---
|
||||||
|
name: 小麦(Xiaomai)
|
||||||
|
title: 游戏开发者 | 前后端开发者 | 工作室创办人
|
||||||
|
location: 马来西亚,柔佛
|
||||||
|
email: xsbugh@gmail.com
|
||||||
|
website: https://github.com/kingsmai
|
||||||
|
education:
|
||||||
|
university: 武汉工商学院
|
||||||
|
major: 计算机科学与技术
|
||||||
|
gpa: 3.93/4.0
|
||||||
|
period: 2019年9月 - 2024年8月
|
||||||
|
rank: 专业排名 8/303
|
||||||
|
scholarship: 四年全额奖学金获得者
|
||||||
|
awards:
|
||||||
|
- 2021年全国高校商业精英挑战赛创新创业竞赛全国总决赛一等奖
|
||||||
|
- 2021年"互联网+"大学生创新创业大赛湖北省复赛金奖
|
||||||
|
- 马来西亚外交部志愿者贡献表彰(2022年)
|
||||||
|
skills:
|
||||||
|
- Unity 2D/3D 游戏开发
|
||||||
|
- Godot 4 游戏开发
|
||||||
|
- JavaWeb 后端开发 (SpringBoot)
|
||||||
|
- Web 前端开发 (Vue, Node.js, Webpack)
|
||||||
|
- Python 数据分析与自动化
|
||||||
|
- SQLite, MySQL 数据库管理
|
||||||
|
- Blender LowPoly 建模
|
||||||
|
- 区块链开发与NFT技术
|
||||||
|
- 自动化测试 (Selenium)
|
||||||
|
- AI与机器学习基础
|
||||||
|
---
|
||||||
|
|
||||||
|
# 麦祖奕 - 工作室创办人介绍
|
||||||
|
|
||||||
|
## 个人简介
|
||||||
|
|
||||||
|
我是一名来自马来西亚的华裔游戏开发者,本科以优异成绩毕业于武汉工商学院计算机科学与技术专业。作为一名充满热情的技术创作者,我拥有丰富的全栈开发经验。
|
||||||
|
|
||||||
|
我的技术生涯始于对游戏开发的热爱,逐渐扩展到区块链技术、Web 全栈开发和自动化系统等多个领域。我相信技术应该服务于创意,致力于通过代码实现具有社会价值的创新项目。
|
||||||
|
|
||||||
|
**人生使命**:开发具有教育价值且在全球广受欢迎的角色扮演游戏,通过游戏传递知识、启发思考。
|
||||||
|
|
||||||
|
## 教育背景与学术成就
|
||||||
|
|
||||||
|
在武汉工商学院就读期间,我以 **3.93 的 GPA** 成绩位列专业前 3%(8/303),连续四年获得全额奖学金。系统学习了计算机科学的核心课程,包括数据结构、算法设计、软件工程、数据库原理等,为后续的技术实践奠定了坚实的理论基础。
|
||||||
|
|
||||||
|
## 专业技术能力
|
||||||
|
|
||||||
|
### 游戏开发专长
|
||||||
|
- **Unity引擎开发者**:精通 2D 游戏开发,熟悉物理系统、动画系统、UI系统
|
||||||
|
- **Godot引擎实践者**:掌握 Godot 4 及 GDScript,具备快速原型开发能力
|
||||||
|
- **游戏架构设计**:熟练运用单例模式、工厂模式、观察者模式、对象池等设计模式
|
||||||
|
- **AI系统实现**:掌握状态机、上下文转向寻路、行为树等AI技术
|
||||||
|
- **数据持久化**:精通 SQLite 嵌入式数据库、PlayerPrefs 等存储方案
|
||||||
|
- **安全加密**:实践 XOR 数据加密技术保护游戏数据
|
||||||
|
|
||||||
|
### 全栈开发能力
|
||||||
|
- **后端开发**:SpringBoot, ASP .NET Core, PHP, Node.js, 数据库设计与优化
|
||||||
|
- **前端开发**:Vue.js, Nuxt, Webpack, 响应式设计, 静态站点生成
|
||||||
|
- **移动端开发**:Android 原生开发,跨平台适配
|
||||||
|
- **自动化脚本**:Python + Selenium 自动化操作
|
||||||
|
|
||||||
|
### 其他技术技能
|
||||||
|
- **区块链开发**:NFT 自动化交易开发,智能合约理解
|
||||||
|
- **3D建模**:Blender LowPoly 建模,游戏资源制作
|
||||||
|
- **数据分析**:Python 数据处理与可视化
|
||||||
|
- **项目管理**:Git 版本控制,团队协作开发
|
||||||
|
|
||||||
|
## 代表性项目
|
||||||
|
|
||||||
|
### 🎮 《匠人英雄》- 2D生存类游戏(毕业设计)
|
||||||
|
**技术栈**: Unity, SQLite, Context Steering AI, Perlin Noise, 设计模式
|
||||||
|
|
||||||
|
作为大学毕业设计,我独立设计并开发了这款2D俯视角生存游戏。项目实现了:
|
||||||
|
- 基于 CSV 和 XOR 加密的游戏数据配置系统
|
||||||
|
- 嵌入式 SQLite 数据库存档系统
|
||||||
|
- 上下文转向 AI 寻路与 Perlin 噪声地图生成
|
||||||
|
- 完整的设计模式应用架构
|
||||||
|
|
||||||
|
### 🔥 《光追》- 地牢冒险游戏(GameJam作品)
|
||||||
|
**技术栈**: Godot 4, 有限状态机, GDScript
|
||||||
|
|
||||||
|
在 48 小时极限开发挑战中,我担任程序与策划,带领团队完成:
|
||||||
|
- 基于状态机的 AI 行为系统
|
||||||
|
- 光影核心玩法机制设计
|
||||||
|
- B站宣传片获得 700+ 观看量
|
||||||
|
- 吸引 200+ 玩家参与测试
|
||||||
|
|
||||||
|
### 🌐 马来西亚赴华资料整合网站
|
||||||
|
**技术栈**: Node.js, Webpack, GitHub Pages, JSON API
|
||||||
|
|
||||||
|
疫情期间,我联合多所高校留学生发起并开发了这个信息整合平台:
|
||||||
|
- 3 天内完成从需求分析到部署上线的全流程
|
||||||
|
- 自研基于 JSON 的静态页面 API 模拟框架
|
||||||
|
- 帮助近 5000 名马来西亚留学生顺利返校
|
||||||
|
- 获得马来西亚外交部官方认可
|
||||||
|
|
||||||
|
### 💰 慈善竞标大屏系统
|
||||||
|
**技术栈**: Unity, 双屏显示, 实时动画
|
||||||
|
|
||||||
|
为慈善机构开发的商业化项目:
|
||||||
|
- 实时竞价数据显示与动画效果
|
||||||
|
- 主控台与大屏幕的双屏协同
|
||||||
|
- 在马来西亚多个组织中成功应用
|
||||||
|
|
||||||
|
## 工作与创业经历
|
||||||
|
|
||||||
|
### 马来西亚民主行动党 - 软件开发实习生
|
||||||
|
**2022年2月-2022年9月**
|
||||||
|
|
||||||
|
在实习期间,我承担了多项技术任务:
|
||||||
|
- 使用 Python 进行选举数据分析和可视化
|
||||||
|
- 基于 SpringBoot + Vue 开发中大型数据管理系统
|
||||||
|
- 实现 NFT 交易平台的自动化操作脚本
|
||||||
|
- 协助多语言新闻稿的发布与传播
|
||||||
|
|
||||||
|
### 技术创业经历
|
||||||
|
基于在游戏开发和 Web 全栈领域的技术积累,我具备从零到一的产品开发能力,能够带领团队完成技术选型、架构设计、开发实施和运营维护的全过程。
|
||||||
|
|
||||||
|
## 技术理念与愿景
|
||||||
|
|
||||||
|
### 开发哲学
|
||||||
|
我相信优秀的技术产品应该具备三个特质:**用户体验优先**、**技术架构稳健**、**社会价值正向**。在每一个项目中,我都努力平衡技术创新与实际需求,确保代码质量与开发效率的最佳结合。
|
||||||
|
|
||||||
|
### 工作室愿景
|
||||||
|
作为工作室创办人,我致力于:
|
||||||
|
1. 打造具有教育意义的精品游戏
|
||||||
|
2. 探索游戏与新兴技术的结合点
|
||||||
|
3. 培养年轻开发者的技术能力
|
||||||
|
4. 通过技术解决方案创造社会价值
|
||||||
|
|
||||||
|
## 荣誉与认可
|
||||||
|
|
||||||
|
除了在学术和技术竞赛中获得的奖项外,我最珍视的认可是那些通过技术帮助他人的时刻。特别是在疫情期间开发的留学生返校网站,不仅获得了马来西亚外交部的正式表彰,更重要的是切实帮助了数千名学子重返校园。
|
||||||
|
|
||||||
|
我相信,技术的真正价值在于它能够为人们的生活带来积极的改变。作为一名技术创作者,这始终是我前进的动力和追求的目标。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*欢迎通过以上联系方式与我交流技术创意、项目合作或投资机会。我始终对新的技术挑战和具有社会价值的项目保持开放态度。*
|
||||||
@@ -51,6 +51,15 @@
|
|||||||
"description": "Have a look at our indie games!"
|
"description": "Have a look at our indie games!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"teams": {
|
||||||
|
"label": "Teams",
|
||||||
|
"children": {
|
||||||
|
"xiaomai": {
|
||||||
|
"label": "Xiaomai",
|
||||||
|
"description": "Founder of Tootaio Studio - Full Stack Developer"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
|
|||||||
@@ -51,6 +51,15 @@
|
|||||||
"description": "我们工作室创始人小麦的博客网站。"
|
"description": "我们工作室创始人小麦的博客网站。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"teams": {
|
||||||
|
"label": "团队",
|
||||||
|
"children": {
|
||||||
|
"xiaomai": {
|
||||||
|
"label": "小麦",
|
||||||
|
"description": "Tootaio Studio 创始人 - 全栈开发者"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ export default defineNuxtConfig({
|
|||||||
compatibilityDate: "2025-07-15",
|
compatibilityDate: "2025-07-15",
|
||||||
devtools: { enabled: process.env.NODE_ENV !== "production" },
|
devtools: { enabled: process.env.NODE_ENV !== "production" },
|
||||||
modules: [
|
modules: [
|
||||||
"@nuxt/content",
|
|
||||||
"@nuxt/ui",
|
"@nuxt/ui",
|
||||||
|
"@nuxt/content",
|
||||||
"@nuxt/eslint",
|
"@nuxt/eslint",
|
||||||
"@nuxtjs/i18n",
|
"@nuxtjs/i18n",
|
||||||
"@nuxtjs/seo",
|
"@nuxtjs/seo",
|
||||||
|
|||||||
BIN
public/images/xiaomai.png
Normal file
BIN
public/images/xiaomai.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
Reference in New Issue
Block a user