feat: 添加个人信息展示功能,更新配置文件以支持年龄、性别、代词和地区

This commit is contained in:
2025-12-07 00:02:25 +08:00
parent f80e5c0b5a
commit d7b419f401
5 changed files with 126 additions and 6 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Rhen Cloud
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,6 +1,6 @@
# Cloud Home
一个基于 Vue 的个人主页模板,内置友链申请、项目展示、友链随机展示、自定义配置,支持 Vercel 部署与邮件通知。
一个基于 Vue 的个人主页模板,内置友链申请、网站展示、项目展示、友链随机展示、自定义配置,支持 Vercel 部署与邮件通知。
## 特性
@@ -145,9 +145,7 @@ pnpm build
## 部署到 Vercel
1. 导入仓库到 Vercel。
2. 设置上文的 SMTP 环境变量。
3. 保持 `vercel.json``distDir: "dist"`
4. 部署后,静态文件从 `dist/` 提供API 走 `/api/send-mail`
2. 设置上文的环境变量。
## API

View File

@@ -2,6 +2,41 @@
<section class="card panel">
<h2>个人简介</h2>
<p class="muted">关于我 · About Me</p>
<div class="about-grid info-grid">
<article v-if="age" class="about-card info-card">
<div class="about-head">
<span class="icon">🎂</span>
<h3>年龄</h3>
</div>
<p class="muted">{{ age }} </p>
</article>
<article v-if="profile?.gender" class="about-card info-card">
<div class="about-head">
<span class="icon"></span>
<h3>性别</h3>
</div>
<p class="muted">{{ profile.gender }}</p>
</article>
<article v-if="profile?.pronouns" class="about-card info-card">
<div class="about-head">
<span class="icon">🗣</span>
<h3>代词</h3>
</div>
<p class="muted">{{ profile.pronouns }}</p>
</article>
<article v-if="profile?.location" class="about-card info-card">
<div class="about-head">
<span class="icon">📍</span>
<h3>地区</h3>
</div>
<p class="muted">{{ profile.location }}</p>
</article>
</div>
<div class="about-grid">
<article v-for="item in items" :key="item.title" class="about-card">
<div class="about-head">
@@ -15,7 +50,24 @@
</template>
<script setup>
defineProps({ items: Array });
import { computed } from "vue";
const props = defineProps({
items: Array,
profile: Object,
});
const age = computed(() => {
if (!props.profile?.birthday) return null;
const birthDate = new Date(props.profile.birthday);
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const m = today.getMonth() - birthDate.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
return age;
});
</script>
<style scoped>
@@ -36,10 +88,23 @@ h2 {
grid-template-columns: repeat(2, minmax(240px, 1fr));
gap: 14px;
}
.info-grid {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 14px;
}
.about-grid + .about-grid {
margin-top: 10px;
}
@media (max-width: 720px) {
.about-grid {
grid-template-columns: 1fr;
}
.info-grid {
display: flex;
gap: 10px;
}
}
.about-card {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.02));
@@ -49,6 +114,34 @@ h2 {
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.info-card {
flex: 1 1 140px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 14px;
}
.info-card .about-head {
margin-bottom: 0;
}
.info-card .about-head h3 {
font-size: 15px;
color: rgba(255, 255, 255, 0.9);
font-weight: 600;
margin: 0;
}
.info-card .icon {
font-size: 18px;
}
.info-card .muted {
margin: 0;
text-align: right;
white-space: nowrap;
font-weight: 500;
color: rgba(255, 255, 255, 0.6);
font-size: 13px;
}
.about-card:hover {
transform: translateY(-2px);
border-color: rgba(124, 193, 255, 0.4);

View File

@@ -4,6 +4,10 @@ interface SiteConfig {
title: string;
avatar: string;
bio: string;
birthday?: string;
gender?: string;
pronouns?: string;
location?: string;
};
socialLinks: Array<{
name: string;
@@ -56,6 +60,10 @@ const siteConfig: SiteConfig = {
title: "I'm RhenCloud.",
avatar: "avatar.webp", // public/avatar.webp
bio: "趁世界还未重启之前 约一次爱恋",
birthday: "2010-03-28",
// gender: "女",
pronouns: "她",
location: "中国 · 天津",
},
socialLinks: [

View File

@@ -2,7 +2,7 @@
<main class="page">
<HeroSection :profile="profile" />
<SocialLinks :links="socialLinks" />
<AboutSection :items="about" />
<AboutSection :items="about" :profile="profile" />
</main>
</template>