Compare commits
4 Commits
a3805f76a1
...
b207aa5e29
| Author | SHA1 | Date | |
|---|---|---|---|
| b207aa5e29 | |||
| a552865b2f | |||
| 999cf5bf16 | |||
| aad969fc46 |
@ -139,6 +139,11 @@
|
|||||||
help = "Serve Formula 11 (Prod)";
|
help = "Serve Formula 11 (Prod)";
|
||||||
command = "npm run build && npm run preview -- --host --port 5173";
|
command = "npm run build && npm run preview -- --host --port 5173";
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
name = "check";
|
||||||
|
help = "Continuously monitor for SvelteKit issues";
|
||||||
|
command = "svelte-check --watch";
|
||||||
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,77 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import type { Snippet } from "svelte";
|
|
||||||
import { LazyImage } from "$lib/components";
|
|
||||||
import { lazyload } from "$lib/lazyload";
|
|
||||||
|
|
||||||
interface LazyCardProps {
|
|
||||||
children: Snippet;
|
|
||||||
|
|
||||||
/** The URL for a possible header image. Leave undefined for no header image. Set to empty string for an image not yet loaded. */
|
|
||||||
imgsrc?: string | undefined;
|
|
||||||
|
|
||||||
/** The id of the header image element for JS access. */
|
|
||||||
imgid?: string | undefined;
|
|
||||||
|
|
||||||
/** The aspect ratio width used to reserve image space (while its loading) */
|
|
||||||
imgwidth: number;
|
|
||||||
|
|
||||||
/** The aspect ratio height used to reserve image space (while its loading) */
|
|
||||||
imgheight: number;
|
|
||||||
|
|
||||||
/** Hide the header image element. It can be shown by removing the "hidden" property using JS and the imgid. */
|
|
||||||
imghidden?: boolean;
|
|
||||||
|
|
||||||
/** The aspect ratio width used to reserve card space (while its loading) */
|
|
||||||
cardwidth: number;
|
|
||||||
|
|
||||||
/** The aspect ratio height used to reserve card space (while its loading) */
|
|
||||||
cardheight: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
|
||||||
children,
|
|
||||||
imgsrc = undefined,
|
|
||||||
imgid = undefined,
|
|
||||||
imgwidth,
|
|
||||||
imgheight,
|
|
||||||
imghidden = false,
|
|
||||||
cardwidth,
|
|
||||||
cardheight,
|
|
||||||
...restProps
|
|
||||||
}: LazyCardProps = $props();
|
|
||||||
|
|
||||||
let load: boolean = $state(false);
|
|
||||||
|
|
||||||
const lazy_visible_handler = () => {
|
|
||||||
load = true;
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div
|
|
||||||
use:lazyload
|
|
||||||
onLazyVisible={lazy_visible_handler}
|
|
||||||
style="aspect-ratio: {cardwidth} / {cardheight};"
|
|
||||||
>
|
|
||||||
<div class="card w-full overflow-hidden bg-white shadow">
|
|
||||||
<!-- Allow empty strings for images that only appear after user action -->
|
|
||||||
{#if imgsrc !== undefined}
|
|
||||||
<LazyImage
|
|
||||||
id={imgid}
|
|
||||||
src={imgsrc}
|
|
||||||
{imgwidth}
|
|
||||||
{imgheight}
|
|
||||||
alt="Card header"
|
|
||||||
draggable="false"
|
|
||||||
class="select-none shadow"
|
|
||||||
hidden={imghidden}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- Only lazyload children, as the image is already lazy (also the image fade would break) -->
|
|
||||||
{#if load}
|
|
||||||
<div class="p-2" {...restProps}>
|
|
||||||
{@render children()}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@ -9,7 +9,6 @@ import Search from "./form/Search.svelte";
|
|||||||
|
|
||||||
import Card from "./cards/Card.svelte";
|
import Card from "./cards/Card.svelte";
|
||||||
import DriverCard from "./cards/DriverCard.svelte";
|
import DriverCard from "./cards/DriverCard.svelte";
|
||||||
import LazyCard from "./cards/LazyCard.svelte";
|
|
||||||
import RaceCard from "./cards/RaceCard.svelte";
|
import RaceCard from "./cards/RaceCard.svelte";
|
||||||
import SubstitutionCard from "./cards/SubstitutionCard.svelte";
|
import SubstitutionCard from "./cards/SubstitutionCard.svelte";
|
||||||
import TeamCard from "./cards/TeamCard.svelte";
|
import TeamCard from "./cards/TeamCard.svelte";
|
||||||
@ -18,6 +17,7 @@ import type { DropdownOption } from "./form/Dropdown";
|
|||||||
import type { TableColumn } from "./Table";
|
import type { TableColumn } from "./Table";
|
||||||
|
|
||||||
import MenuDrawerIcon from "./svg/MenuDrawerIcon.svelte";
|
import MenuDrawerIcon from "./svg/MenuDrawerIcon.svelte";
|
||||||
|
import NameIcon from "./svg/NameIcon.svelte";
|
||||||
import PasswordIcon from "./svg/PasswordIcon.svelte";
|
import PasswordIcon from "./svg/PasswordIcon.svelte";
|
||||||
import UserIcon from "./svg/UserIcon.svelte";
|
import UserIcon from "./svg/UserIcon.svelte";
|
||||||
|
|
||||||
@ -36,7 +36,6 @@ export {
|
|||||||
// Cards
|
// Cards
|
||||||
Card,
|
Card,
|
||||||
DriverCard,
|
DriverCard,
|
||||||
LazyCard,
|
|
||||||
RaceCard,
|
RaceCard,
|
||||||
SubstitutionCard,
|
SubstitutionCard,
|
||||||
TeamCard,
|
TeamCard,
|
||||||
@ -46,6 +45,7 @@ export {
|
|||||||
type TableColumn,
|
type TableColumn,
|
||||||
|
|
||||||
// SVG
|
// SVG
|
||||||
|
NameIcon,
|
||||||
MenuDrawerIcon,
|
MenuDrawerIcon,
|
||||||
PasswordIcon,
|
PasswordIcon,
|
||||||
UserIcon,
|
UserIcon,
|
||||||
|
|||||||
10
src/lib/components/svg/NameIcon.svelte
Normal file
10
src/lib/components/svg/NameIcon.svelte
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 411 511.71"
|
||||||
|
fill="currentColor"
|
||||||
|
class="h-4 w-4 opacity-70"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M69.04 126.32h70.44L76.02 0h40.4l63.25 126.32h49.54L292.22.01h40.16l-62.87 126.31h72.46c37.9 0 69.03 31.13 69.03 69.03v247.33c0 37.9-31.13 69.03-69.03 69.03H69.04C31.07 511.71 0 480.64 0 442.68V195.35c0-37.96 31.08-69.03 69.04-69.03zm36.57 231.81L89.13 334.2c-.58-.79-.94-2.51-1.08-5.17h-.43v29.1H66.06v-67.37h20.27l16.48 23.94c.58.78.94 2.5 1.08 5.17h.43v-29.11h21.57v67.37h-20.28zm49.53 0H132.4l17.46-67.37h33.31l17.46 67.37h-22.75l-2.48-10.67h-17.77l-2.49 10.67zm9.53-46.68-4.42 18.87h12.42l-4.31-18.87h-3.69zm62.31 46.68h-22.53l4.1-67.37h28.13l8.41 34.28h.75l8.41-34.28h28.13l4.1 67.37h-22.52l-1.31-32.66h-.75l-8.19 32.66h-16.49l-8.3-32.66h-.64l-1.3 32.66zm113.11-25.44h-21.55v10.71h26.41v14.73h-47.97v-67.37h47.42l-2.68 14.74h-23.18v11.57h21.55v15.62zM154.5 437.39h102v17.27h-102v-17.27zm-53.72-44.49h209.43v17.27H100.78V392.9zm104.07-217.74 12.62-25.3H69.04c-25.03 0-45.5 20.47-45.5 45.49v247.33c0 24.96 20.53 45.49 45.5 45.49h272.93c24.97 0 45.49-20.53 45.49-45.49V195.35c0-25.02-20.47-45.49-45.49-45.49h-84.2l-20.65 41.39c5.41 7 8.62 15.77 8.62 25.29 0 22.86-18.53 41.39-41.39 41.39-22.85 0-41.39-18.53-41.39-41.39s18.54-41.39 41.39-41.39l.5.01z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
@ -7,6 +7,7 @@ export interface Graphic {
|
|||||||
export interface User {
|
export interface User {
|
||||||
id: string;
|
id: string;
|
||||||
username: string;
|
username: string;
|
||||||
|
firstname: string;
|
||||||
avatar: string;
|
avatar: string;
|
||||||
avatar_url?: string;
|
avatar_url?: string;
|
||||||
admin: boolean;
|
admin: boolean;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
TeamCard,
|
TeamCard,
|
||||||
RaceCard,
|
RaceCard,
|
||||||
SubstitutionCard,
|
SubstitutionCard,
|
||||||
|
NameIcon,
|
||||||
} from "$lib/components";
|
} from "$lib/components";
|
||||||
import { get_avatar_preview_event_handler } from "$lib/image";
|
import { get_avatar_preview_event_handler } from "$lib/image";
|
||||||
|
|
||||||
@ -151,13 +152,15 @@
|
|||||||
<!-- Data Drawer -->
|
<!-- Data Drawer -->
|
||||||
<!-- Data Drawer -->
|
<!-- Data Drawer -->
|
||||||
<div class="flex flex-col gap-2 p-2 pt-3">
|
<div class="flex flex-col gap-2 p-2 pt-3">
|
||||||
<Button href="/data/raceresult" onclick={close_drawer} color="surface" width="w-full"
|
<Button href="/data/raceresults" onclick={close_drawer} color="surface" width="w-full">
|
||||||
>Race Results
|
Race Results
|
||||||
|
</Button>
|
||||||
|
<Button href="/data/season/teams" onclick={close_drawer} color="surface" width="w-full">
|
||||||
|
Season
|
||||||
|
</Button>
|
||||||
|
<Button href="/data/users" onclick={close_drawer} color="surface" width="w-full">
|
||||||
|
Users
|
||||||
</Button>
|
</Button>
|
||||||
<Button href="/data/season/teams" onclick={close_drawer} color="surface" width="w-full"
|
|
||||||
>Season</Button
|
|
||||||
>
|
|
||||||
<Button href="/data/user" onclick={close_drawer} color="surface" width="w-full">Users</Button>
|
|
||||||
</div>
|
</div>
|
||||||
{:else if $drawerStore.id === "login_drawer"}
|
{:else if $drawerStore.id === "login_drawer"}
|
||||||
<!-- Login Drawer -->
|
<!-- Login Drawer -->
|
||||||
@ -168,22 +171,26 @@
|
|||||||
<form method="POST" class="contents">
|
<form method="POST" class="contents">
|
||||||
<!-- Supply the pathname so the form can redirect to the current page. -->
|
<!-- Supply the pathname so the form can redirect to the current page. -->
|
||||||
<input type="hidden" name="redirect_url" value={$page.url.pathname} />
|
<input type="hidden" name="redirect_url" value={$page.url.pathname} />
|
||||||
<Input name="username" placeholder="Username" autocomplete="username" required
|
<Input name="username" placeholder="Username" autocomplete="username" required>
|
||||||
><UserIcon />
|
<UserIcon />
|
||||||
</Input>
|
</Input>
|
||||||
<Input name="password" type="password" placeholder="Password" autocomplete="off" required
|
<Input name="firstname" placeholder="First Name (leave empty for login)" autocomplete="off">
|
||||||
><PasswordIcon />
|
<NameIcon />
|
||||||
|
</Input>
|
||||||
|
<Input name="password" type="password" placeholder="Password" autocomplete="off" required>
|
||||||
|
<PasswordIcon />
|
||||||
</Input>
|
</Input>
|
||||||
<div class="flex justify-end gap-2">
|
<div class="flex justify-end gap-2">
|
||||||
<Button formaction="/profile?/login" onclick={close_drawer} color="tertiary" submit
|
<Button formaction="/profile?/login" onclick={close_drawer} color="tertiary" submit>
|
||||||
>Login
|
Login
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
formaction="/profile?/create_profile"
|
formaction="/profile?/create_profile"
|
||||||
onclick={close_drawer}
|
onclick={close_drawer}
|
||||||
color="tertiary"
|
color="tertiary"
|
||||||
submit
|
submit
|
||||||
>Register
|
>
|
||||||
|
Register
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
@ -206,6 +213,14 @@
|
|||||||
>
|
>
|
||||||
<UserIcon />
|
<UserIcon />
|
||||||
</Input>
|
</Input>
|
||||||
|
<Input
|
||||||
|
name="firstname"
|
||||||
|
value={data.user.firstname}
|
||||||
|
placeholder="First Name"
|
||||||
|
autocomplete="off"
|
||||||
|
>
|
||||||
|
<NameIcon />
|
||||||
|
</Input>
|
||||||
<FileDropzone
|
<FileDropzone
|
||||||
name="avatar"
|
name="avatar"
|
||||||
onchange={get_avatar_preview_event_handler("user_avatar_preview")}
|
onchange={get_avatar_preview_event_handler("user_avatar_preview")}
|
||||||
|
|||||||
@ -7,11 +7,12 @@ import { AVATAR_HEIGHT, AVATAR_WIDTH } from "$lib/config";
|
|||||||
export const actions = {
|
export const actions = {
|
||||||
create_profile: async ({ request, locals }): Promise<void> => {
|
create_profile: async ({ request, locals }): Promise<void> => {
|
||||||
const data: FormData = form_data_clean(await request.formData());
|
const data: FormData = form_data_clean(await request.formData());
|
||||||
form_data_ensure_keys(data, ["username", "password", "redirect_url"]);
|
form_data_ensure_keys(data, ["username", "firstname", "password", "redirect_url"]);
|
||||||
|
|
||||||
// Confirm password lol
|
// Confirm password lol
|
||||||
await locals.pb.collection("users").create({
|
await locals.pb.collection("users").create({
|
||||||
username: data.get("username")?.toString(),
|
username: data.get("username")?.toString(),
|
||||||
|
firstname: data.get("firstname")?.toString(),
|
||||||
password: data.get("password")?.toString(),
|
password: data.get("password")?.toString(),
|
||||||
passwordConfirm: data.get("password")?.toString(),
|
passwordConfirm: data.get("password")?.toString(),
|
||||||
admin: false,
|
admin: false,
|
||||||
@ -22,6 +23,7 @@ export const actions = {
|
|||||||
.collection("users")
|
.collection("users")
|
||||||
.authWithPassword(data.get("username")?.toString(), data.get("password")?.toString());
|
.authWithPassword(data.get("username")?.toString(), data.get("password")?.toString());
|
||||||
|
|
||||||
|
// The current page is sent with the form, redirect to that page
|
||||||
redirect(303, data.get("redirect_url")?.toString() ?? "/");
|
redirect(303, data.get("redirect_url")?.toString() ?? "/");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user