Create auth page, add styling & prettier
This commit is contained in:
parent
8da9ef55ed
commit
4ad3290e04
16 changed files with 235 additions and 34 deletions
4
.prettierignore
Normal file
4
.prettierignore
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Package Managers
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
18
.prettierrc
Normal file
18
.prettierrc
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"useTabs": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"printWidth": 100,
|
||||
"plugins": ["prettier-plugin-svelte"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.svelte",
|
||||
"options": {
|
||||
"parser": "svelte",
|
||||
"svelteStrictMode": true,
|
||||
"svelteBracketNewLine": false,
|
||||
"svelteIndentScriptAndStyle": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
70
package.json
70
package.json
|
@ -1,34 +1,40 @@
|
|||
{
|
||||
"name": "talkomatic",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"daisyui": "^4.12.10",
|
||||
"postcss": "^8.4.41",
|
||||
"svelte": "^5.0.0-next.1",
|
||||
"svelte-check": "^3.6.0",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.3"
|
||||
},
|
||||
"type": "module",
|
||||
"trustedDependencies": [
|
||||
"svelte-preprocess"
|
||||
],
|
||||
"dependencies": {
|
||||
"@olli/kvdex": "npm:@jsr/olli__kvdex",
|
||||
"@ts-rex/argon2": "npm:@jsr/ts-rex__argon2",
|
||||
"lucia": "^3.2.0"
|
||||
}
|
||||
"name": "talkomatic",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deno/kv": "^0.8.1",
|
||||
"@olli/kvdex": "npm:@jsr/olli__kvdex",
|
||||
"@sveltejs/adapter-auto": "^3.0.0",
|
||||
"@sveltejs/kit": "^2.0.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||
"@ts-rex/argon2": "npm:@jsr/ts-rex__argon2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"daisyui": "^4.12.10",
|
||||
"hono": "^4.5.5",
|
||||
"lucia": "^3.2.0",
|
||||
"postcss": "^8.4.41",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier-plugin-svelte": "^3.2.5",
|
||||
"svelte": "^5.0.0-next.1",
|
||||
"svelte-check": "^3.6.0",
|
||||
"sveltekit-superforms": "^2.17.0",
|
||||
"tailwindcss": "^3.4.10",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^5.0.3",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"type": "module",
|
||||
"trustedDependencies": [
|
||||
"svelte-preprocess"
|
||||
]
|
||||
}
|
||||
|
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
3
src/app.pcss
Normal file
3
src/app.pcss
Normal file
|
@ -0,0 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
21
src/lib/Tab.svelte
Normal file
21
src/lib/Tab.svelte
Normal file
|
@ -0,0 +1,21 @@
|
|||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
let { tab = $bindable(), disabled = $bindable(false), map, ...props }: {
|
||||
tab: string | undefined,
|
||||
disabled?: boolean,
|
||||
map?: Record<string, string>,
|
||||
class?: string,
|
||||
[x: `_${string}`]: Snippet<[]>;
|
||||
} = $props();
|
||||
const tabs = Object.fromEntries(Object.entries(props).filter((v) => v[0].startsWith('_')).map(([name, snippet]): [string, Snippet<[]>] => [name.replace('_', ''), snippet]));
|
||||
</script>
|
||||
|
||||
<div role="tablist" class="tabs tabs-boxed {props.class}">
|
||||
{#each Object.entries(tabs) as [tabID]}
|
||||
<!-- svelte-ignore a11y_interactive_supports_focus -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_missing_attribute -->
|
||||
<a class:cursor-not-allowed={disabled} class:pointer-events-none={disabled} class:tab-disabled={disabled} role="tab" class="tab uppercase" onclick={() => tab = tabID} class:tab-active={tabID == tab}>{@render tabs[tabID]()}</a>
|
||||
{/each}
|
||||
</div>
|
10
src/lib/apiclient.ts
Normal file
10
src/lib/apiclient.ts
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { type api } from "./hono"
|
||||
import { hc } from "hono/client"
|
||||
export const client = hc<api>('/api', {
|
||||
async fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
||||
return await fetch(input, {
|
||||
...init,
|
||||
credentials: 'include',
|
||||
})
|
||||
}
|
||||
})
|
|
@ -0,0 +1,2 @@
|
|||
import { } from "@olli/kvdex"
|
||||
import { } from "@deno/kv"
|
|
@ -0,0 +1,6 @@
|
|||
import { Hono } from "hono"
|
||||
|
||||
const api = new Hono()
|
||||
export type api = typeof api
|
||||
|
||||
export const hono = new Hono().route('/api', api)
|
6
src/routes/+layout.svelte
Normal file
6
src/routes/+layout.svelte
Normal file
|
@ -0,0 +1,6 @@
|
|||
<script>
|
||||
import "../app.pcss"
|
||||
const { children } = $props()
|
||||
</script>
|
||||
|
||||
{@render children()}
|
|
@ -1,2 +1 @@
|
|||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
|
||||
<script></script>
|
5
src/routes/api/[...path]/+server.ts
Normal file
5
src/routes/api/[...path]/+server.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { hono } from '$lib/hono.js';
|
||||
|
||||
export async function fallback({ request }) {
|
||||
return hono.fetch(request)
|
||||
}
|
33
src/routes/auth/+page.server.ts
Normal file
33
src/routes/auth/+page.server.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { fail, message, superValidate } from 'sveltekit-superforms';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { z } from 'zod';
|
||||
|
||||
const schema = z.object({
|
||||
username: z.string().min(4, "must be atleast 4 characters").max(32, "must be less than 32 characters").regex(/^[a-z0-9_\-]{4,32}$/i, `must be alphanumeric, with the exception of "_" and "-"`),
|
||||
password: z.string().min(8, "must be atleast 8 characters")
|
||||
});
|
||||
|
||||
export async function load() {
|
||||
const form = await superValidate(zod(schema));
|
||||
return { form };
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
login: async ({ request }) => {
|
||||
const form = await superValidate(request, zod(schema));
|
||||
|
||||
if (!form.valid) return fail(400, { form });
|
||||
|
||||
// TODO: Login user
|
||||
return message(form, 'Login form submitted');
|
||||
},
|
||||
signup: async ({ request }) => {
|
||||
const form = await superValidate(request, zod(schema));
|
||||
|
||||
if (!form.valid) return fail(400, { form });
|
||||
|
||||
// TODO: Login user
|
||||
return message(form, 'Signup form submitted');
|
||||
|
||||
}
|
||||
}
|
71
src/routes/auth/+page.svelte
Normal file
71
src/routes/auth/+page.svelte
Normal file
|
@ -0,0 +1,71 @@
|
|||
<script lang="ts">
|
||||
import { superForm } from 'sveltekit-superforms';
|
||||
|
||||
const { data } = $props();
|
||||
const { enhance, message, constraints, errors, form } = superForm(data.form);
|
||||
</script>
|
||||
|
||||
<div class="h-[100vh] flex items-center justify-center">
|
||||
<div class="card bg-base-100 w-96 shadow-xl">
|
||||
<form class="m-2 flex-col flex gap-y-4" method="post" use:enhance>
|
||||
<label class="input input-bordered flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="size-4">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M11.89 4.111a5.5 5.5 0 1 0 0 7.778.75.75 0 1 1 1.06 1.061A7 7 0 1 1 15 8a2.5 2.5 0 0 1-4.083 1.935A3.5 3.5 0 1 1 11.5 8a1 1 0 0 0 2 0 5.48 5.48 0 0 0-1.61-3.889ZM10 8a2 2 0 1 0-4 0 2 2 0 0 0 4 0Z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
|
||||
<input
|
||||
bind:value={$form.username}
|
||||
aria-invalid={$errors.username ? 'true' : undefined}
|
||||
type="text"
|
||||
class="grow placeholder:text-base-content/20"
|
||||
placeholder="kaii" />
|
||||
</label>
|
||||
<span
|
||||
class="opacity-0 hidden transition-opacity duration-1000 text-error"
|
||||
class:showerror={$errors.username}>^ {$errors.username?.join(" & ")}</span>
|
||||
<label class="input input-bordered flex items-center gap-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="size-4">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M8 1a3.5 3.5 0 0 0-3.5 3.5V7A1.5 1.5 0 0 0 3 8.5v5A1.5 1.5 0 0 0 4.5 15h7a1.5 1.5 0 0 0 1.5-1.5v-5A1.5 1.5 0 0 0 11.5 7V4.5A3.5 3.5 0 0 0 8 1Zm2 6V4.5a2 2 0 1 0-4 0V7h4Z"
|
||||
clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
<input
|
||||
bind:value={$form.password}
|
||||
aria-invalid={$errors.password ? 'true' : undefined}
|
||||
type="password"
|
||||
class="grow placeholder:text-base-content/20"
|
||||
placeholder="verygoodpassword" />
|
||||
</label>
|
||||
<span
|
||||
class="opacity-0 hidden transition-opacity duration-1000 text-error"
|
||||
class:showerror={$errors.password}>^ {$errors.password}</span>
|
||||
<div class="flex flex-row gap-x-4">
|
||||
<button formaction="?/signup" type="submit" class="btn btn-secondary flex-grow">
|
||||
Signup
|
||||
</button>
|
||||
<button formaction="?/login" type="submit" class="btn btn-secondary btn-outline flex-grow">
|
||||
Login
|
||||
</button>
|
||||
</div>
|
||||
{#if $message}<span class="text-xs">{$message}</span>{/if}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.showerror {
|
||||
@apply block opacity-100;
|
||||
}
|
||||
</style>
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import daisyui from "daisyui"
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [daisyui],
|
||||
}
|
||||
|
Loading…
Reference in a new issue