This commit is contained in:
@@ -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
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import { g as getContext, f as escape_html } from "../../chunks/index2.js";
|
||||
import "clsx";
|
||||
import "../../chunks/state.svelte.js";
|
||||
import "@sveltejs/kit/internal";
|
||||
import "../../chunks/exports.js";
|
||||
import "../../chunks/utils.js";
|
||||
import { w as writable } from "../../chunks/index.js";
|
||||
import "@sveltejs/kit/internal/server";
|
||||
import "../../chunks/root.js";
|
||||
function create_updated_store() {
|
||||
const { set, subscribe } = writable(false);
|
||||
{
|
||||
return {
|
||||
subscribe,
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
check: async () => false
|
||||
};
|
||||
}
|
||||
}
|
||||
const stores = {
|
||||
updated: /* @__PURE__ */ create_updated_store()
|
||||
};
|
||||
({
|
||||
check: stores.updated.check
|
||||
});
|
||||
function context() {
|
||||
return getContext("__request__");
|
||||
}
|
||||
const page$1 = {
|
||||
get error() {
|
||||
return context().page.error;
|
||||
},
|
||||
get status() {
|
||||
return context().page.status;
|
||||
}
|
||||
};
|
||||
const page = page$1;
|
||||
function Error$1($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
$$renderer2.push(`<h1>${escape_html(page.status)}</h1> <p>${escape_html(page.error?.message)}</p>`);
|
||||
});
|
||||
}
|
||||
export {
|
||||
Error$1 as default
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { redirect } from "@sveltejs/kit";
|
||||
import PocketBase from "pocketbase";
|
||||
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;
|
||||
event.locals.user = record ? {
|
||||
id: record.id,
|
||||
email: record.email,
|
||||
name: record.name,
|
||||
avatar: record.avatar,
|
||||
darkmode: !!record.darkmode
|
||||
} : null;
|
||||
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,48 @@
|
||||
import "clsx";
|
||||
import { B as Button } from "../../chunks/button.js";
|
||||
function _page($$renderer, $$props) {
|
||||
let { data } = $$props;
|
||||
{
|
||||
$$renderer.push("<!--[!-->");
|
||||
$$renderer.push(`<main class="flex min-h-0 flex-1 flex-col items-center justify-center gap-6 p-6"><h1 class="text-2xl font-semibold">Base</h1> <div class="flex w-full max-w-xs flex-col gap-3"><a href="https://prism.ccllc.pro" class="block" target="_blank" rel="noopener noreferrer">`);
|
||||
Button($$renderer, {
|
||||
class: "h-12 w-full min-h-12",
|
||||
children: ($$renderer2) => {
|
||||
$$renderer2.push(`<!---->Prism`);
|
||||
},
|
||||
$$slots: { default: true }
|
||||
});
|
||||
$$renderer.push(`<!----></a> <a href="https://tasgrid.ccllc.pro" class="block" target="_blank" rel="noopener noreferrer">`);
|
||||
Button($$renderer, {
|
||||
class: "h-12 min-h-12 w-full",
|
||||
variant: "outline",
|
||||
children: ($$renderer2) => {
|
||||
$$renderer2.push(`<!---->TasGrid`);
|
||||
},
|
||||
$$slots: { default: true }
|
||||
});
|
||||
$$renderer.push(`<!----></a> <a href="https://stackq.ccllc.pro" class="block" target="_blank" rel="noopener noreferrer">`);
|
||||
Button($$renderer, {
|
||||
class: "h-12 min-h-12 w-full",
|
||||
variant: "outline",
|
||||
children: ($$renderer2) => {
|
||||
$$renderer2.push(`<!---->Stackq`);
|
||||
},
|
||||
$$slots: { default: true }
|
||||
});
|
||||
$$renderer.push(`<!----></a> <a href="https://hrm.ccllc.pro" class="block" target="_blank" rel="noopener noreferrer">`);
|
||||
Button($$renderer, {
|
||||
class: "h-12 min-h-12 w-full",
|
||||
variant: "outline",
|
||||
children: ($$renderer2) => {
|
||||
$$renderer2.push(`<!---->HRM`);
|
||||
},
|
||||
$$slots: { default: true }
|
||||
});
|
||||
$$renderer.push(`<!----></a></div></main>`);
|
||||
}
|
||||
$$renderer.push(`<!--]-->`);
|
||||
}
|
||||
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,256 @@
|
||||
import { b as attributes, j as clsx, c as bind_props, i as attr, f 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 "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 Card($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let {
|
||||
ref = null,
|
||||
class: className,
|
||||
children,
|
||||
$$slots,
|
||||
$$events,
|
||||
...restProps
|
||||
} = $$props;
|
||||
$$renderer2.push(`<div${attributes({
|
||||
"data-slot": "card",
|
||||
class: clsx(cn("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className)),
|
||||
...restProps
|
||||
})}>`);
|
||||
children?.($$renderer2);
|
||||
$$renderer2.push(`<!----></div>`);
|
||||
bind_props($$props, { ref });
|
||||
});
|
||||
}
|
||||
function Card_content($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let {
|
||||
ref = null,
|
||||
class: className,
|
||||
children,
|
||||
$$slots,
|
||||
$$events,
|
||||
...restProps
|
||||
} = $$props;
|
||||
$$renderer2.push(`<div${attributes({
|
||||
"data-slot": "card-content",
|
||||
class: clsx(cn("px-6", className)),
|
||||
...restProps
|
||||
})}>`);
|
||||
children?.($$renderer2);
|
||||
$$renderer2.push(`<!----></div>`);
|
||||
bind_props($$props, { ref });
|
||||
});
|
||||
}
|
||||
function Card_description($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let {
|
||||
ref = null,
|
||||
class: className,
|
||||
children,
|
||||
$$slots,
|
||||
$$events,
|
||||
...restProps
|
||||
} = $$props;
|
||||
$$renderer2.push(`<p${attributes({
|
||||
"data-slot": "card-description",
|
||||
class: clsx(cn("text-muted-foreground text-sm", className)),
|
||||
...restProps
|
||||
})}>`);
|
||||
children?.($$renderer2);
|
||||
$$renderer2.push(`<!----></p>`);
|
||||
bind_props($$props, { ref });
|
||||
});
|
||||
}
|
||||
function Card_header($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let {
|
||||
ref = null,
|
||||
class: className,
|
||||
children,
|
||||
$$slots,
|
||||
$$events,
|
||||
...restProps
|
||||
} = $$props;
|
||||
$$renderer2.push(`<div${attributes({
|
||||
"data-slot": "card-header",
|
||||
class: clsx(cn("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", className)),
|
||||
...restProps
|
||||
})}>`);
|
||||
children?.($$renderer2);
|
||||
$$renderer2.push(`<!----></div>`);
|
||||
bind_props($$props, { ref });
|
||||
});
|
||||
}
|
||||
function Card_title($$renderer, $$props) {
|
||||
$$renderer.component(($$renderer2) => {
|
||||
let {
|
||||
ref = null,
|
||||
class: className,
|
||||
children,
|
||||
$$slots,
|
||||
$$events,
|
||||
...restProps
|
||||
} = $$props;
|
||||
$$renderer2.push(`<div${attributes({
|
||||
"data-slot": "card-title",
|
||||
class: clsx(cn("leading-none font-semibold", className)),
|
||||
...restProps
|
||||
})}>`);
|
||||
children?.($$renderer2);
|
||||
$$renderer2.push(`<!----></div>`);
|
||||
bind_props($$props, { ref });
|
||||
});
|
||||
}
|
||||
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 { i 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
|
||||
};
|
||||
Reference in New Issue
Block a user