- Delete old Vite+Svelte frontend - Initialize new SvelteKit project with TypeScript - Configure Tailwind CSS v4 + DaisyUI - Implement JWT authentication with auto-refresh - Create login page with form validation (Zod) - Add protected route guards - Update Docker configuration for single-stage build - Add E2E tests with Playwright (6/11 passing) - Fix Svelte 5 reactivity with $state() runes Known issues: - 5 E2E tests failing (timing/async issues) - Token refresh implementation needs debugging - Validation error display timing
114 lines
5.4 KiB
JavaScript
114 lines
5.4 KiB
JavaScript
import { f as fallback, e as escape_html, b as attr_class, c as attr, d as bind_props, h as head, s as store_get, u as unsubscribe_stores } from "../../../chunks/root.js";
|
|
import "@sveltejs/kit/internal";
|
|
import "../../../chunks/exports.js";
|
|
import "../../../chunks/utils.js";
|
|
import "clsx";
|
|
import "@sveltejs/kit/internal/server";
|
|
import "../../../chunks/state.svelte.js";
|
|
import { z } from "zod";
|
|
import "ts-deepmerge";
|
|
import "@sveltejs/kit";
|
|
import "memoize-weak";
|
|
import Type from "typebox";
|
|
import "zod-v3-to-json-schema";
|
|
import { a as auth } from "../../../chunks/auth.js";
|
|
var FetchStatus;
|
|
(function(FetchStatus2) {
|
|
FetchStatus2[FetchStatus2["Idle"] = 0] = "Idle";
|
|
FetchStatus2[FetchStatus2["Submitting"] = 1] = "Submitting";
|
|
FetchStatus2[FetchStatus2["Delayed"] = 2] = "Delayed";
|
|
FetchStatus2[FetchStatus2["Timeout"] = 3] = "Timeout";
|
|
})(FetchStatus || (FetchStatus = {}));
|
|
let LEGACY_MODE = false;
|
|
try {
|
|
if (SUPERFORMS_LEGACY)
|
|
LEGACY_MODE = true;
|
|
} catch {
|
|
}
|
|
let STORYBOOK_MODE = false;
|
|
try {
|
|
if (globalThis.STORIES)
|
|
STORYBOOK_MODE = true;
|
|
} catch {
|
|
}
|
|
let legacyMode = false;
|
|
try {
|
|
if (SUPERFORMS_LEGACY)
|
|
legacyMode = true;
|
|
} catch {
|
|
}
|
|
class TDate extends Type.Base {
|
|
Check(value) {
|
|
return value instanceof globalThis.Date;
|
|
}
|
|
Errors(value) {
|
|
return this.Check(value) ? [] : [{ message: "must be Date" }];
|
|
}
|
|
Create() {
|
|
return new globalThis.Date(0);
|
|
}
|
|
}
|
|
function LoginForm($$renderer, $$props) {
|
|
$$renderer.component(($$renderer2) => {
|
|
let isLoading = fallback($$props["isLoading"], false);
|
|
let errorMessage = fallback($$props["errorMessage"], null);
|
|
z.object({
|
|
email: z.string().min(1, "Email is required").email("Invalid email format"),
|
|
password: z.string().min(1, "Password is required")
|
|
});
|
|
let formData = { email: "", password: "" };
|
|
let errors = {};
|
|
$$renderer2.push(`<form class="space-y-4">`);
|
|
if (errorMessage) {
|
|
$$renderer2.push("<!--[-->");
|
|
$$renderer2.push(`<div class="alert alert-error" role="alert"><svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg> <span>${escape_html(errorMessage)}</span></div>`);
|
|
} else {
|
|
$$renderer2.push("<!--[!-->");
|
|
}
|
|
$$renderer2.push(`<!--]--> <div class="form-control"><label class="label" for="email"><span class="label-text">Email</span></label> <input type="email" id="email"${attr_class("input input-bordered w-full", void 0, { "input-error": errors.email })} placeholder="admin@example.com"${attr("value", formData.email)}${attr("disabled", isLoading, true)}${attr("aria-invalid", errors.email ? "true" : "false")}${attr("aria-describedby", errors.email ? "email-error" : void 0)}/> `);
|
|
if (errors.email) {
|
|
$$renderer2.push("<!--[-->");
|
|
$$renderer2.push(`<span id="email-error" class="label-text-alt text-error">${escape_html(errors.email)}</span>`);
|
|
} else {
|
|
$$renderer2.push("<!--[!-->");
|
|
}
|
|
$$renderer2.push(`<!--]--></div> <div class="form-control"><label class="label" for="password"><span class="label-text">Password</span></label> <input type="password" id="password"${attr_class("input input-bordered w-full", void 0, { "input-error": errors.password })} placeholder="••••••••"${attr("value", formData.password)}${attr("disabled", isLoading, true)}${attr("aria-invalid", errors.password ? "true" : "false")}${attr("aria-describedby", errors.password ? "password-error" : void 0)}/> `);
|
|
if (errors.password) {
|
|
$$renderer2.push("<!--[-->");
|
|
$$renderer2.push(`<span id="password-error" class="label-text-alt text-error">${escape_html(errors.password)}</span>`);
|
|
} else {
|
|
$$renderer2.push("<!--[!-->");
|
|
}
|
|
$$renderer2.push(`<!--]--></div> <button type="submit" class="btn btn-primary w-full"${attr("disabled", isLoading, true)}>`);
|
|
if (isLoading) {
|
|
$$renderer2.push("<!--[-->");
|
|
$$renderer2.push(`<span class="loading loading-spinner loading-sm"></span> Logging in...`);
|
|
} else {
|
|
$$renderer2.push("<!--[!-->");
|
|
$$renderer2.push(`Login`);
|
|
}
|
|
$$renderer2.push(`<!--]--></button></form>`);
|
|
bind_props($$props, { isLoading, errorMessage });
|
|
});
|
|
}
|
|
function _page($$renderer, $$props) {
|
|
$$renderer.component(($$renderer2) => {
|
|
var $$store_subs;
|
|
head("1x05zx6", $$renderer2, ($$renderer3) => {
|
|
$$renderer3.title(($$renderer4) => {
|
|
$$renderer4.push(`<title>Login - Headroom</title>`);
|
|
});
|
|
});
|
|
$$renderer2.push(`<div class="min-h-screen flex items-center justify-center bg-base-200"><div class="card w-full max-w-md bg-base-100 shadow-xl"><div class="card-body"><h1 class="card-title text-2xl text-center justify-center mb-6">Welcome to Headroom</h1> <p class="text-center text-base-content/70 mb-6">Sign in to access your dashboard</p> `);
|
|
LoginForm($$renderer2, {
|
|
isLoading: store_get($$store_subs ??= {}, "$auth", auth).isLoading,
|
|
errorMessage: store_get($$store_subs ??= {}, "$auth", auth).error
|
|
});
|
|
$$renderer2.push(`<!----> <div class="divider"></div> <div class="text-center text-sm text-base-content/60"><p>Demo credentials:</p> <p class="font-mono mt-1">admin@example.com / password</p></div></div></div></div>`);
|
|
if ($$store_subs) unsubscribe_stores($$store_subs);
|
|
});
|
|
}
|
|
export {
|
|
_page as default
|
|
};
|