hello world
Some checks failed
main-branch-frovide/pipeline/head There was a failure building this commit
Some checks failed
main-branch-frovide/pipeline/head There was a failure building this commit
This commit is contained in:
parent
555f4c5396
commit
3d08574401
138
src/routes/(public)/login/+page.server.ts
Normal file
138
src/routes/(public)/login/+page.server.ts
Normal file
@ -0,0 +1,138 @@
|
||||
import type { PageServerLoad, Actions } from "./$types.js";
|
||||
import { fail } from "@sveltejs/kit";
|
||||
import { superValidate } from "sveltekit-superforms";
|
||||
import { zod } from "sveltekit-superforms/adapters";
|
||||
import { formSchema } from "./schema";
|
||||
|
||||
export const load: PageServerLoad = async () => {
|
||||
return {
|
||||
form: await superValidate(zod(formSchema)),
|
||||
};
|
||||
};
|
||||
|
||||
export const actions: Actions = {
|
||||
default: async (event) => {
|
||||
const form = await superValidate(event, zod(formSchema));
|
||||
if (!form.valid) {
|
||||
return fail(400, {
|
||||
form,
|
||||
});
|
||||
}
|
||||
return {
|
||||
form,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// import { hash, verify } from '@node-rs/argon2';
|
||||
// import { encodeBase32LowerCase } from '@oslojs/encoding';
|
||||
// import { fail, redirect } from '@sveltejs/kit';
|
||||
// import { eq } from 'drizzle-orm';
|
||||
// import * as auth from '$lib/server/auth';
|
||||
// import { db } from '$lib/server/db';
|
||||
// import * as table from '$lib/server/db/schema';
|
||||
// import type { Actions, PageServerLoad } from './$types';
|
||||
|
||||
// export const load: PageServerLoad = async (event) => {
|
||||
// if (event.locals.user) {
|
||||
// return redirect(302, '/demo/lucia');
|
||||
// }
|
||||
// return {};
|
||||
// };
|
||||
|
||||
// export const actions: Actions = {
|
||||
// login: async (event) => {
|
||||
// const formData = await event.request.formData();
|
||||
// const username = formData.get('username');
|
||||
// const password = formData.get('password');
|
||||
|
||||
// if (!validateUsername(username)) {
|
||||
// return fail(400, { message: 'Invalid username (min 3, max 31 characters, alphanumeric only)' });
|
||||
// }
|
||||
// if (!validatePassword(password)) {
|
||||
// return fail(400, { message: 'Invalid password (min 6, max 255 characters)' });
|
||||
// }
|
||||
|
||||
// const results = await db
|
||||
// .select()
|
||||
// .from(table.user)
|
||||
// .where(eq(table.user.username, username));
|
||||
|
||||
// const existingUser = results.at(0);
|
||||
// if (!existingUser) {
|
||||
// return fail(400, { message: 'Incorrect username or password' });
|
||||
// }
|
||||
|
||||
// const validPassword = await verify(existingUser.passwordHash, password, {
|
||||
// memoryCost: 19456,
|
||||
// timeCost: 2,
|
||||
// outputLen: 32,
|
||||
// parallelism: 1,
|
||||
// });
|
||||
// if (!validPassword) {
|
||||
// return fail(400, { message: 'Incorrect username or password' });
|
||||
// }
|
||||
|
||||
// const sessionToken = auth.generateSessionToken();
|
||||
// const session = await auth.createSession(sessionToken, existingUser.id);
|
||||
// auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
|
||||
// return redirect(302, '/demo/lucia');
|
||||
// },
|
||||
// register: async (event) => {
|
||||
// const formData = await event.request.formData();
|
||||
// const username = formData.get('username');
|
||||
// const password = formData.get('password');
|
||||
|
||||
// if (!validateUsername(username)) {
|
||||
// return fail(400, { message: 'Invalid username' });
|
||||
// }
|
||||
// if (!validatePassword(password)) {
|
||||
// return fail(400, { message: 'Invalid password' });
|
||||
// }
|
||||
|
||||
// const userId = generateUserId();
|
||||
// const passwordHash = await hash(password, {
|
||||
// // recommended minimum parameters
|
||||
// memoryCost: 19456,
|
||||
// timeCost: 2,
|
||||
// outputLen: 32,
|
||||
// parallelism: 1,
|
||||
// });
|
||||
|
||||
// try {
|
||||
// await db.insert(table.user).values({ id: userId, username, passwordHash });
|
||||
|
||||
// const sessionToken = auth.generateSessionToken();
|
||||
// const session = await auth.createSession(sessionToken, userId);
|
||||
// auth.setSessionTokenCookie(event, sessionToken, session.expiresAt);
|
||||
// } catch (e) {
|
||||
// return fail(500, { message: 'An error has occurred' });
|
||||
// }
|
||||
// return redirect(302, '/demo/lucia');
|
||||
// },
|
||||
// };
|
||||
|
||||
// function generateUserId() {
|
||||
// // ID with 120 bits of entropy, or about the same as UUID v4.
|
||||
// const bytes = crypto.getRandomValues(new Uint8Array(15));
|
||||
// const id = encodeBase32LowerCase(bytes);
|
||||
// return id;
|
||||
// }
|
||||
|
||||
// function validateUsername(username: unknown): username is string {
|
||||
// return (
|
||||
// typeof username === 'string' &&
|
||||
// username.length >= 3 &&
|
||||
// username.length <= 31 &&
|
||||
// /^[a-z0-9_-]+$/.test(username)
|
||||
// );
|
||||
// }
|
||||
|
||||
// function validatePassword(password: unknown): password is string {
|
||||
// return (
|
||||
// typeof password === 'string' &&
|
||||
// password.length >= 6 &&
|
||||
// password.length <= 255
|
||||
// );
|
||||
// }
|
||||
@ -1,17 +1,10 @@
|
||||
<script lang="ts">
|
||||
import LoginForm from "./login-form.svelte";
|
||||
import GalleryVerticalEndIcon from "@lucide/svelte/icons/gallery-vertical-end";
|
||||
import type { PageData } from "./$types.js";
|
||||
import LoginForm from "./login-form.svelte";
|
||||
let { data }: { data: PageData } = $props();
|
||||
</script>
|
||||
<div class="bg-muted flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
|
||||
<div class="bg-muted flex min-h-svh flex-col items-center justify-center gap-6 p-6 md:p-10">
|
||||
<div class="flex w-full max-w-sm flex-col gap-6">
|
||||
<a href="##" class="flex items-center gap-2 self-center font-medium">
|
||||
<div
|
||||
class="bg-primary text-primary-foreground flex size-6 items-center justify-center rounded-md"
|
||||
>
|
||||
<GalleryVerticalEndIcon class="size-4" />
|
||||
</div>
|
||||
Frovide.
|
||||
</a>
|
||||
<LoginForm />
|
||||
<LoginForm {data} />
|
||||
</div>
|
||||
</div>
|
||||
@ -1,44 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import * as Form from "$lib/components/ui/form/index.js";
|
||||
import { Input } from "$lib/components/ui/input/index.js";
|
||||
import { formSchema, type FormSchema } from "./schema";
|
||||
import {
|
||||
type SuperValidated,
|
||||
type Infer,
|
||||
superForm,
|
||||
} from "sveltekit-superforms";
|
||||
import { zodClient } from "sveltekit-superforms/adapters";
|
||||
import { Button } from "$lib/components/ui/button/index.js";
|
||||
import * as Card from "$lib/components/ui/card/index.js";
|
||||
import { Label } from "$lib/components/ui/label/index.js";
|
||||
import { Switch } from "$lib/components/ui/switch/index.js";
|
||||
import { Input } from "$lib/components/ui/input/index.js";
|
||||
import { cn } from "$lib/utils.js";
|
||||
import type { HTMLAttributes } from "svelte/elements";
|
||||
|
||||
let { class: className, ...restProps }: HTMLAttributes<HTMLDivElement> = $props();
|
||||
|
||||
const id = $props.id();
|
||||
|
||||
let { data }: { data: { form: SuperValidated<Infer<FormSchema>> } } =
|
||||
$props();
|
||||
|
||||
const form = superForm(data.form, {
|
||||
validators: zodClient(formSchema),
|
||||
});
|
||||
|
||||
const { form: formData, enhance } = form;
|
||||
</script>
|
||||
|
||||
<form method="POST" use:enhance>
|
||||
<Form.Field {form} name="login">
|
||||
<Form.Control>
|
||||
{#snippet children({ props })}
|
||||
<Form.Label>Email</Form.Label>
|
||||
<Input {...props} bind:value={$formData.email} />
|
||||
{/snippet}
|
||||
</Form.Control>
|
||||
<Form.Description>This is your public display name.</Form.Description>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Button>Submit</Form.Button>
|
||||
</form>
|
||||
|
||||
<div class={cn("flex flex-col gap-6", className)} {...restProps}>
|
||||
<Card.Root>
|
||||
<Card.Header class="text-center">
|
||||
<Card.Title class="text-xl">:: LOGIN ::</Card.Title>
|
||||
<Card.Description>외부인증 서비스를 통해 소셜로그인.</Card.Description>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<form>
|
||||
<div class="grid gap-6">
|
||||
<div class="flex flex-col gap-4">
|
||||
<Button variant="outline" class="w-full">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
Google 계정으로 로그인
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
class="after:border-border relative text-center text-sm after:absolute after:inset-0 after:top-1/2 after:z-0 after:flex after:items-center after:border-t"
|
||||
>
|
||||
<span class="bg-card text-muted-foreground relative z-10 px-2">
|
||||
등록한 계정으로 직접 로그인
|
||||
</span>
|
||||
</div>
|
||||
<div class="grid gap-6">
|
||||
<div class="grid gap-3">
|
||||
<Label for="email-{id}">이메일</Label>
|
||||
@ -82,3 +94,4 @@
|
||||
과 <a href="##">개인정보 보호정책</a> 에 동의합니다.
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
|
||||
8
src/routes/(public)/login/schema.ts
Normal file
8
src/routes/(public)/login/schema.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const formSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(8),
|
||||
});
|
||||
|
||||
export type FormSchema = typeof formSchema;
|
||||
Loading…
x
Reference in New Issue
Block a user