feat: add Google OAuth, user profiles, community hub improvements

- Add Google OAuth sign-in alongside magic link authentication
- Username onboarding: require username selection after first sign-in
- Public profile pages at /u/[username] with social links (GitHub, X)
- Settings page for managing username and social links
- Viewer header: unified floating card with project name, @username, breadcrumb
- Guest CTA on viewer page prompting sign-in
- Show owner avatar + username on community project cards
- Redesigned project cards (larger preview, avatar + stats row below)
- Consistent navbar across hub and profile pages with GitHub link
- Footer with links to GitHub repo and npm packages
- Borderless design with natural shadows throughout
- Apple corner smoothing (squircle) progressive enhancement
- cursor:pointer globally on buttons and links
- DB migrations: username, github_url, x_url columns on auth_users
- Root-level db:generate/migrate/push/studio scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aymeric Rabot
2026-02-19 01:04:37 -05:00
co-authored by Claude Opus 4.6
parent 0fd8656090
commit 62dde6ef5a
30 changed files with 4398 additions and 213 deletions
+10 -1
View File
@@ -13,13 +13,22 @@ export const users = pgTable(
emailVerified: t.boolean('email_verified').notNull().default(false),
name: t.text('name').notNull(),
image: t.text('image'),
/** Public username for the community hub */
username: t.text('username'),
/** GitHub profile URL */
githubUrl: t.text('github_url'),
/** X/Twitter profile URL */
xUrl: t.text('x_url'),
role: userRoles('role').notNull().default('user'),
banned: t.boolean('banned').notNull().default(false),
banReason: t.text('ban_reason'),
banExpires: t.timestamp('ban_expires', { withTimezone: true }),
...timestampsColumns,
}),
(t) => [uniqueIndex('email_unique_index').on(lower(t.email))],
(t) => [
uniqueIndex('email_unique_index').on(lower(t.email)),
uniqueIndex('username_unique_index').on(lower(t.username)),
],
).enableRLS()
export type User = typeof users.$inferSelect