PWA
CI / build (push) Has been skipped
CI / deploy (push) Successful in 1m24s

This commit is contained in:
eewing
2026-02-19 07:41:49 -06:00
parent 5776a1fdb1
commit c0fae761da
10919 changed files with 874329 additions and 13511 deletions
@@ -0,0 +1,23 @@
import { json } from "@sveltejs/kit";
const POST = async ({ request, locals }) => {
if (!locals.user) {
return json({ error: "Unauthorized" }, { status: 401 });
}
let body;
try {
body = await request.json();
} catch {
return json({ error: "Invalid JSON" }, { status: 400 });
}
const darkmode = !!body.darkmode;
try {
await locals.pb.collection("users").update(locals.user.id, { darkmode });
await locals.pb.collection("users").authRefresh();
} catch (e) {
return json({ error: "Update failed" }, { status: 500 });
}
return json({ darkmode });
};
export {
POST
};
@@ -1,4 +1,4 @@
import { g as getContext, f as escape_html } from "../../chunks/index2.js";
import { g as getContext, i as escape_html } from "../../chunks/index2.js";
import "clsx";
import "../../chunks/state.svelte.js";
import "@sveltejs/kit/internal";
@@ -0,0 +1,45 @@
import { redirect } from "@sveltejs/kit";
import PocketBase from "pocketbase";
import { m as mapUserRecord } from "../chunks/user-from-record.js";
const POCKETBASE_URL = process.env.VITE_POCKETBASE_URL ?? "https://pocketbase.ccllc.pro";
const LOGIN_PATH = "/login";
const LOGOUT_PATH = "/logout";
function isPublicRoute(pathname) {
return pathname === LOGIN_PATH || pathname.startsWith(LOGIN_PATH + "/") || pathname === LOGOUT_PATH;
}
const handle = async ({ event, resolve }) => {
event.locals.pb = new PocketBase(POCKETBASE_URL);
event.locals.pb.authStore.loadFromCookie(event.request.headers.get("cookie") ?? "");
try {
if (event.locals.pb.authStore.isValid) {
await event.locals.pb.collection("users").authRefresh();
}
} catch {
event.locals.pb.authStore.clear();
}
const record = event.locals.pb.authStore.record;
if (!record) {
event.locals.user = null;
} else {
try {
const full = await event.locals.pb.collection("users").getOne(record.id);
event.locals.user = mapUserRecord(full);
} catch {
event.locals.user = mapUserRecord(record);
}
}
if (!event.locals.user && !isPublicRoute(event.url.pathname)) {
const redirectTo = event.url.pathname + event.url.search;
const loginUrl = redirectTo && redirectTo !== "/" ? `${LOGIN_PATH}?redirectTo=${encodeURIComponent(redirectTo)}` : LOGIN_PATH;
throw redirect(303, loginUrl);
}
const response = await resolve(event);
response.headers.append(
"set-cookie",
event.locals.pb.authStore.exportToCookie({ httpOnly: false, sameSite: "Lax" })
);
return response;
};
export {
handle
};
@@ -0,0 +1,8 @@
const load = async ({ locals }) => {
return {
user: locals.user
};
};
export {
load
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,33 @@
import { j as ensure_array_like, k as attr, i as escape_html, m as stringify } from "../../chunks/index2.js";
import { B as Button } from "../../chunks/button.js";
import { s as siteSlugs, a as sites } from "../../chunks/sites.js";
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { data } = $$props;
const visibleSlugs = data.user ? siteSlugs.filter((slug) => data.user && data.user[slug] === true) : [];
{
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<main class="flex min-h-0 flex-1 flex-col items-center justify-center gap-4 p-4 sm:gap-6 sm:p-6"><h1 class="text-2xl font-semibold">Base</h1> <div class="flex w-full max-w-xs flex-col gap-3"><!--[-->`);
const each_array = ensure_array_like(visibleSlugs);
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
let slug = each_array[$$index];
const site = sites[slug];
$$renderer2.push(`<a${attr("href", `/${stringify(slug)}`)} class="block">`);
Button($$renderer2, {
class: "h-16 w-full min-h-16",
variant: "outline",
children: ($$renderer3) => {
$$renderer3.push(`<!---->${escape_html(site.title)}`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!----></a>`);
}
$$renderer2.push(`<!--]--></div></main>`);
}
$$renderer2.push(`<!--]-->`);
});
}
export {
_page as default
};
@@ -0,0 +1,10 @@
import "clsx";
function _layout($$renderer, $$props) {
let { children } = $$props;
$$renderer.push(`<div class="site-fullscreen">`);
children?.($$renderer);
$$renderer.push(`<!----></div>`);
}
export {
_layout as default
};
@@ -0,0 +1,17 @@
import { a as sites } from "../../../chunks/sites.js";
import { error } from "@sveltejs/kit";
function load({ params }) {
const slug = params.site?.toLowerCase();
const site = slug && slug in sites ? sites[slug] : null;
if (!site) {
throw error(404, `Unknown site: ${params.site}`);
}
return {
slug,
url: site.url,
title: site.title
};
}
export {
load
};
@@ -0,0 +1,26 @@
import { f as head, k as attr, i as escape_html } from "../../../chunks/index2.js";
import { B as Button } from "../../../chunks/button.js";
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { data } = $$props;
head("mbpe06", $$renderer2, ($$renderer3) => {
$$renderer3.title(($$renderer4) => {
$$renderer4.push(`<title>${escape_html(data.title)} — Base</title>`);
});
});
$$renderer2.push(`<main class="relative flex-1 min-h-0 min-w-0 flex flex-col"><iframe id="app-iframe"${attr("title", data.title)}${attr("src", data.url)} class="absolute inset-0 w-full h-full border-0 rounded-none"></iframe> <div class="absolute top-2 left-1/2 -translate-x-1/2 z-10 flex items-center justify-center pointer-events-none pt-[env(safe-area-inset-top)]" aria-hidden="true"><div class="pointer-events-auto"><a href="/">`);
Button($$renderer2, {
type: "button",
variant: "secondary",
class: "shadow-md",
children: ($$renderer3) => {
$$renderer3.push(`<!---->Base`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!----></a></div></div></main>`);
});
}
export {
_page as default
};
@@ -0,0 +1,38 @@
import { redirect } from "@sveltejs/kit";
const load = async ({ url, locals }) => {
if (locals.user) {
throw redirect(303, url.searchParams.get("redirectTo") ?? "/");
}
return {
redirectTo: url.searchParams.get("redirectTo") ?? "",
error: null
};
};
const actions = {
default: async ({ request, locals, url }) => {
const formData = await request.formData();
const email = String(formData.get("email") ?? "").trim();
const password = String(formData.get("password") ?? "");
const redirectTo = String(formData.get("redirectTo") ?? "").trim() || "/";
if (!email || !password) {
return {
redirectTo,
error: "Email and password are required."
};
}
try {
await locals.pb.collection("users").authWithPassword(email, password);
} catch (err) {
const message = err && typeof err === "object" && "message" in err ? String(err.message) : "Invalid email or password.";
return {
redirectTo,
error: message
};
}
throw redirect(303, redirectTo);
}
};
export {
actions,
load
};
@@ -0,0 +1,157 @@
import { b as attributes, o as clsx, c as bind_props, k as attr, i as escape_html } from "../../../chunks/index2.js";
import "@sveltejs/kit/internal";
import "../../../chunks/exports.js";
import "../../../chunks/utils.js";
import "@sveltejs/kit/internal/server";
import "../../../chunks/root.js";
import "../../../chunks/state.svelte.js";
import { B as Button } from "../../../chunks/button.js";
import { c as cn } from "../../../chunks/utils2.js";
import { L as Label } from "../../../chunks/label.js";
import { C as Card, a as Card_header, b as Card_title, c as Card_description, d as Card_content } from "../../../chunks/card-title.js";
import "clsx";
function Input($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
value = void 0,
type,
files = void 0,
class: className,
"data-slot": dataSlot = "input",
$$slots,
$$events,
...restProps
} = $$props;
if (type === "file") {
$$renderer2.push("<!--[-->");
$$renderer2.push(`<input${attributes(
{
"data-slot": dataSlot,
class: clsx(cn("selection:bg-primary dark:bg-input/30 selection:text-primary-foreground border-input ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 pt-1.5 text-sm font-medium shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className)),
type: "file",
...restProps
},
void 0,
void 0,
void 0,
4
)}/>`);
} else {
$$renderer2.push("<!--[!-->");
$$renderer2.push(`<input${attributes(
{
"data-slot": dataSlot,
class: clsx(cn("border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className)),
type,
value,
...restProps
},
void 0,
void 0,
void 0,
4
)}/>`);
}
$$renderer2.push(`<!--]-->`);
bind_props($$props, { ref, value, files });
});
}
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { data, formAction } = $$props;
const redirectTo = data.form?.redirectTo ?? data.redirectTo ?? "";
const error = data.form?.error;
$$renderer2.push(`<div class="app-shell max-w-sm mx-auto w-full">`);
$$renderer2.push("<!---->");
Card?.($$renderer2, {
children: ($$renderer3) => {
$$renderer3.push("<!---->");
Card_header?.($$renderer3, {
children: ($$renderer4) => {
$$renderer4.push("<!---->");
Card_title?.($$renderer4, {
children: ($$renderer5) => {
$$renderer5.push(`<!---->Sign in`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----> `);
$$renderer4.push("<!---->");
Card_description?.($$renderer4, {
children: ($$renderer5) => {
$$renderer5.push(`<!---->Enter your email and password.`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!----> `);
$$renderer3.push("<!---->");
Card_content?.($$renderer3, {
children: ($$renderer4) => {
$$renderer4.push(`<form method="POST"${attr("action", formAction)} class="flex flex-col gap-4"><input type="hidden" name="redirectTo"${attr("value", redirectTo)}/> <div class="grid gap-2">`);
Label($$renderer4, {
for: "email",
children: ($$renderer5) => {
$$renderer5.push(`<!---->Email`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----> `);
Input($$renderer4, {
id: "email",
name: "email",
type: "email",
placeholder: "you@example.com",
required: true,
autocomplete: "email"
});
$$renderer4.push(`<!----></div> <div class="grid gap-2">`);
Label($$renderer4, {
for: "password",
children: ($$renderer5) => {
$$renderer5.push(`<!---->Password`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----> `);
Input($$renderer4, {
id: "password",
name: "password",
type: "password",
required: true,
autocomplete: "current-password"
});
$$renderer4.push(`<!----></div> `);
if (error) {
$$renderer4.push("<!--[-->");
$$renderer4.push(`<p class="text-sm text-destructive">${escape_html(error)}</p>`);
} else {
$$renderer4.push("<!--[!-->");
}
$$renderer4.push(`<!--]--> `);
Button($$renderer4, {
type: "submit",
class: "w-full",
children: ($$renderer5) => {
$$renderer5.push(`<!---->Sign in`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----></form>`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!----></div>`);
});
}
export {
_page as default
};
@@ -0,0 +1,10 @@
import { redirect } from "@sveltejs/kit";
const actions = {
default: async ({ locals }) => {
locals.pb.authStore.clear();
throw redirect(303, "/login");
}
};
export {
actions
};
@@ -0,0 +1,23 @@
import { k as attr } from "../../../chunks/index2.js";
import "@sveltejs/kit/internal";
import "../../../chunks/exports.js";
import "../../../chunks/utils.js";
import "@sveltejs/kit/internal/server";
import "../../../chunks/root.js";
import "../../../chunks/state.svelte.js";
import { B as Button } from "../../../chunks/button.js";
function _page($$renderer, $$props) {
let { formAction } = $$props;
$$renderer.push(`<div class="app-shell flex items-center justify-center min-h-[200px]"><form method="POST"${attr("action", formAction)}>`);
Button($$renderer, {
type: "submit",
children: ($$renderer2) => {
$$renderer2.push(`<!---->Log out`);
},
$$slots: { default: true }
});
$$renderer.push(`<!----></form></div>`);
}
export {
_page as default
};
@@ -0,0 +1,15 @@
import { error } from "@sveltejs/kit";
import { m as mapUserRecord } from "../../../../chunks/user-from-record.js";
const load = 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);
return { user: mapUserRecord(record) };
} catch {
throw error(404, "User not found");
}
};
export {
load
};
@@ -0,0 +1,74 @@
import { f as head, i as escape_html } from "../../../../chunks/index2.js";
import { C as Card, a as Card_header, b as Card_title, c as Card_description, d as Card_content } from "../../../../chunks/card-title.js";
import "clsx";
import { B as Button } from "../../../../chunks/button.js";
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { data } = $$props;
const user = data.user;
head("xnw5yb", $$renderer2, ($$renderer3) => {
$$renderer3.title(($$renderer4) => {
$$renderer4.push(`<title>${escape_html(user.name ?? user.email ?? "User")} — Base</title>`);
});
});
$$renderer2.push(`<main class="flex min-h-0 flex-1 flex-col gap-4 p-4 sm:gap-6 sm:p-6"><a href="/users" class="self-start">`);
Button($$renderer2, {
variant: "ghost",
size: "sm",
children: ($$renderer3) => {
$$renderer3.push(`<!---->← Users`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!----></a> `);
$$renderer2.push("<!---->");
Card?.($$renderer2, {
class: "max-w-md",
children: ($$renderer3) => {
$$renderer3.push("<!---->");
Card_header?.($$renderer3, {
children: ($$renderer4) => {
$$renderer4.push("<!---->");
Card_title?.($$renderer4, {
children: ($$renderer5) => {
$$renderer5.push(`<!---->${escape_html(user.name ?? user.email ?? user.id)}`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----> `);
if (user.email) {
$$renderer4.push("<!--[-->");
$$renderer4.push("<!---->");
Card_description?.($$renderer4, {
children: ($$renderer5) => {
$$renderer5.push(`<!---->${escape_html(user.email)}`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!---->`);
} else {
$$renderer4.push("<!--[!-->");
}
$$renderer4.push(`<!--]-->`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!----> `);
$$renderer3.push("<!---->");
Card_content?.($$renderer3, {
class: "flex flex-col gap-2",
children: ($$renderer4) => {
$$renderer4.push(`<p class="text-muted-foreground text-sm"><span class="font-medium text-foreground">Access:</span><br/> Prism ${escape_html(user.prism ? "✓" : "—")} · TasGrid ${escape_html(user.tasgrid ? "✓" : "—")} · Stackq ${escape_html(user.stackq ? "✓" : "—")} · HRM ${escape_html(user.hrm ? "✓" : "—")}</p> <p class="text-muted-foreground text-sm"><span class="font-medium text-foreground">Dark mode:</span> ${escape_html(user.darkmode ? "On" : "Off")}</p>`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!----></main>`);
});
}
export {
_page as default
};
@@ -0,0 +1,9 @@
import { m as mapUserRecord } from "../../../chunks/user-from-record.js";
const load = async ({ locals }) => {
const list = await locals.pb.collection("users").getFullList();
const users = list.map((r) => mapUserRecord(r));
return { users };
};
export {
load
};
@@ -0,0 +1,111 @@
import { b as attributes, o as clsx, c as bind_props, f as head, j as ensure_array_like, i as escape_html, k as attr, m as stringify } from "../../../chunks/index2.js";
import { C as Card, a as Card_header, b as Card_title, c as Card_description, d as Card_content } from "../../../chunks/card-title.js";
import { c as cn } from "../../../chunks/utils2.js";
import "clsx";
import { B as Button } from "../../../chunks/button.js";
function Card_footer($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let {
ref = null,
class: className,
children,
$$slots,
$$events,
...restProps
} = $$props;
$$renderer2.push(`<div${attributes({
"data-slot": "card-footer",
class: clsx(cn("flex items-center px-6 [.border-t]:pt-6", className)),
...restProps
})}>`);
children?.($$renderer2);
$$renderer2.push(`<!----></div>`);
bind_props($$props, { ref });
});
}
function _page($$renderer, $$props) {
$$renderer.component(($$renderer2) => {
let { data } = $$props;
head("9fk07v", $$renderer2, ($$renderer3) => {
$$renderer3.title(($$renderer4) => {
$$renderer4.push(`<title>Users — Base</title>`);
});
});
$$renderer2.push(`<main class="flex min-h-0 flex-1 flex-col gap-4 p-4 sm:gap-6 sm:p-6"><h1 class="text-2xl font-semibold">Users</h1> <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3"><!--[-->`);
const each_array = ensure_array_like(data.users);
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
let user = each_array[$$index];
$$renderer2.push("<!---->");
Card?.($$renderer2, {
class: "flex flex-col",
children: ($$renderer3) => {
$$renderer3.push("<!---->");
Card_header?.($$renderer3, {
class: "flex flex-row items-center gap-3",
children: ($$renderer4) => {
$$renderer4.push(`<div class="flex size-10 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground text-sm font-medium">${escape_html(user.name ? String(user.name).slice(0, 2).toUpperCase() : user.email ? String(user.email).slice(0, 2).toUpperCase() : "?")}</div> <div class="min-w-0 flex-1">`);
$$renderer4.push("<!---->");
Card_title?.($$renderer4, {
class: "truncate",
children: ($$renderer5) => {
$$renderer5.push(`<!---->${escape_html(user.name ?? user.email ?? user.id)}`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----> `);
if (user.email && user.name) {
$$renderer4.push("<!--[-->");
$$renderer4.push("<!---->");
Card_description?.($$renderer4, {
class: "truncate text-xs",
children: ($$renderer5) => {
$$renderer5.push(`<!---->${escape_html(user.email)}`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!---->`);
} else {
$$renderer4.push("<!--[!-->");
}
$$renderer4.push(`<!--]--></div>`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!----> `);
$$renderer3.push("<!---->");
Card_content?.($$renderer3, {
class: "flex-1",
children: ($$renderer4) => {
$$renderer4.push(`<p class="text-muted-foreground text-sm">Prism ${escape_html(user.prism ? "✓" : "—")} · TasGrid ${escape_html(user.tasgrid ? "✓" : "—")} · Stackq ${escape_html(user.stackq ? "✓" : "—")} · HRM ${escape_html(user.hrm ? "✓" : "—")}</p>`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!----> `);
$$renderer3.push("<!---->");
Card_footer?.($$renderer3, {
children: ($$renderer4) => {
$$renderer4.push(`<a${attr("href", `/users/${stringify(user.id)}`)} class="block">`);
Button($$renderer4, {
variant: "outline",
class: "w-full",
children: ($$renderer5) => {
$$renderer5.push(`<!---->View`);
},
$$slots: { default: true }
});
$$renderer4.push(`<!----></a>`);
},
$$slots: { default: true }
});
$$renderer3.push(`<!---->`);
},
$$slots: { default: true }
});
$$renderer2.push(`<!---->`);
}
$$renderer2.push(`<!--]--></div></main>`);
});
}
export {
_page as default
};