style: 统一代码风格 — 格式化 auth schema、修复 setup 页面 return 语句、规范 drizzle snapshot

This commit is contained in:
2026-03-31 22:46:47 +08:00
parent 9f39e7f7e8
commit dcccf6675f
4 changed files with 151 additions and 172 deletions
+13 -37
View File
@@ -110,12 +110,8 @@
"name": "account_user_id_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -202,12 +198,8 @@
"name": "session_user_id_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -217,9 +209,7 @@
"session_token_unique": {
"name": "session_token_unique",
"nullsNotDistinct": false,
"columns": [
"token"
]
"columns": ["token"]
}
},
"policies": {},
@@ -283,9 +273,7 @@
"user_email_unique": {
"name": "user_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
"columns": ["email"]
}
},
"policies": {},
@@ -434,12 +422,8 @@
"name": "bookmark_category_id_category_id_fk",
"tableFrom": "bookmark",
"tableTo": "category",
"columnsFrom": [
"category_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["category_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
@@ -447,12 +431,8 @@
"name": "bookmark_user_id_user_id_fk",
"tableFrom": "bookmark",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -527,12 +507,8 @@
"name": "category_user_id_user_id_fk",
"tableFrom": "category",
"tableTo": "user",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"columnsFrom": ["user_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
@@ -555,4 +531,4 @@
"schemas": {},
"tables": {}
}
}
}
+1 -1
View File
@@ -10,4 +10,4 @@
"breakpoints": true
}
]
}
}
+85 -82
View File
@@ -52,90 +52,93 @@ function SetupPage() {
router.navigate({ to: '/' as never })
}
;<div className="min-h-screen bg-slate-50 flex items-center justify-center px-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-slate-900 tracking-tight">Kairos</h1>
<p className="text-slate-500 mt-2"></p>
</div>
<div className="bg-white rounded-2xl shadow-[0_8px_30px_rgb(0,0,0,0.04)] ring-1 ring-slate-100 p-8">
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label htmlFor="name" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="name"
type="text"
required
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="你的名字"
return (
<div className="min-h-screen bg-slate-50 flex items-center justify-center px-4">
<div className="w-full max-w-md">
<div className="text-center mb-8">
<h1 className="text-4xl font-bold text-slate-900 tracking-tight">Kairos</h1>
<p className="text-slate-500 mt-2"></p>
</div>
<div className="bg-white rounded-2xl shadow-[0_8px_30px_rgb(0,0,0,0.04)] ring-1 ring-slate-100 p-8">
<form onSubmit={handleSubmit} className="space-y-5">
<div>
<label htmlFor="name" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="name"
type="text"
required
value={name}
onChange={(e) => setName(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="你的名字"
disabled={loading}
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="email"
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="your@email.com"
disabled={loading}
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="password"
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="至少 8 个字符"
disabled={loading}
/>
</div>
<div>
<label htmlFor="confirmPassword" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="confirmPassword"
type="password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="再次输入密码"
disabled={loading}
/>
</div>
{error && <p className="text-sm text-red-600">{error}</p>}
<button
type="submit"
disabled={loading}
/>
</div>
<div>
<label htmlFor="email" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="email"
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="your@email.com"
disabled={loading}
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="password"
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="至少 8 个字符"
disabled={loading}
/>
</div>
<div>
<label htmlFor="confirmPassword" className="block text-sm font-medium text-slate-700 mb-1.5">
</label>
<input
id="confirmPassword"
type="password"
required
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
className="w-full px-4 py-3 rounded-xl bg-slate-50 border-0 ring-1 ring-slate-200 focus:ring-2 focus:ring-indigo-500 outline-none transition-all text-slate-700 placeholder:text-slate-400"
placeholder="再次输入密码"
disabled={loading}
/>
</div>
{error && <p className="text-sm text-red-600">{error}</p>}
<button
type="submit"
disabled={loading}
className="w-full py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl font-medium transition-all shadow-md shadow-indigo-200 disabled:opacity-50 disabled:shadow-none hover:shadow-lg hover:shadow-indigo-300 active:scale-[0.98]"
>
{loading ? '初始化中...' : '开始使用 Kairos'}
</button>
</form>
className="w-full py-3 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl font-medium transition-all shadow-md shadow-indigo-200 disabled:opacity-50 disabled:shadow-none hover:shadow-lg hover:shadow-indigo-300 active:scale-[0.98]"
>
{loading ? '初始化中...' : '开始使用 Kairos'}
</button>
</form>
</div>
</div>
</div>
</div>
)
}
+52 -52
View File
@@ -1,93 +1,93 @@
import { relations } from "drizzle-orm";
import { pgTable, text, timestamp, boolean, index } from "drizzle-orm/pg-core";
import { relations } from 'drizzle-orm'
import { boolean, index, pgTable, text, timestamp } from 'drizzle-orm/pg-core'
export const user = pgTable("user", {
id: text("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
emailVerified: boolean("email_verified").default(false).notNull(),
image: text("image"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
export const user = pgTable('user', {
id: text('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
emailVerified: boolean('email_verified').default(false).notNull(),
image: text('image'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.defaultNow()
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
});
})
export const session = pgTable(
"session",
'session',
{
id: text("id").primaryKey(),
expiresAt: timestamp("expires_at").notNull(),
token: text("token").notNull().unique(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
id: text('id').primaryKey(),
expiresAt: timestamp('expires_at').notNull(),
token: text('token').notNull().unique(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
userId: text("user_id")
ipAddress: text('ip_address'),
userAgent: text('user_agent'),
userId: text('user_id')
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
.references(() => user.id, { onDelete: 'cascade' }),
},
(table) => [index("session_userId_idx").on(table.userId)],
);
(table) => [index('session_userId_idx').on(table.userId)],
)
export const account = pgTable(
"account",
'account',
{
id: text("id").primaryKey(),
accountId: text("account_id").notNull(),
providerId: text("provider_id").notNull(),
userId: text("user_id")
id: text('id').primaryKey(),
accountId: text('account_id').notNull(),
providerId: text('provider_id').notNull(),
userId: text('user_id')
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
accessToken: text("access_token"),
refreshToken: text("refresh_token"),
idToken: text("id_token"),
accessTokenExpiresAt: timestamp("access_token_expires_at"),
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
scope: text("scope"),
password: text("password"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
.references(() => user.id, { onDelete: 'cascade' }),
accessToken: text('access_token'),
refreshToken: text('refresh_token'),
idToken: text('id_token'),
accessTokenExpiresAt: timestamp('access_token_expires_at'),
refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
scope: text('scope'),
password: text('password'),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
},
(table) => [index("account_userId_idx").on(table.userId)],
);
(table) => [index('account_userId_idx').on(table.userId)],
)
export const verification = pgTable(
"verification",
'verification',
{
id: text("id").primaryKey(),
identifier: text("identifier").notNull(),
value: text("value").notNull(),
expiresAt: timestamp("expires_at").notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at")
id: text('id').primaryKey(),
identifier: text('identifier').notNull(),
value: text('value').notNull(),
expiresAt: timestamp('expires_at').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
updatedAt: timestamp('updated_at')
.defaultNow()
.$onUpdate(() => /* @__PURE__ */ new Date())
.notNull(),
},
(table) => [index("verification_identifier_idx").on(table.identifier)],
);
(table) => [index('verification_identifier_idx').on(table.identifier)],
)
export const userRelations = relations(user, ({ many }) => ({
sessions: many(session),
accounts: many(account),
}));
}))
export const sessionRelations = relations(session, ({ one }) => ({
user: one(user, {
fields: [session.userId],
references: [user.id],
}),
}));
}))
export const accountRelations = relations(account, ({ one }) => ({
user: one(user, {
fields: [account.userId],
references: [user.id],
}),
}));
}))