初版demo效果
背景
很久以来我都在找一个能够聚合个人生活、工作、分享的网站,但是一直没找到合适的,所以一直打算自己写一个,但是工作时间太长且强度比较大,就一直没开始,后面cursor出现之后,我借助ai编辑器快速实现了第一版demo,可以在线访问,但ai实现的有较多的bug,会在后续会手动去优化并整理开发文档,开源出去
思路
我主要是想要是能够当一个:
- 在线简历:能让别人知道我,知道我在做什么,知道我会什么,说不定有人看上这个网站,能免试呢,主要涉及简介、教育经历、工作经历、技术文档列表、技术栈
- 灵感笔记:脑袋里总是经常蹦出一些想法,不记录下来很快就忘了,这是一个类似发消息的页面
- 在线相册:我比较喜欢记录生活,经常用手机拍摄一些图片,最近刚买了相机,在学习,所以我需要一个瀑布流的相册
- 工作空间:电子爱好者,上面会列举一些我正在用的产品
- 导航站:记录书签,根据分类列出平时收集的网站工具等等,后续需要支持导入书签,导出书签,接入ai搜索给建议
- 时间轴:用于记录大事件
- 项目:自己写的项目,或者是参与过的一些开源项目
- demo:记录平时写的demo动画,组件什么的,通过gif动态展示
- 友链:交朋友,欢迎提交友链
系列文章
技术栈
nextjs+tailwind+pnpm+ts+mongodb+ai
详细介绍
首页&简介
基本功能
-
主要展示社交链接,网站信息,教育经历,工作经历
-
社交链接跟侧边栏同步
-
信息存储在后端
-
自动计算工作时间
-
展示发布文章列表可以跳转文章详情
数据模型
网站信息数据模型
import { Schema, model, models } from 'mongoose';
import { IEducation } from "./education";
export interface ISite {
createdAt: Date; // 网站创建时间
visitCount: number; // 访问人数
likeCount: number; // 点赞数量
favicon: string; // 网站图标链接
qrcode: string; // 二维码图片链接
appreciationCode: string; // 赞赏码图片链接
wechatGroup: string; // 微信公众号图片链接
title: string; // 网站标题
description: string; // 网站描述
backgroundImage: string; // 首页背景图链接
author: { // 作者信息
name: string;
avatar: string;
description: string; // 作者一句话描述
bio: string; // 作者详细介绍
education: IEducation[]; // 教育经历
};
icp?: string; // 备案信息
seo: { // SEO相关信息
keywords: string[];
description: string;
};
}
const siteSchema = new Schema<ISite>({
createdAt: { type: Date, default: Date.now },
visitCount: { type: Number, default: 0 },
likeCount: { type: Number, default: 0 },
favicon: { type: String, required: true },
qrcode: { type: String, required: true },
appreciationCode: { type: String, required: true },
wechatGroup: { type: String, required: true },
title: { type: String, required: true },
description: { type: String, required: true },
backgroundImage: { type: String, required: true },
author: {
name: { type: String, required: true },
avatar: { type: String, required: true },
description: { type: String, required: true },
bio: { type: String, required: true },
education: [{ type: Schema.Types.ObjectId, ref: 'Education' }]
},
icp: String,
seo: {
keywords: [String],
description: { type: String, required: true },
ogImage: String
},
});
export const Site = models.Site || model<ISite>('Site', siteSchema);
社交链接数据模型
import mongoose, { Schema, Document } from 'mongoose';
export interface ISocialLinkBase {
name: string;
icon: string;
url: string;
bgColor: string;
}
export interface ISocialLink extends Document, ISocialLinkBase {}
const socialLinkSchema = new Schema<ISocialLink>({
name: { type: String, required: true },
icon: { type: String, required: true },
url: { type: String, required: true },
bgColor: { type: String, required: true }
}, {
timestamps: true
});
export const SocialLink = mongoose.models.SocialLink || mongoose.model<ISocialLink>('SocialLink', socialLinkSchema);
工作经历数据模型
import mongoose, { Schema, Document } from "mongoose";
export interface IWorkExperienceBase {
_id?: string;
company: string;
companyUrl: string;
position: string;
description: string;
startDate: string;
endDate: string | null; // null means current position
}
export interface IWorkExperience extends Document, IWorkExperienceBase {
_id: string;
}
const workExperienceSchema = new Schema<IWorkExperience>(
{
company: { type: String, required: true },
companyUrl: { type: String, required: true },
position: { type: String, required: true },
description: { type: String, required: true },
startDate: { type: String, required: true },
endDate: { type: String, default: null },
},
{
timestamps: true,
}
);
export const WorkExperience =
mongoose.models.WorkExperience ||
mongoose.model<IWorkExperience>("WorkExperience", workExperienceSchema);
教育经历数据模型
export interface IEducation {
school: string; // 学校名称
major: string; // 专业
degree: string; // 学位
certifications?: string[]; // 证书,如 CET6 等
startDate: string; // 入学时间
endDate: string; // 毕业时间
}
技术栈
基本功能
展示已经接触过的技术,跳转官网 | 技术文档
数据模型
import mongoose, { Schema, Document } from 'mongoose';
export interface IStack extends Document {
title: string;
description: string;
link: string;
iconSrc: string;
}
const stackSchema = new Schema<IStack>({
title: { type: String, required: true },
description: { type: String, required: true },
link: { type: String, required: true },
iconSrc: { type: String, required: true }
}, {
timestamps: true
});
export const Stack = mongoose.models.Stack || mongoose.model<IStack>('Stack', stackSchema);
灵感笔记
基本功能
ui类似微信聊天界面,能够展示气泡信息就行,支持快速发送灵感,支持嵌入b站视频,图片等。
数据模型
import { ObjectId } from "mongodb";
export interface IInspiration {
_id?: ObjectId;
title: string;
content: string;
images?: string[]; // 图片URL数组
createdAt: Date;
updatedAt: Date;
likes: number;
views: number;
bilibili?: {
bvid: string; // B站视频的BV号
title?: string; // 视频标题
cover?: string; // 视频封面图片URL
page?: number; // 视频分P号,默认为1
};
links?: {
title: string;
url: string;
icon?: string; // 可选的链接图标
}[];
tags?: string[]; // 可选的标签
status: "draft" | "published"; // 草稿或已发布状态
}
export interface IInspirationCreate
extends Omit<
IInspiration,
"_id" | "createdAt" | "updatedAt" | "likes" | "views"
> {
// 创建时不需要的字段都被省略
}
export interface IInspirationUpdate
extends Partial<Omit<IInspiration, "_id" | "createdAt" | "updatedAt">> {
// 更新时所有字段都是可选的
}
// 用于前端展示的灵感笔记类型
export interface InspirationDisplay
extends Omit<IInspiration, "_id" | "createdAt" | "updatedAt"> {
_id: string; // ObjectId 转为字符串
createdAt: string; // Date 转为字符串
updatedAt: string; // Date 转为字符串
}
// 数据库中的灵感笔记类型
export type InspirationDocument = IInspiration & {
_id: ObjectId;
};
// 用于查询的过滤器类型
export interface InspirationFilter {
status?: "draft" | "published";
tags?: string[];
createdAt?: {
$gte?: Date;
$lte?: Date;
};
searchText?: string; // 用于搜索标题和内容
}
技术文章
基本功能
可根据分类展示文章列表,跳转文章详情,交互式文档实现,可在网站运行自己写的组件等,mdx就可以,但是我想自己看看这个得实现思路,就自己写了个。
数据模型
export interface Article {
// MongoDB ID
_id?: string;
// 文章标题
title: string;
// 文章链接(slug)
url?: string;
// 文章分类
category?: string;
// 文章分类ID
categoryId?: string;
// 文章标签(可以有多个)
tags?: string[];
// 文章内容(Markdown格式)
content: string;
// OSS存储路径
ossPath: string;
// 文章状态(draft-草稿/published-已发布)
status: ArticleStatus;
// 文章摘要
summary?: string;
// 封面图片URL
coverImage?: string;
// 点赞数
likes?: number;
// 阅读数
views?: number;
// 创建时间
createdAt: string;
// 更新时间(可选)
updatedAt?: string;
}
// 文章状态枚举
export enum ArticleStatus {
DRAFT = 'draft',
PUBLISHED = 'published'
}
// 文章分类接口
export interface ArticleCategory {
_id?: string;
name: string;
description?: string;
createdAt: string;
updatedAt: string;
}
生活相册
基本功能
通过瀑布流展示我平时拍摄的图片,支持预览,切图,喜欢摄影的带带弟弟,刚开始
数据模型
import mongoose, { Schema, Document } from "mongoose";
import { ObjectId } from "mongodb";
export interface IPhoto {
src: string;
width: number;
height: number;
title: string;
location: string;
date: string;
}
export interface IPhotoDB extends Omit<IPhoto, "_id"> {
_id: ObjectId;
createdAt: Date;
updatedAt: Date;
}
const photoSchema = new Schema<IPhotoDB>(
{
src: { type: String, required: true },
width: { type: Number, required: true },
height: { type: Number, required: true },
title: { type: String, required: true },
location: { type: String, required: true },
date: { type: String, required: true },
},
{
timestamps: true,
}
);
export const Photo =
mongoose.models.Photo || mongoose.model<IPhotoDB>("Photo", photoSchema);
工作空间
基本功能
分享展示一些自己正在使用的电子产品
数据模型
import mongoose, { Schema, Document } from "mongoose";
export interface IWorkspaceItem extends Document {
// _id?: string; // 使用可选的 _id
product: string;
specs: string;
buyAddress: string;
buyLink: string;
}
const workspaceItemSchema = new Schema<IWorkspaceItem>(
{
product: { type: String, required: true },
specs: { type: String, required: true },
buyAddress: { type: String, required: true },
buyLink: { type: String, required: true },
},
{
timestamps: true,
}
);
export const WorkspaceItem =
mongoose.models.WorkspaceItem ||
mongoose.model<IWorkspaceItem>("WorkspaceItem", workspaceItemSchema);
导航站
基本功能
根据分类记录网站,写了一个网站截图的服务,不需要上传图片,根据链接截取图片,后续会增加订阅 & ai搜索建议
数据模型
import { ObjectId } from 'mongodb';
// API interfaces (for frontend use)
export interface IBookmark {
_id?: ObjectId;
title: string;
url: string;
description: string;
imageUrl?: string;
categoryId: ObjectId;
createdAt: Date;
updatedAt: Date;
}
export interface IBookmarkCategory {
_id?: ObjectId;
name: string;
bookmarks: IBookmark[];
createdAt: Date;
updatedAt: Date;
}
// Database interfaces (for MongoDB)
export interface IBookmarkDB extends Omit<IBookmark, 'categoryId'> {
categoryId: ObjectId;
}
export interface IBookmarkCategoryDB extends Omit<IBookmarkCategory, 'bookmarks'> {
bookmarks: ObjectId[];
}
时间轴
基本功能
用来记录一些大事件,支持嵌入推特推文
数据模型
import mongoose, { Schema, Document } from 'mongoose';
import { ObjectId } from 'mongodb';
export interface ITimelineLink {
text: string;
url: string;
}
export interface ITimelineEvent {
_id?: string | ObjectId;
year: number;
month: number;
day: number;
title: string;
location?: string;
description: string;
tweetUrl?: string;
imageUrl?: string;
links?: ITimelineLink[];
createdAt?: Date;
updatedAt?: Date;
}
const timelineLinkSchema = new Schema<ITimelineLink>({
text: { type: String, required: true },
url: { type: String, required: true }
});
const timelineEventSchema = new Schema<ITimelineEvent>({
year: { type: Number, required: true },
month: { type: Number, required: true },
day: { type: Number, required: true },
title: { type: String, required: true },
location: { type: String },
description: { type: String, required: true },
tweetUrl: { type: String },
imageUrl: { type: String },
links: [timelineLinkSchema]
}, {
timestamps: true
});
export const TimelineEvent = mongoose.models.TimelineEvent || mongoose.model<ITimelineEvent>('TimelineEvent', timelineEventSchema);
项目
基本功能
展示一些自己参与 | 写过的项目,请求github,展示star,展示项目标签、项目状态等
数据模型
import mongoose, { Schema, Document } from 'mongoose';
import { ObjectId } from "mongodb";
export interface Project {
title: string;
description: string;
url?: string;
github?: string;
imageUrl?: string;
tags: string[];
status: "completed" | "in-progress" | "planned";
categoryId: ObjectId;
}
export interface ProjectDB extends Omit<Project, "_id"> {
_id?: ObjectId;
createdAt: Date;
updatedAt: Date;
}
export interface ProjectCategory {
name: string;
description: string;
projects: ObjectId[];
}
export interface ProjectCategoryDB extends Omit<ProjectCategory, "_id"> {
_id?: ObjectId;
createdAt: Date;
updatedAt: Date;
}
export interface IProject extends Document {
_id: ObjectId;
title: string;
description: string;
url?: string;
github?: string;
imageUrl?: string;
tags: string[];
status: "completed" | "in-progress" | "planned";
categoryId: ObjectId;
createdAt: Date;
updatedAt: Date;
}
export interface IProjectCategory extends Document {
_id: ObjectId;
name: string;
description: string;
projects: ObjectId[];
createdAt: Date;
updatedAt: Date;
}
const projectSchema = new Schema<IProject>({
title: { type: String, required: true },
description: { type: String, required: true },
url: { type: String },
github: { type: String },
imageUrl: { type: String },
tags: [{ type: String }],
status: {
type: String,
enum: ["completed", "in-progress", "planned"],
required: true
},
categoryId: { type: Schema.Types.ObjectId, ref: 'ProjectCategory', required: true }
}, {
timestamps: true
});
const projectCategorySchema = new Schema<IProjectCategory>({
name: { type: String, required: true },
description: { type: String, required: true },
projects: [{ type: Schema.Types.ObjectId, ref: 'Project' }]
}, {
timestamps: true
});
// Check if models exist before creating new ones
export const Project = mongoose.models.Project || mongoose.model<IProject>('Project', projectSchema);
export const ProjectCategory = mongoose.models.ProjectCategory || mongoose.model<IProjectCategory>('ProjectCategory', projectCategorySchema);
demo
基本功能
展示平时写的一些demo,也算个作品集吧
数据模型
import { ObjectId } from '../utils/objectId';
// API interfaces (for frontend use)
export interface WithTimestamps {
createdAt?: Date | string;
updatedAt?: Date | string;
}
export interface IDemo extends WithTimestamps {
_id?: string | ObjectId;
name: string;
description: string;
url?: string;
gifUrl?: string;
categoryId: string | ObjectId;
tags?: string[];
views: number;
likes: number;
completed: boolean;
}
export interface IDemoCategory extends WithTimestamps {
_id?: string | ObjectId;
name: string;
description?: string;
order?: number;
demos?: IDemo[];
}
// Database interfaces (for MongoDB)
export interface IDemoDB extends Omit<IDemo, '_id'> {
_id?: ObjectId;
}
export interface IDemoCategoryDB extends Omit<IDemoCategory, '_id'> {
_id?: ObjectId;
}
友链
基本功能
展示朋友头像和基本信息
数据模型
import mongoose, { Schema, Document } from 'mongoose';
export interface IFriend extends Document {
avatar: string;
name: string;
title: string;
description: string;
link: string;
position?: string;
location?: string;
isApproved: boolean;
}
const friendSchema = new Schema<IFriend>({
avatar: { type: String, required: true },
name: { type: String, required: true },
title: { type: String, required: true },
description: { type: String, required: true },
link: { type: String, required: true },
position: { type: String },
location: { type: String },
isApproved: { type: Boolean, default: false }
}, {
timestamps: true
});
export const Friend = mongoose.models.Friend || mongoose.model<IFriend>('Friend', friendSchema);