From 5776a1fdb1bbbdf804b36158224d183813499cea Mon Sep 17 00:00:00 2001 From: eewing Date: Wed, 18 Feb 2026 15:59:16 -0600 Subject: [PATCH] Enhance user routing and layout management. Added support for user-specific routes, including dynamic user ID handling and updated component imports. Improved type definitions and user data mapping in hooks for better user experience. --- .svelte-kit/generated/client/app.js | 10 ++-- .svelte-kit/generated/client/nodes/5.js | 2 +- .svelte-kit/generated/client/nodes/6.js | 2 +- .svelte-kit/generated/client/nodes/7.js | 1 + .svelte-kit/generated/client/nodes/8.js | 1 + .svelte-kit/generated/server/internal.js | 2 +- .svelte-kit/non-ambient.d.ts | 9 ++-- .svelte-kit/types/route_meta_data.json | 8 ++++ .svelte-kit/types/src/routes/$types.d.ts | 4 +- .../types/src/routes/users/$types.d.ts | 25 ++++++++++ .../types/src/routes/users/[id]/$types.d.ts | 26 +++++++++++ .../routes/users/[id]/proxy+page.server.ts | 15 ++++++ .../src/routes/users/proxy+page.server.ts | 9 ++++ src/app.d.ts | 12 ++++- src/hooks.server.ts | 20 ++++---- src/lib/user-from-record.ts | 28 +++++++++++ src/routes/+page.svelte | 12 +++-- src/routes/HomeWithDialog.svelte | 13 ++++-- src/routes/users/+page.server.ts | 8 ++++ src/routes/users/+page.svelte | 46 +++++++++++++++++++ src/routes/users/[id]/+page.server.ts | 14 ++++++ src/routes/users/[id]/+page.svelte | 35 ++++++++++++++ 22 files changed, 274 insertions(+), 28 deletions(-) create mode 100644 .svelte-kit/generated/client/nodes/7.js create mode 100644 .svelte-kit/generated/client/nodes/8.js create mode 100644 .svelte-kit/types/src/routes/users/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/users/[id]/$types.d.ts create mode 100644 .svelte-kit/types/src/routes/users/[id]/proxy+page.server.ts create mode 100644 .svelte-kit/types/src/routes/users/proxy+page.server.ts create mode 100644 src/lib/user-from-record.ts create mode 100644 src/routes/users/+page.server.ts create mode 100644 src/routes/users/+page.svelte create mode 100644 src/routes/users/[id]/+page.server.ts create mode 100644 src/routes/users/[id]/+page.svelte diff --git a/.svelte-kit/generated/client/app.js b/.svelte-kit/generated/client/app.js index ae6c9a8e..92ad6d19 100644 --- a/.svelte-kit/generated/client/app.js +++ b/.svelte-kit/generated/client/app.js @@ -7,16 +7,20 @@ export const nodes = [ () => import('./nodes/3'), () => import('./nodes/4'), () => import('./nodes/5'), - () => import('./nodes/6') + () => import('./nodes/6'), + () => import('./nodes/7'), + () => import('./nodes/8') ]; export const server_loads = [0]; export const dictionary = { "/": [3], - "/login": [~6], + "/login": [~8], "/logout": [~4], - "/[site]": [~5,[2]] + "/users": [~5], + "/users/[id]": [~6], + "/[site]": [~7,[2]] }; export const hooks = { diff --git a/.svelte-kit/generated/client/nodes/5.js b/.svelte-kit/generated/client/nodes/5.js index 0f681549..81499dfe 100644 --- a/.svelte-kit/generated/client/nodes/5.js +++ b/.svelte-kit/generated/client/nodes/5.js @@ -1 +1 @@ -export { default as component } from "../../../../src/routes/[site]/+page.svelte"; \ No newline at end of file +export { default as component } from "../../../../src/routes/users/+page.svelte"; \ No newline at end of file diff --git a/.svelte-kit/generated/client/nodes/6.js b/.svelte-kit/generated/client/nodes/6.js index f2b26cd1..e240dfec 100644 --- a/.svelte-kit/generated/client/nodes/6.js +++ b/.svelte-kit/generated/client/nodes/6.js @@ -1 +1 @@ -export { default as component } from "../../../../src/routes/login/+page.svelte"; \ No newline at end of file +export { default as component } from "../../../../src/routes/users/[id]/+page.svelte"; \ No newline at end of file diff --git a/.svelte-kit/generated/client/nodes/7.js b/.svelte-kit/generated/client/nodes/7.js new file mode 100644 index 00000000..0f681549 --- /dev/null +++ b/.svelte-kit/generated/client/nodes/7.js @@ -0,0 +1 @@ +export { default as component } from "../../../../src/routes/[site]/+page.svelte"; \ No newline at end of file diff --git a/.svelte-kit/generated/client/nodes/8.js b/.svelte-kit/generated/client/nodes/8.js new file mode 100644 index 00000000..f2b26cd1 --- /dev/null +++ b/.svelte-kit/generated/client/nodes/8.js @@ -0,0 +1 @@ +export { default as component } from "../../../../src/routes/login/+page.svelte"; \ No newline at end of file diff --git a/.svelte-kit/generated/server/internal.js b/.svelte-kit/generated/server/internal.js index fdeb54db..9fd51aa7 100644 --- a/.svelte-kit/generated/server/internal.js +++ b/.svelte-kit/generated/server/internal.js @@ -24,7 +24,7 @@ export const options = { app: ({ head, body, assets, nonce, env }) => "\n\n \n \n \n \n " + head + "\n \n \n
" + body + "
\n \n\n", error: ({ status, message }) => "\n\n\t\n\t\t\n\t\t" + message + "\n\n\t\t\n\t\n\t\n\t\t
\n\t\t\t" + status + "\n\t\t\t
\n\t\t\t\t

" + message + "

\n\t\t\t
\n\t\t
\n\t\n\n" }, - version_hash: "xmp3r" + version_hash: "1untsbf" }; export async function get_hooks() { diff --git a/.svelte-kit/non-ambient.d.ts b/.svelte-kit/non-ambient.d.ts index 7f6a1cb6..d69fb6ae 100644 --- a/.svelte-kit/non-ambient.d.ts +++ b/.svelte-kit/non-ambient.d.ts @@ -27,19 +27,22 @@ export {}; declare module "$app/types" { export interface AppTypes { - RouteId(): "/" | "/api" | "/api/darkmode" | "/login" | "/logout" | "/[site]"; + RouteId(): "/" | "/api" | "/api/darkmode" | "/login" | "/logout" | "/users" | "/users/[id]" | "/[site]"; RouteParams(): { + "/users/[id]": { id: string }; "/[site]": { site: string } }; LayoutParams(): { - "/": { site?: string }; + "/": { id?: string; site?: string }; "/api": Record; "/api/darkmode": Record; "/login": Record; "/logout": Record; + "/users": { id?: string }; + "/users/[id]": { id: string }; "/[site]": { site: string } }; - Pathname(): "/" | "/api/darkmode" | "/login" | "/logout" | `/${string}` & {}; + Pathname(): "/" | "/api/darkmode" | "/login" | "/logout" | "/users" | `/users/${string}` & {} | `/${string}` & {}; ResolvedPathname(): `${"" | `/${string}`}${ReturnType}`; Asset(): string & {}; } diff --git a/.svelte-kit/types/route_meta_data.json b/.svelte-kit/types/route_meta_data.json index 43dfcff7..89faf021 100644 --- a/.svelte-kit/types/route_meta_data.json +++ b/.svelte-kit/types/route_meta_data.json @@ -14,6 +14,14 @@ "src/routes/logout/+page.server.ts", "src/routes/+layout.server.ts" ], + "/users": [ + "src/routes/users/+page.server.ts", + "src/routes/+layout.server.ts" + ], + "/users/[id]": [ + "src/routes/users/[id]/+page.server.ts", + "src/routes/+layout.server.ts" + ], "/[site]": [ "src/routes/[site]/+page.server.ts", "src/routes/+layout.server.ts", diff --git a/.svelte-kit/types/src/routes/$types.d.ts b/.svelte-kit/types/src/routes/$types.d.ts index 88171839..155589bf 100644 --- a/.svelte-kit/types/src/routes/$types.d.ts +++ b/.svelte-kit/types/src/routes/$types.d.ts @@ -12,8 +12,8 @@ type EnsureDefined = T extends null | undefined ? {} : T; type OptionalUnion, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude]?: never } & U : never; export type Snapshot = Kit.Snapshot; type PageParentData = EnsureDefined; -type LayoutRouteId = RouteId | "/" | "/logout" | "/[site]" | "/login" | null -type LayoutParams = RouteParams & { site?: string } +type LayoutRouteId = RouteId | "/" | "/logout" | "/users" | "/users/[id]" | "/[site]" | "/login" | null +type LayoutParams = RouteParams & { id?: string; site?: string } type LayoutServerParentData = EnsureDefined<{}>; type LayoutParentData = EnsureDefined<{}>; diff --git a/.svelte-kit/types/src/routes/users/$types.d.ts b/.svelte-kit/types/src/routes/users/$types.d.ts new file mode 100644 index 00000000..bbefd131 --- /dev/null +++ b/.svelte-kit/types/src/routes/users/$types.d.ts @@ -0,0 +1,25 @@ +import type * as Kit from '@sveltejs/kit'; + +type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; +// @ts-ignore +type MatcherParam = M extends (param : string) => param is infer U ? U extends string ? U : string : string; +type RouteParams = { }; +type RouteId = '/users'; +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T]; +type OutputDataShape = MaybeWithVoid> & Partial> & Record> +type EnsureDefined = T extends null | undefined ? {} : T; +type OptionalUnion, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude]?: never } & U : never; +export type Snapshot = Kit.Snapshot; +type PageServerParentData = EnsureDefined; +type PageParentData = EnsureDefined; + +export type PageServerLoad = OutputDataShape> = Kit.ServerLoad; +export type PageServerLoadEvent = Parameters[0]; +export type ActionData = unknown; +export type PageServerData = Expand>>>>>; +export type PageData = Expand & EnsureDefined>; +export type Action | void = Record | void> = Kit.Action +export type Actions | void = Record | void> = Kit.Actions +export type PageProps = { params: RouteParams; data: PageData; form: ActionData } +export type RequestEvent = Kit.RequestEvent; \ No newline at end of file diff --git a/.svelte-kit/types/src/routes/users/[id]/$types.d.ts b/.svelte-kit/types/src/routes/users/[id]/$types.d.ts new file mode 100644 index 00000000..643b47db --- /dev/null +++ b/.svelte-kit/types/src/routes/users/[id]/$types.d.ts @@ -0,0 +1,26 @@ +import type * as Kit from '@sveltejs/kit'; + +type Expand = T extends infer O ? { [K in keyof O]: O[K] } : never; +// @ts-ignore +type MatcherParam = M extends (param : string) => param is infer U ? U extends string ? U : string : string; +type RouteParams = { id: string }; +type RouteId = '/users/[id]'; +type MaybeWithVoid = {} extends T ? T | void : T; +export type RequiredKeys = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T]; +type OutputDataShape = MaybeWithVoid> & Partial> & Record> +type EnsureDefined = T extends null | undefined ? {} : T; +type OptionalUnion, A extends keyof U = U extends U ? keyof U : never> = U extends unknown ? { [P in Exclude]?: never } & U : never; +export type Snapshot = Kit.Snapshot; +type PageServerParentData = EnsureDefined; +type PageParentData = EnsureDefined; + +export type EntryGenerator = () => Promise> | Array; +export type PageServerLoad = OutputDataShape> = Kit.ServerLoad; +export type PageServerLoadEvent = Parameters[0]; +export type ActionData = unknown; +export type PageServerData = Expand>>>>>; +export type PageData = Expand & EnsureDefined>; +export type Action | void = Record | void> = Kit.Action +export type Actions | void = Record | void> = Kit.Actions +export type PageProps = { params: RouteParams; data: PageData; form: ActionData } +export type RequestEvent = Kit.RequestEvent; \ No newline at end of file diff --git a/.svelte-kit/types/src/routes/users/[id]/proxy+page.server.ts b/.svelte-kit/types/src/routes/users/[id]/proxy+page.server.ts new file mode 100644 index 00000000..0a8c9ff1 --- /dev/null +++ b/.svelte-kit/types/src/routes/users/[id]/proxy+page.server.ts @@ -0,0 +1,15 @@ +// @ts-nocheck +import { error } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; +import { mapUserRecord } from '$lib/user-from-record'; + +export const load = async ({ params, locals }: Parameters[0]) => { + const id = params.id; + if (!id) throw error(404, 'User not found'); + try { + const record = (await locals.pb.collection('users').getOne(id)) as Record; + return { user: mapUserRecord(record) }; + } catch { + throw error(404, 'User not found'); + } +}; diff --git a/.svelte-kit/types/src/routes/users/proxy+page.server.ts b/.svelte-kit/types/src/routes/users/proxy+page.server.ts new file mode 100644 index 00000000..af3d9436 --- /dev/null +++ b/.svelte-kit/types/src/routes/users/proxy+page.server.ts @@ -0,0 +1,9 @@ +// @ts-nocheck +import type { PageServerLoad } from './$types'; +import { mapUserRecord } from '$lib/user-from-record'; + +export const load = async ({ locals }: Parameters[0]) => { + const list = await locals.pb.collection('users').getFullList(); + const users = list.map((r) => mapUserRecord(r as Record)); + return { users }; +}; diff --git a/src/app.d.ts b/src/app.d.ts index 0293fbf8..66ce6de4 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -5,7 +5,17 @@ declare global { namespace App { interface Locals { pb: PocketBase; - user: { id: string; email?: string; name?: string; avatar?: string; darkmode: boolean } | null; + user: { + id: string; + email?: string; + name?: string; + avatar?: string; + darkmode: boolean; + prism?: boolean; + tasgrid?: boolean; + stackq?: boolean; + hrm?: boolean; + } | null; } } } diff --git a/src/hooks.server.ts b/src/hooks.server.ts index d1fa8fd9..e9b82cba 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,6 +1,7 @@ import { redirect } from '@sveltejs/kit'; import PocketBase from 'pocketbase'; import type { Handle } from '@sveltejs/kit'; +import { mapUserRecord } from '$lib/user-from-record'; const POCKETBASE_URL = process.env.VITE_POCKETBASE_URL ?? 'https://pocketbase.ccllc.pro'; @@ -28,15 +29,16 @@ export const handle: Handle = async ({ event, resolve }) => { } const record = event.locals.pb.authStore.record; - event.locals.user = record - ? { - id: record.id, - email: record.email, - name: record.name, - avatar: record.avatar, - darkmode: !!record.darkmode - } - : null; + if (!record) { + event.locals.user = null; + } else { + try { + const full = (await event.locals.pb.collection('users').getOne(record.id)) as Record; + event.locals.user = mapUserRecord(full); + } catch { + event.locals.user = mapUserRecord(record as Record); + } + } if (!event.locals.user && !isPublicRoute(event.url.pathname)) { const redirectTo = event.url.pathname + event.url.search; diff --git a/src/lib/user-from-record.ts b/src/lib/user-from-record.ts new file mode 100644 index 00000000..bb774e4c --- /dev/null +++ b/src/lib/user-from-record.ts @@ -0,0 +1,28 @@ +/** + * Map a PocketBase users collection record to our app user shape. + * Handles multiple possible field names (PRISM, prism, TasGrid, etc.). + */ + +function bool(r: Record, ...keys: string[]): boolean { + for (const k of keys) { + const v = r[k]; + if (v === true || v === 'true') return true; + } + return false; +} + +export type UserFromRecord = NonNullable; + +export function mapUserRecord(r: Record): UserFromRecord { + return { + id: r.id as string, + email: r.email as string | undefined, + name: r.name as string | undefined, + avatar: r.avatar as string | undefined, + darkmode: bool(r, 'darkmode'), + prism: bool(r, 'PRISM', 'prism', 'Prism'), + tasgrid: bool(r, 'TasGrid', 'tasgrid'), + stackq: bool(r, 'Stackq', 'stackq'), + hrm: bool(r, 'HRM', 'hrm', 'Hrm') + }; +} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index beaf145a..176bd309 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,9 +1,15 @@ {#if browser} @@ -18,7 +24,7 @@

Base

- {#each siteSlugs as slug} + {#each visibleSlugs as slug} {@const site = sites[slug]} diff --git a/src/routes/HomeWithDialog.svelte b/src/routes/HomeWithDialog.svelte index d3dea964..266449e6 100644 --- a/src/routes/HomeWithDialog.svelte +++ b/src/routes/HomeWithDialog.svelte @@ -1,15 +1,20 @@

Base

- {#each siteSlugs as slug} + {#each visibleSlugs as slug} {@const site = sites[slug]} + + + + {/each} +
+
diff --git a/src/routes/users/[id]/+page.server.ts b/src/routes/users/[id]/+page.server.ts new file mode 100644 index 00000000..16854cf0 --- /dev/null +++ b/src/routes/users/[id]/+page.server.ts @@ -0,0 +1,14 @@ +import { error } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; +import { mapUserRecord } from '$lib/user-from-record'; + +export const load: PageServerLoad = async ({ params, locals }) => { + const id = params.id; + if (!id) throw error(404, 'User not found'); + try { + const record = (await locals.pb.collection('users').getOne(id)) as Record; + return { user: mapUserRecord(record) }; + } catch { + throw error(404, 'User not found'); + } +}; diff --git a/src/routes/users/[id]/+page.svelte b/src/routes/users/[id]/+page.svelte new file mode 100644 index 00000000..0c88f1ec --- /dev/null +++ b/src/routes/users/[id]/+page.svelte @@ -0,0 +1,35 @@ + + + + {user.name ?? user.email ?? 'User'} — Base + + +
+ + + + + + {user.name ?? user.email ?? user.id} + {#if user.email} + {user.email} + {/if} + + +

+ Access:
+ Prism {user.prism ? '✓' : '—'} · TasGrid {user.tasgrid ? '✓' : '—'} · Stackq {user.stackq ? '✓' : '—'} · HRM {user.hrm ? '✓' : '—'} +

+

+ Dark mode: {user.darkmode ? 'On' : 'Off'} +

+
+
+