mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Alert on login failure and starting light/dark mode change.
This commit is contained in:
parent
f80b8f5391
commit
9c71c3664f
10 changed files with 130 additions and 67 deletions
|
|
@ -5,16 +5,19 @@ const atImport = require('postcss-import');
|
|||
|
||||
const config = {
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
atImport(),
|
||||
// 'tailwindcss/nesting'(),
|
||||
tailwindcss(),
|
||||
postcssPresetEnv({
|
||||
stage: 2,
|
||||
features: {
|
||||
'nesting-rules': true,
|
||||
'nesting-rules': false,
|
||||
'custom-media-queries': true,
|
||||
'media-query-ranges': true
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
||||
|
||||
] //Some plugins, like tailwindcss/nesting, need to run before Tailwind, tailwindcss(), //But others, like autoprefixer, need to run after, autoprefixer]
|
||||
};
|
||||
|
||||
|
|
|
|||
46
src/app.html
46
src/app.html
|
|
@ -6,34 +6,34 @@
|
|||
<link rel="icon" href="%sveltekit.assets%/favicon-bored.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<script>
|
||||
const htmlElement = document.documentElement;
|
||||
const userTheme = localStorage.theme;
|
||||
const userFont = localStorage.font;
|
||||
// const htmlElement = document.documentElement;
|
||||
// const userTheme = localStorage.theme;
|
||||
// const userFont = localStorage.font;
|
||||
|
||||
const prefersDarkMode = window.matchMedia('prefers-color-scheme: dark').matches;
|
||||
const prefersLightMode = window.matchMedia('prefers-color-scheme: light').matches;
|
||||
// const prefersDarkMode = window.matchMedia('prefers-color-scheme: dark').matches;
|
||||
// const prefersLightMode = window.matchMedia('prefers-color-scheme: light').matches;
|
||||
|
||||
// check if the user set a theme
|
||||
if (userTheme) {
|
||||
htmlElement.dataset.theme = userTheme;
|
||||
}
|
||||
// // check if the user set a theme
|
||||
// if (userTheme) {
|
||||
// htmlElement.dataset.theme = userTheme;
|
||||
// }
|
||||
|
||||
// otherwise check for user preference
|
||||
if (!userTheme && prefersDarkMode) {
|
||||
htmlElement.dataset.theme = '🌛 Night';
|
||||
localStorage.theme = '🌛 Night';
|
||||
}
|
||||
// // otherwise check for user preference
|
||||
// if (!userTheme && prefersDarkMode) {
|
||||
// htmlElement.dataset.theme = '🌛 Night';
|
||||
// localStorage.theme = '🌛 Night';
|
||||
// }
|
||||
|
||||
if (!userTheme && prefersLightMode) {
|
||||
htmlElement.dataset.theme = '☀️ Daylight';
|
||||
localStorage.theme = '☀️ Daylight';
|
||||
}
|
||||
// if (!userTheme && prefersLightMode) {
|
||||
// htmlElement.dataset.theme = '☀️ Daylight';
|
||||
// localStorage.theme = '☀️ Daylight';
|
||||
// }
|
||||
|
||||
// if nothing is set default to dark mode
|
||||
if (!userTheme && !prefersDarkMode && !prefersLightMode) {
|
||||
htmlElement.dataset.theme = '🌛 Night';
|
||||
localStorage.theme = '🌛 Night';
|
||||
}
|
||||
// // if nothing is set default to dark mode
|
||||
// if (!userTheme && !prefersDarkMode && !prefersLightMode) {
|
||||
// htmlElement.dataset.theme = '🌛 Night';
|
||||
// localStorage.theme = '🌛 Night';
|
||||
// }
|
||||
</script>
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import { LogOut } from 'lucide-svelte';
|
||||
import Button from '$components/ui/button/Button.svelte';
|
||||
// import Profile from '../preferences/profile.svelte';
|
||||
import logo from './bored-game.png';
|
||||
|
||||
|
|
@ -23,9 +25,10 @@
|
|||
action="/auth/signout"
|
||||
method="POST"
|
||||
>
|
||||
<button type="submit" class="btn"
|
||||
><span>Sign out</span></button
|
||||
>
|
||||
<Button type="submit">
|
||||
<LogOut class="mr-2 h-4 w-4"/>
|
||||
Sign out
|
||||
</Button>
|
||||
</form>
|
||||
{/if}
|
||||
{#if !user}
|
||||
|
|
|
|||
30
src/lib/components/ui/alert/Alert.svelte
Normal file
30
src/lib/components/ui/alert/Alert.svelte
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<script lang="ts">
|
||||
import type { VariantProps } from "class-variance-authority";
|
||||
import { cva } from "class-variance-authority";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
const alertVariants = cva(
|
||||
"relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-background text-foreground",
|
||||
destructive:
|
||||
"text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive"
|
||||
}
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default"
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
export let variant: VariantProps<typeof alertVariants>["variant"] =
|
||||
"default";
|
||||
</script>
|
||||
|
||||
<div class={cn(alertVariants({ variant }), className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
||||
10
src/lib/components/ui/alert/AlertDescription.svelte
Normal file
10
src/lib/components/ui/alert/AlertDescription.svelte
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
</script>
|
||||
|
||||
<div class={cn("text-sm [&_p]:leading-relaxed", className)} {...$$restProps}>
|
||||
<slot />
|
||||
</div>
|
||||
15
src/lib/components/ui/alert/AlertTitle.svelte
Normal file
15
src/lib/components/ui/alert/AlertTitle.svelte
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<script lang="ts">
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let className: string | undefined | null = undefined;
|
||||
export { className as class };
|
||||
export let level: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" = "h5";
|
||||
</script>
|
||||
|
||||
<svelte:element
|
||||
this={level}
|
||||
class={cn("mb-1 font-medium leading-none tracking-tight", className)}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</svelte:element>
|
||||
3
src/lib/components/ui/alert/index.ts
Normal file
3
src/lib/components/ui/alert/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
export { default as Alert } from "./Alert.svelte";
|
||||
export { default as AlertDescription } from "./AlertDescription.svelte";
|
||||
export { default as AlertTitle } from "./AlertTitle.svelte";
|
||||
|
|
@ -52,7 +52,7 @@ export const actions = {
|
|||
// TODO: need to return error message to the client
|
||||
console.error(e);
|
||||
form.data.password = '';
|
||||
return setError(form, '', 'The username or password is incorrect.');
|
||||
return setError(form, '', 'Your username or password is incorrect.');
|
||||
}
|
||||
form.data.username = '';
|
||||
form.data.password = '';
|
||||
|
|
|
|||
|
|
@ -1,46 +1,43 @@
|
|||
<script lang="ts">
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
import { AlertCircle } from "lucide-svelte";
|
||||
import { userSchema } from '$lib/config/zod-schemas.js';
|
||||
import Label from '$components/ui/label/Label.svelte';
|
||||
import Input from '$components/ui/input/Input.svelte';
|
||||
import Button from '$components/ui/button/Button.svelte';
|
||||
import { Alert, AlertDescription, AlertTitle } from "$components/ui/alert";
|
||||
|
||||
export let data;
|
||||
|
||||
const signInSchema = userSchema.pick({ username: true, password: true });
|
||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||
taintedMessage: null,
|
||||
validators: signInSchema,
|
||||
validationMethod: 'oninput',
|
||||
delayMs: 0,
|
||||
});
|
||||
console.log($errors);
|
||||
</script>
|
||||
|
||||
<form method="POST" use:enhance>
|
||||
<div>
|
||||
{#if $errors._errors}
|
||||
<aside class="alert">
|
||||
<div class="alert-message">
|
||||
<h3>There was an error signing in</h3>
|
||||
<p>{$errors._errors}</p>
|
||||
</div>
|
||||
</aside>
|
||||
<Alert variant="destructive">
|
||||
<AlertCircle class="h-4 w-4" />
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>
|
||||
{$errors._errors}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
{/if}
|
||||
<div class="grid w-full max-w-sm items-center gap-2">
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Sign into your account
|
||||
</h2>
|
||||
<Label for="username">Username</Label>
|
||||
<Input type="text" id="username" name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} />
|
||||
{#if $errors.username}
|
||||
<p class="text-sm text-muted-foreground">{$errors.username}</p>
|
||||
{/if}
|
||||
<Label for="password">Password</Label>
|
||||
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="new-password" data-invalid={$errors.password} bind:value={$form.password} />
|
||||
{#if $errors.password}
|
||||
<p class="text-sm text-muted-foreground">{$errors.password}</p>
|
||||
{/if}
|
||||
<Button type="submit">Sign In</Button>
|
||||
</div>
|
||||
</form>
|
||||
<form method="POST" use:enhance>
|
||||
<div class="grid w-full max-w-sm items-center gap-2">
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Sign into your account
|
||||
</h2>
|
||||
<Label for="username">Username</Label>
|
||||
<Input type="text" id="username" name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} />
|
||||
<Label for="password">Password</Label>
|
||||
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="new-password" data-invalid={$errors.password} bind:value={$form.password} />
|
||||
<Button type="submit">Sign In</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -25,43 +25,45 @@ import { userSchema } from '$lib/config/zod-schemas.js';
|
|||
|
||||
<div class="page">
|
||||
<form method="POST" action="/auth/signup" use:enhance>
|
||||
<div class="grid w-full max-w-sm items-center gap-2">
|
||||
<div class="grid w-full max-w-sm items-center gap-2.5">
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Signup for an account
|
||||
</h2>
|
||||
<Label for="firstName">First Name</Label>
|
||||
<Input type="text" id="firstName" name="firstName" placeholder="First Name" autocomplete="given-name" data-invalid={$errors.firstName} bind:value={$form.firstName} />
|
||||
<Input
|
||||
type="text"
|
||||
id="firstName" class={$errors.firstName && "outline outline-destructive"} name="firstName" placeholder="First Name" autocomplete="given-name" data-invalid={$errors.firstName} bind:value={$form.firstName} />
|
||||
{#if $errors.firstName}
|
||||
<p class="text-sm text-destructive">{$errors.firstName}</p>
|
||||
{/if}
|
||||
<Label for="firstName">Last Name</Label>
|
||||
<Input type="text" id="lastName" name="lastName" placeholder="Last Name" autocomplete="family-name" data-invalid={$errors.lastName} bind:value={$form.lastName} />
|
||||
<Input type="text" id="lastName" class={$errors.firstName && "outline outline-destructive"} name="lastName" placeholder="Last Name" autocomplete="family-name" data-invalid={$errors.lastName} bind:value={$form.lastName} />
|
||||
{#if $errors.lastName}
|
||||
<p class="text-sm text-destructive">{$errors.lastName}</p>
|
||||
{/if}
|
||||
<Label for="email">Email</Label>
|
||||
<Input type="email" id="email" name="email" placeholder="Email" autocomplete="email" data-invalid={$errors.email} bind:value={$form.email} />
|
||||
<Input type="email" id="email" class={$errors.email && "outline outline-destructive"} name="email" placeholder="Email" autocomplete="email" data-invalid={$errors.email} bind:value={$form.email} />
|
||||
{#if $errors.email}
|
||||
<p class="text-sm text-destructive">{$errors.email}</p>
|
||||
{/if}
|
||||
<Label for="username">Username</Label>
|
||||
<Input type="text" id="username" name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} />
|
||||
<Input type="text" id="username" class={$errors.username && "outline outline-destructive"} name="username" placeholder="Username" autocomplete="username" data-invalid={$errors.username} bind:value={$form.username} />
|
||||
{#if $errors.username}
|
||||
<p class="text-sm text-destructive">{$errors.username}</p>
|
||||
{/if}
|
||||
<Label for="password">Password</Label>
|
||||
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="new-password" data-invalid={$errors.password} bind:value={$form.password} />
|
||||
<Input type="password" id="password" class={$errors.password && "outline outline-destructive"} name="password" placeholder="Password" autocomplete="new-password" data-invalid={$errors.password} bind:value={$form.password} />
|
||||
{#if $errors.password}
|
||||
<p class="text-sm text-destructive">{$errors.password}</p>
|
||||
{/if}
|
||||
<Label for="confirm_password">Confirm Password</Label>
|
||||
<Input type="password" id="confirm_password" name="confirm_password" placeholder="Confirm Password" autocomplete="new-password" data-invalid={$errors.confirm_password} bind:value={$form.confirm_password} />
|
||||
<Input type="password" id="confirm_password" class={$errors.confirm_password && "outline outline-destructive"} name="confirm_password" placeholder="Confirm Password" autocomplete="new-password" data-invalid={$errors.confirm_password} bind:value={$form.confirm_password} />
|
||||
{#if $errors.confirm_password}
|
||||
<p class="text-sm text-destructive">{$errors.confirm_password}</p>
|
||||
{/if}
|
||||
<div class="flex place-content-">
|
||||
<div class="grid grid-cols-2">
|
||||
<Button type="submit">Signup</Button>
|
||||
<Button variant="link" href="/">or Cancel</Button>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue