You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

200 lines
8.1 KiB

import "./env";
import { dbGlobal } from "./lib/db";
import { categories, tags, items, itemTags } from "./lib/schema/collection";
import { users } from "./lib/schema/auth";
import { hash } from "bcryptjs";
async function main() {
// Create demo user if not exists
const [demoUser] = await dbGlobal
.insert(users)
.values({
username: "demo",
password: await hash("demo1234", 12),
nickname: "陈",
role: "user",
})
.onConflictDoNothing()
.returning({ id: users.id });
const userId = demoUser?.id;
if (!userId) {
console.log("Demo user already exists, skipping seed.");
// process.exit(0);
}
// Create categories
const catDesign = await dbGlobal
.insert(categories)
.values({ name: "设计", icon: "🎨", color: "#c8a97e" })
.returning()
.then((r) => r[0]);
const catUI = await dbGlobal
.insert(categories)
.values({ name: "UI / 交互", icon: "🖥️", color: "#5db8a0", parentId: catDesign.id, sortOrder: 1 })
.returning()
.then((r) => r[0]);
const catFont = await dbGlobal
.insert(categories)
.values({ name: "字体排版", icon: "🔤", color: "#9d88d4", parentId: catDesign.id, sortOrder: 2 })
.returning()
.then((r) => r[0]);
const catAI = await dbGlobal
.insert(categories)
.values({ name: "AI / 技术", icon: "🤖", color: "#6da4d4" })
.returning()
.then((r) => r[0]);
const catRead = await dbGlobal
.insert(categories)
.values({ name: "阅读 / 思考", icon: "📚", color: "#d46d6d" })
.returning()
.then((r) => r[0]);
// Create tags
const tagNames = ["值得深读", "灵感", "参考资料", "AI工具", "设计"];
const tagMap: Record<string, number> = {};
for (const name of tagNames) {
const [tag] = await dbGlobal
.insert(tags)
.values({ name, color: name === "灵感" ? "#9d88d4" : name === "AI工具" ? "#6da4d4" : name === "设计" ? "#5db8a0" : "#c8a97e" })
.returning();
tagMap[name] = tag.id;
}
// Demo items from prototype
const demoItems = [
{
type: "web" as const,
title: "Vercel 设计系统 2024 更新:新组件库与动效规范",
description: "Vercel 团队分享了最新的设计系统更新,包括全新的 Radix 组件封装、Motion 动效库集成和无障碍规范改进。",
url: "https://vercel.com/design",
sourceHost: "vercel.com",
tagNames: ["设计", "参考资料"],
starred: true,
rating: 4,
note: "重点关注他们的 Motion 实现方案,和我们的项目需求很贴近。",
aiSummary: "文章详细介绍了 Vercel 如何重构其设计系统,核心思路是「组件即文档」——每个组件自带使用示例和无障碍说明。动效方面引入了基于物理的弹簧动画替代传统缓动曲线。",
categoryId: catDesign.id,
},
{
type: "text" as const,
title: "关于「慢阅读」的思考碎片",
description: "在信息爆炸时代,我们需要主动降速。真正的理解需要摩擦感,需要反复咀嚼,需要停下来想一想。",
sourceHost: "个人笔记",
tagNames: ["灵感", "值得深读"],
rating: 5,
note: "这段话在地铁上想到的,和最近读《深度工作》有关。",
aiSummary: "这段文字探讨了现代人与信息的关系——我们消费的速度远超消化的速度。提出「慢阅读」作为一种对抗信息焦虑的实践方法。",
categoryId: catRead.id,
},
{
type: "web" as const,
title: "2024 年最值得关注的 AI 设计工具合集",
description: "涵盖 Galileo AI、Uizard、Framer AI 等 14 款工具的深度对比,从生成质量、可控性、工作流融合三个维度评分。",
url: "https://uxdesign.cc/ai-design-tools",
sourceHost: "uxdesign.cc",
tagNames: ["AI工具", "设计"],
starred: true,
rating: 4,
aiSummary: "文章系统比较了当前主流 AI 设计工具,结论是 Framer AI 在工作流融合上领先,但 Galileo AI 的生成质量更高。建议根据团队使用场景分开选择。",
categoryId: catAI.id,
},
{
type: "image" as const,
title: "Teenage Engineering OP-1 产品摄影参考",
description: "极简主义硬件产品的摄影风格:高对比、单色背景、精准的光影层次,彰显工业美学。",
sourceHost: "Dribbble",
tagNames: ["灵感", "设计"],
rating: 3,
note: "下次产品拍摄可以参考这种风格。",
aiSummary: "这组产品摄影展示了如何用极简布景突出产品本身的设计语言——没有任何多余道具,只有主体、光线和阴影的对话。",
categoryId: catDesign.id,
},
{
type: "video" as const,
title: "3Blue1Brown: 神经网络的可视化解释",
description: "通过动态几何可视化,直觉上理解反向传播、梯度下降和神经元激活的工作原理,无需数学公式。",
url: "https://youtube.com/watch?v=aircAruvnKk",
sourceHost: "YouTube",
tagNames: ["AI工具", "参考资料", "值得深读"],
starred: true,
rating: 5,
note: "最好的 ML 入门视频,没有之一。准备在团队分享会上播放。",
aiSummary: "Grant 用其标志性的数学可视化风格,将反向传播从一个抽象算法变成可以「看到」的几何变换过程,极大降低了理解门槛。",
categoryId: catAI.id,
},
{
type: "doc" as const,
title: "《设计系统:企业级 UI 的构建法则》PDF",
description: "Nathan Curtis 的经典著作,详述如何从零搭建可维护的设计系统,包含 Figma 组织规范和开发交接流程。",
sourceHost: "PDF 文档",
tagNames: ["设计", "参考资料"],
rating: 4,
note: "第三章关于 Token 体系的部分要精读,跟我们的需求高度相关。",
aiSummary: "本书是目前最系统的设计系统建设指南,核心观点:设计系统不是组件库,而是一套治理语言和协作流程。",
},
{
type: "web" as const,
title: "Raycast 如何在产品增长上做了哪些正确的事",
description: "从 0 到 100 万用户的增长路径复盘:产品主导增长、开发者社区、插件生态三大飞轮如何协同运转。",
url: "https://raycast.com/blog",
sourceHost: "raycast.com",
tagNames: ["灵感", "值得深读"],
rating: 3,
aiSummary: "Raycast 的增长故事印证了「产品即渠道」的理念——当工具足够好用,用户自然成为传播者。插件生态是其最聪明的护城河策略。",
categoryId: catRead.id,
},
{
type: "text" as const,
title: "设计师应该学代码吗?我的答案变了三次",
description: "从「完全没必要」到「会一点很好」再到「这个问题本身就是错的」——真正的边界在于理解,而不在于实现。",
sourceHost: "个人笔记",
tagNames: ["灵感", "设计"],
starred: true,
rating: 4,
note: "这是我要写的下一篇文章的核心论点。",
aiSummary: "作者认为「设计师要不要学代码」这个问题预设了一个错误的二元对立。更好的问题是:如何建立跨越学科的理解力?",
categoryId: catDesign.id,
},
];
for (const d of demoItems) {
const [item] = await dbGlobal
.insert(items)
.values({
userId,
type: d.type,
title: d.title,
description: d.description,
url: d.url || null,
sourceHost: d.sourceHost,
categoryId: d.categoryId || null,
note: d.note || null,
rating: d.rating || null,
starred: d.starred ?? false,
aiSummary: d.aiSummary || null,
})
.returning();
if (d.tagNames && item) {
for (const tn of d.tagNames) {
const tagId = tagMap[tn];
if (tagId) {
await dbGlobal.insert(itemTags).values({ itemId: item.id, tagId });
}
}
}
}
console.log("Seed complete! Demo user: demo / demo1234");
process.exit(0);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});