@axium/server 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/web/actions.ts +7 -6
- package/web/index.ts +1 -4
- package/web/lib/Account.svelte +76 -0
- package/web/lib/Dialog.svelte +55 -0
- package/web/lib/FormDialog.svelte +45 -0
- package/web/lib/SignUp.svelte +20 -0
- package/web/lib/index.ts +5 -0
- package/web/routes/+page.server.ts +8 -2
- package/web/routes/+page.svelte +3 -53
- package/web/routes/name/+page.svelte +11 -16
- package/web/routes/signup/+page.svelte +10 -23
- package/web/routes/email/+page.server.ts +0 -5
- package/web/routes/email/+page.svelte +0 -24
package/package.json
CHANGED
package/web/actions.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Registration, User } from '@axium/core/schemas';
|
|
2
2
|
import type { RequestEvent } from '@sveltejs/kit';
|
|
3
|
-
import { fail
|
|
3
|
+
import { fail } from '@sveltejs/kit';
|
|
4
4
|
import { adapter, register } from '../dist/auth.js';
|
|
5
|
-
import { web } from '../dist/config.js';
|
|
6
5
|
import { parseForm } from './utils.js';
|
|
7
6
|
|
|
8
7
|
export async function editEmail(event: RequestEvent) {
|
|
9
8
|
const session = await event.locals.auth();
|
|
9
|
+
if (!session) return fail(401, { error: 'You are not signed in' });
|
|
10
10
|
|
|
11
|
-
const [{ email }, error] = await parseForm(event, User.pick({ email: true }));
|
|
11
|
+
const [{ email } = {}, error] = await parseForm(event, User.pick({ email: true }));
|
|
12
12
|
if (error) return error;
|
|
13
13
|
|
|
14
14
|
const user = await adapter.getUserByEmail(session.user.email);
|
|
@@ -19,13 +19,14 @@ export async function editEmail(event: RequestEvent) {
|
|
|
19
19
|
} catch (error: any) {
|
|
20
20
|
return fail(400, { email, error: typeof error === 'string' ? error : error.message });
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
return { success: true };
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export async function editName(event: RequestEvent) {
|
|
26
26
|
const session = await event.locals.auth();
|
|
27
|
+
if (!session) return fail(401, { error: 'You are not signed in' });
|
|
27
28
|
|
|
28
|
-
const [{ name }, error] = await parseForm(event, User.pick({ name: true }));
|
|
29
|
+
const [{ name } = {}, error] = await parseForm(event, User.pick({ name: true }));
|
|
29
30
|
if (error) return error;
|
|
30
31
|
|
|
31
32
|
const user = await adapter.getUserByEmail(session.user.email);
|
|
@@ -36,7 +37,7 @@ export async function editName(event: RequestEvent) {
|
|
|
36
37
|
} catch (error: any) {
|
|
37
38
|
return fail(400, { name, error: typeof error === 'string' ? error : error.message });
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
+
return { success: true };
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
export async function signup(event: RequestEvent) {
|
package/web/index.ts
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { default as Account } from './routes/+page.svelte';
|
|
3
|
-
export { default as EditName } from './routes/name/+page.svelte';
|
|
4
|
-
export { default as EditEmail } from './routes/email/+page.svelte';
|
|
1
|
+
export * from './lib/index.js';
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { goto } from '$app/navigation';
|
|
3
|
+
import { getUserImage } from '@axium/core';
|
|
4
|
+
import './account.css';
|
|
5
|
+
import FormDialog from './FormDialog.svelte';
|
|
6
|
+
import Icon from './Icon.svelte';
|
|
7
|
+
import './styles.css';
|
|
8
|
+
|
|
9
|
+
const { data, children = () => {}, form } = $props();
|
|
10
|
+
|
|
11
|
+
const user = $derived(data.user);
|
|
12
|
+
|
|
13
|
+
$effect(() => {
|
|
14
|
+
if (!user) goto('/auth/signin');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const image = $derived(getUserImage(user));
|
|
18
|
+
|
|
19
|
+
let changeEmail = $state(false);
|
|
20
|
+
let changeName = $state(false);
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<div class="Account flex-content">
|
|
24
|
+
<img class="pfp" src={image} alt="User profile" />
|
|
25
|
+
<p class="greeting">Welcome, {user.name}</p>
|
|
26
|
+
<div class="account-section main">
|
|
27
|
+
<div class="account-item">
|
|
28
|
+
<p class="subtle">Name</p>
|
|
29
|
+
<p>{user.name}</p>
|
|
30
|
+
<button style:display="contents" class="change" onclick={() => (changeName = true)}><Icon i="chevron-right" /></button>
|
|
31
|
+
</div>
|
|
32
|
+
<div class="account-item">
|
|
33
|
+
<p class="subtle">Email</p>
|
|
34
|
+
<p>{user.email}</p>
|
|
35
|
+
<button style:display="contents" class="change" onclick={() => (changeEmail = true)}><Icon i="chevron-right" /></button>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="account-item">
|
|
38
|
+
<p class="subtle">User ID <dfn title="This is your UUID."><Icon i="regular/circle-info" /></dfn></p>
|
|
39
|
+
<p>{user.id}</p>
|
|
40
|
+
</div>
|
|
41
|
+
<a class="signout" href="/auth/signout"><button>Sign out</button></a>
|
|
42
|
+
</div>
|
|
43
|
+
{@render children()}
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<FormDialog bind:active={changeEmail} {form} submitText="Change" action="?/email">
|
|
47
|
+
<div>
|
|
48
|
+
<label for="email">Email Address</label>
|
|
49
|
+
<input name="email" type="email" value={form?.email || user.email || ''} required />
|
|
50
|
+
</div>
|
|
51
|
+
</FormDialog>
|
|
52
|
+
|
|
53
|
+
<FormDialog bind:active={changeName} {form} submitText="Change" action="?/name">
|
|
54
|
+
<div>
|
|
55
|
+
<label for="name">What do you want to be called?</label>
|
|
56
|
+
<input name="name" type="text" value={form?.name || user.name || ''} required />
|
|
57
|
+
</div>
|
|
58
|
+
</FormDialog>
|
|
59
|
+
|
|
60
|
+
<style>
|
|
61
|
+
.pfp {
|
|
62
|
+
width: 100px;
|
|
63
|
+
height: 100px;
|
|
64
|
+
border-radius: 50%;
|
|
65
|
+
border: 1px solid #8888;
|
|
66
|
+
margin-top: 3em;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.greeting {
|
|
70
|
+
font-size: 2em;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.signout {
|
|
74
|
+
margin-top: 2em;
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
let { show, children, onclose = () => (show = false), ...rest } = $props();
|
|
3
|
+
|
|
4
|
+
let dialog = $state();
|
|
5
|
+
$effect(() => show && dialog.showModal());
|
|
6
|
+
$effect(() => !show && dialog.close());
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<dialog bind:this={dialog} {onclose} {...rest}>
|
|
10
|
+
{@render children()}
|
|
11
|
+
</dialog>
|
|
12
|
+
|
|
13
|
+
<!-- svelte-ignore css_unused_selector -->
|
|
14
|
+
<style>
|
|
15
|
+
dialog {
|
|
16
|
+
border-radius: 1em;
|
|
17
|
+
background: #111;
|
|
18
|
+
border: 1px solid #8888;
|
|
19
|
+
padding: 1em;
|
|
20
|
+
|
|
21
|
+
form {
|
|
22
|
+
display: contents;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
dialog::backdrop {
|
|
27
|
+
background: #0003;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
dialog[open] {
|
|
31
|
+
animation: zoom 0.25s cubic-bezier(0.35, 1.55, 0.65, 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@keyframes zoom {
|
|
35
|
+
from {
|
|
36
|
+
transform: scale(0.95);
|
|
37
|
+
}
|
|
38
|
+
to {
|
|
39
|
+
transform: scale(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
dialog[open]::backdrop {
|
|
44
|
+
animation: fade 0.25s ease-out;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@keyframes fade {
|
|
48
|
+
from {
|
|
49
|
+
opacity: 0;
|
|
50
|
+
}
|
|
51
|
+
to {
|
|
52
|
+
opacity: 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
</style>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { enhance } from '$app/forms';
|
|
3
|
+
import Dialog from './Dialog.svelte';
|
|
4
|
+
import './styles.css';
|
|
5
|
+
|
|
6
|
+
let { children, active = $bindable(null), form, submitText = 'Submit', oncancel = () => {}, action = '', pageMode = false, ...rest } = $props();
|
|
7
|
+
|
|
8
|
+
$effect(() => {
|
|
9
|
+
if (form?.success) active = null;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const show = $derived(!!active || pageMode);
|
|
13
|
+
|
|
14
|
+
function onclick(e: MouseEvent) {
|
|
15
|
+
e.preventDefault();
|
|
16
|
+
active = null;
|
|
17
|
+
oncancel(e);
|
|
18
|
+
}
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<Dialog {show} onclose={() => (active = null)}>
|
|
22
|
+
<form method="POST" {action} use:enhance class="main" {...rest}>
|
|
23
|
+
{#if form?.error}
|
|
24
|
+
<div class="error">{form.error}</div>
|
|
25
|
+
{/if}
|
|
26
|
+
{@render children()}
|
|
27
|
+
{#if pageMode}
|
|
28
|
+
<button type="submit" class="submit">{submitText}</button>
|
|
29
|
+
{:else}
|
|
30
|
+
<div class="actions">
|
|
31
|
+
<button type="button" {onclick}>Cancel</button>
|
|
32
|
+
<button type="submit" class="submit">{submitText}</button>
|
|
33
|
+
</div>
|
|
34
|
+
{/if}
|
|
35
|
+
</form>
|
|
36
|
+
</Dialog>
|
|
37
|
+
|
|
38
|
+
<style>
|
|
39
|
+
.actions {
|
|
40
|
+
display: flex;
|
|
41
|
+
gap: 1em;
|
|
42
|
+
flex-direction: row;
|
|
43
|
+
justify-content: space-between;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import FormDialog from './FormDialog.svelte';
|
|
3
|
+
import './styles.css';
|
|
4
|
+
let { form } = $props();
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<FormDialog pageMode={true} {form} submitText="Sign Up">
|
|
8
|
+
<div>
|
|
9
|
+
<label for="name">Display Name</label>
|
|
10
|
+
<input name="name" type="text" value={form?.name || ''} required />
|
|
11
|
+
</div>
|
|
12
|
+
<div>
|
|
13
|
+
<label for="email">Email</label>
|
|
14
|
+
<input name="email" type="email" value={form?.email || ''} required />
|
|
15
|
+
</div>
|
|
16
|
+
<div>
|
|
17
|
+
<label for="password">Password</label>
|
|
18
|
+
<input name="password" type="password" />
|
|
19
|
+
</div>
|
|
20
|
+
</FormDialog>
|
package/web/lib/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { default as Account } from './Account.svelte';
|
|
2
|
+
export { default as Dialog } from './Dialog.svelte';
|
|
3
|
+
export { default as FormDialog } from './FormDialog.svelte';
|
|
4
|
+
export { default as Icon } from './Icon.svelte';
|
|
5
|
+
export { default as SignUp } from './SignUp.svelte';
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
import type { Actions } from '@sveltejs/kit';
|
|
1
2
|
import { adapter } from '../../dist/auth.js';
|
|
2
|
-
import {
|
|
3
|
+
import { editEmail, editName } from '../actions.js';
|
|
3
4
|
import { loadSession } from '../utils.js';
|
|
4
5
|
import type { PageServerLoadEvent } from './$types.js';
|
|
5
6
|
|
|
6
7
|
export async function load(event: PageServerLoadEvent) {
|
|
7
8
|
const { session } = await loadSession(event);
|
|
8
9
|
const user = await adapter.getUserByEmail(session.user.email);
|
|
9
|
-
return { session, user
|
|
10
|
+
return { session, user };
|
|
10
11
|
}
|
|
12
|
+
|
|
13
|
+
export const actions = {
|
|
14
|
+
email: editEmail,
|
|
15
|
+
name: editName,
|
|
16
|
+
} satisfies Actions;
|
package/web/routes/+page.svelte
CHANGED
|
@@ -1,60 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import '../lib/account.css';
|
|
5
|
-
import Icon from '../lib/Icon.svelte';
|
|
6
|
-
import '../lib/styles.css';
|
|
7
|
-
import type { PageData } from './$types.js';
|
|
8
|
-
|
|
9
|
-
const { data, children = () => {} }: { data: PageData; children?: () => any } = $props();
|
|
10
|
-
|
|
11
|
-
const { user } = data;
|
|
12
|
-
if (!user) goto('/auth/signin');
|
|
13
|
-
|
|
14
|
-
const image = getUserImage(user);
|
|
2
|
+
import Account from '../lib/Account.svelte';
|
|
3
|
+
const { data, form } = $props();
|
|
15
4
|
</script>
|
|
16
5
|
|
|
17
6
|
<svelte:head>
|
|
18
7
|
<title>Account</title>
|
|
19
8
|
</svelte:head>
|
|
20
9
|
|
|
21
|
-
<
|
|
22
|
-
<img class="pfp" src={image} alt="User profile" />
|
|
23
|
-
<p class="greeting">Welcome, {user.name}</p>
|
|
24
|
-
<div class="account-section main">
|
|
25
|
-
<div class="account-item">
|
|
26
|
-
<p class="subtle">Name</p>
|
|
27
|
-
<p>{user.name}</p>
|
|
28
|
-
<a class="change" href="{data.prefix}/name"><Icon i="chevron-right" /></a>
|
|
29
|
-
</div>
|
|
30
|
-
<div class="account-item">
|
|
31
|
-
<p class="subtle">Email</p>
|
|
32
|
-
<p>{user.email}</p>
|
|
33
|
-
<a class="change" href="{data.prefix}/email"><Icon i="chevron-right" /></a>
|
|
34
|
-
</div>
|
|
35
|
-
<div class="account-item">
|
|
36
|
-
<p class="subtle">User ID <dfn title="This is your UUID."><Icon i="regular/circle-info" /></dfn></p>
|
|
37
|
-
<p>{user.id}</p>
|
|
38
|
-
</div>
|
|
39
|
-
<a class="signout" href="/auth/signout"><button>Sign out</button></a>
|
|
40
|
-
</div>
|
|
41
|
-
{@render children()}
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
<style>
|
|
45
|
-
.pfp {
|
|
46
|
-
width: 100px;
|
|
47
|
-
height: 100px;
|
|
48
|
-
border-radius: 50%;
|
|
49
|
-
border: 1px solid #8888;
|
|
50
|
-
margin-top: 3em;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.greeting {
|
|
54
|
-
font-size: 2em;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.signout {
|
|
58
|
-
margin-top: 2em;
|
|
59
|
-
}
|
|
60
|
-
</style>
|
|
10
|
+
<Account {data} {form}></Account>
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { goto } from '$app/navigation';
|
|
3
|
+
import FormDialog from '../../lib/FormDialog.svelte';
|
|
3
4
|
import '../../lib/styles.css';
|
|
4
5
|
let { form, data } = $props();
|
|
5
|
-
|
|
6
|
+
$effect(() => {
|
|
7
|
+
if (form?.success) goto('/');
|
|
8
|
+
});
|
|
6
9
|
</script>
|
|
7
10
|
|
|
8
11
|
<svelte:head>
|
|
9
12
|
<title>Edit Name</title>
|
|
10
13
|
</svelte:head>
|
|
11
14
|
|
|
12
|
-
<
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
{/if}
|
|
19
|
-
<div>
|
|
20
|
-
<label for="name">What do you want to be called?</label>
|
|
21
|
-
<input name="name" type="text" value={form?.name || user.name || ''} required />
|
|
22
|
-
</div>
|
|
23
|
-
<button type="submit">Continue</button>
|
|
24
|
-
</form>
|
|
25
|
-
</div>
|
|
15
|
+
<FormDialog pageMode={true} {form} submitText="Change">
|
|
16
|
+
<div>
|
|
17
|
+
<label for="name">What do you want to be called?</label>
|
|
18
|
+
<input name="name" type="text" value={form?.name || data.session.user.name || ''} required />
|
|
19
|
+
</div>
|
|
20
|
+
</FormDialog>
|
|
@@ -1,28 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { goto } from '$app/navigation';
|
|
3
|
+
import SignUp from '../../lib/SignUp.svelte';
|
|
3
4
|
import '../../lib/styles.css';
|
|
4
5
|
let { form } = $props();
|
|
6
|
+
$effect(() => {
|
|
7
|
+
if (form?.success) goto('/');
|
|
8
|
+
});
|
|
5
9
|
</script>
|
|
6
10
|
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
</div>
|
|
13
|
-
{/if}
|
|
14
|
-
<div>
|
|
15
|
-
<label for="name">Display Name</label>
|
|
16
|
-
<input name="name" type="text" value={form?.name || ''} required />
|
|
17
|
-
</div>
|
|
18
|
-
<div>
|
|
19
|
-
<label for="email">Email</label>
|
|
20
|
-
<input name="email" type="email" value={form?.email || ''} required />
|
|
21
|
-
</div>
|
|
22
|
-
<div>
|
|
23
|
-
<label for="password">Password</label>
|
|
24
|
-
<input name="password" type="password" />
|
|
25
|
-
</div>
|
|
26
|
-
<button type="submit">Register</button>
|
|
27
|
-
</form>
|
|
28
|
-
</div>
|
|
11
|
+
<svelte:head>
|
|
12
|
+
<title>Sign Up</title>
|
|
13
|
+
</svelte:head>
|
|
14
|
+
|
|
15
|
+
<SignUp {form} />
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { enhance } from '$app/forms';
|
|
3
|
-
import '../../lib/styles.css';
|
|
4
|
-
let { form, data } = $props();
|
|
5
|
-
</script>
|
|
6
|
-
|
|
7
|
-
<svelte:head>
|
|
8
|
-
<title>Edit Email</title>
|
|
9
|
-
</svelte:head>
|
|
10
|
-
|
|
11
|
-
<div class="EditEmail">
|
|
12
|
-
<form method="POST" class="main" use:enhance>
|
|
13
|
-
{#if form?.error}
|
|
14
|
-
<div class="error">
|
|
15
|
-
{typeof form.error === 'string' ? form.error : JSON.stringify(form.error)}
|
|
16
|
-
</div>
|
|
17
|
-
{/if}
|
|
18
|
-
<div>
|
|
19
|
-
<label for="email">Email Address</label>
|
|
20
|
-
<input name="email" type="email" value={form?.email || data.session.user.email || ''} required />
|
|
21
|
-
</div>
|
|
22
|
-
<button type="submit">Continue</button>
|
|
23
|
-
</form>
|
|
24
|
-
</div>
|