@atlasauth/svelte 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +231 -0
  3. package/dist/accessors.d.ts +81 -0
  4. package/dist/accessors.js +126 -0
  5. package/dist/appearance.d.ts +85 -0
  6. package/dist/appearance.js +91 -0
  7. package/dist/components/AtlasLoaded.svelte +7 -0
  8. package/dist/components/AtlasLoaded.svelte.d.ts +18 -0
  9. package/dist/components/AtlasLoading.svelte +7 -0
  10. package/dist/components/AtlasLoading.svelte.d.ts +18 -0
  11. package/dist/components/AtlasProvider.svelte +23 -0
  12. package/dist/components/AtlasProvider.svelte.d.ts +33 -0
  13. package/dist/components/AttemptFlow.svelte +95 -0
  14. package/dist/components/AttemptFlow.svelte.d.ts +30 -0
  15. package/dist/components/OrganizationProfile.svelte +22 -0
  16. package/dist/components/OrganizationProfile.svelte.d.ts +16 -0
  17. package/dist/components/OrganizationSwitcher.svelte +25 -0
  18. package/dist/components/OrganizationSwitcher.svelte.d.ts +16 -0
  19. package/dist/components/Protect.svelte +21 -0
  20. package/dist/components/Protect.svelte.d.ts +32 -0
  21. package/dist/components/SignIn.svelte +16 -0
  22. package/dist/components/SignIn.svelte.d.ts +22 -0
  23. package/dist/components/SignUp.svelte +16 -0
  24. package/dist/components/SignUp.svelte.d.ts +21 -0
  25. package/dist/components/SignedIn.svelte +7 -0
  26. package/dist/components/SignedIn.svelte.d.ts +18 -0
  27. package/dist/components/SignedOut.svelte +7 -0
  28. package/dist/components/SignedOut.svelte.d.ts +18 -0
  29. package/dist/components/UserButton.svelte +40 -0
  30. package/dist/components/UserButton.svelte.d.ts +16 -0
  31. package/dist/components/UserProfile.svelte +35 -0
  32. package/dist/components/UserProfile.svelte.d.ts +16 -0
  33. package/dist/context.d.ts +105 -0
  34. package/dist/context.js +258 -0
  35. package/dist/fapi.d.ts +11 -0
  36. package/dist/fapi.js +11 -0
  37. package/dist/i18n.d.ts +23 -0
  38. package/dist/i18n.js +77 -0
  39. package/dist/index.d.ts +31 -0
  40. package/dist/index.js +35 -0
  41. package/dist/protect.d.ts +18 -0
  42. package/dist/protect.js +18 -0
  43. package/dist/server.d.ts +101 -0
  44. package/dist/server.js +87 -0
  45. package/dist/types.d.ts +42 -0
  46. package/dist/types.js +1 -0
  47. package/package.json +57 -0
@@ -0,0 +1,18 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {
8
+ default: {};
9
+ };
10
+ exports?: {} | undefined;
11
+ bindings?: string | undefined;
12
+ };
13
+ export type AtlasLoadingProps = typeof __propDef.props;
14
+ export type AtlasLoadingEvents = typeof __propDef.events;
15
+ export type AtlasLoadingSlots = typeof __propDef.slots;
16
+ export default class AtlasLoading extends SvelteComponent<AtlasLoadingProps, AtlasLoadingEvents, AtlasLoadingSlots> {
17
+ }
18
+ export {};
@@ -0,0 +1,23 @@
1
+ <script>import { onDestroy, onMount } from "svelte";
2
+ import { initAtlas } from "../context";
3
+ import { cssVariables, resolveTokens } from "../appearance";
4
+ export let publishableKey;
5
+ export let frontendApi = void 0;
6
+ export let appearance = void 0;
7
+ export let localization = void 0;
8
+ export let fetchImpl = void 0;
9
+ const client = initAtlas({
10
+ publishableKey,
11
+ frontendApi,
12
+ appearance,
13
+ localization,
14
+ fetchImpl
15
+ });
16
+ $: style = Object.entries(cssVariables(resolveTokens(appearance))).map(([name, value]) => `${name}: ${value}`).join("; ");
17
+ onMount(() => void client.boot());
18
+ onDestroy(() => client.destroy());
19
+ </script>
20
+
21
+ <div class="atlas-root" {style}>
22
+ <slot />
23
+ </div>
@@ -0,0 +1,33 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import { type Appearance } from '../appearance';
3
+ import type { Catalog } from '../i18n';
4
+ declare const __propDef: {
5
+ props: {
6
+ /**
7
+ * §10.1 `<AtlasProvider publishableKey>` — the Svelte peer of React's provider.
8
+ *
9
+ * Calls {@link initAtlas} during component init so the client is in context
10
+ * before any child `<script>` runs, then renders a host-DOM wrapper carrying
11
+ * the appearance tokens as CSS variables. No iframe: components render in the
12
+ * host DOM so Tailwind / plain CSS just work.
13
+ */ publishableKey: string;
14
+ frontendApi?: string | undefined;
15
+ appearance?: Appearance | undefined;
16
+ localization?: Catalog | undefined;
17
+ fetchImpl?: typeof fetch | undefined;
18
+ };
19
+ events: {
20
+ [evt: string]: CustomEvent<any>;
21
+ };
22
+ slots: {
23
+ default: {};
24
+ };
25
+ exports?: {} | undefined;
26
+ bindings?: string | undefined;
27
+ };
28
+ export type AtlasProviderProps = typeof __propDef.props;
29
+ export type AtlasProviderEvents = typeof __propDef.events;
30
+ export type AtlasProviderSlots = typeof __propDef.slots;
31
+ export default class AtlasProvider extends SvelteComponent<AtlasProviderProps, AtlasProviderEvents, AtlasProviderSlots> {
32
+ }
33
+ export {};
@@ -0,0 +1,95 @@
1
+ <script>import { nextStep } from "@atlasauth/js";
2
+ import { useAtlas } from "../context";
3
+ import { classFor } from "../appearance";
4
+ import { translate } from "../i18n";
5
+ export let attempt = null;
6
+ export let busy = false;
7
+ export let errors = [];
8
+ export let titleKey;
9
+ export let onSubmit;
10
+ const atlas = useAtlas();
11
+ const cls = (key, base) => classFor(key, atlas.appearance, base);
12
+ const t = (key, vars) => translate(atlas.catalog, key, vars);
13
+ let values = {};
14
+ $: step = attempt ? nextStep(attempt) : { kind: "collect_identifier" };
15
+ $: fields = (() => {
16
+ switch (step.kind) {
17
+ case "collect_identifier":
18
+ return [{ name: "identifier", labelKey: "signIn.identifierLabel", type: "email" }];
19
+ case "collect_first_factor":
20
+ return [{ name: "password", labelKey: "signIn.passwordLabel", type: "password" }];
21
+ case "collect_second_factor":
22
+ return [{ name: "code", labelKey: "mfa.codeLabel", type: "text" }];
23
+ case "enroll_second_factor":
24
+ return [
25
+ { name: "code", labelKey: "mfa.enrollFirstCodeLabel", type: "text" },
26
+ { name: "secondCode", labelKey: "mfa.enrollSecondCodeLabel", type: "text" }
27
+ ];
28
+ case "collect_email_code":
29
+ return [{ name: "code", labelKey: "signIn.emailCodeLabel", type: "text" }];
30
+ case "collect_new_password":
31
+ return [{ name: "password", labelKey: "reset.newPasswordLabel", type: "password" }];
32
+ default:
33
+ return [];
34
+ }
35
+ })();
36
+ $: message = (() => {
37
+ switch (step.kind) {
38
+ case "await_oauth":
39
+ return t("signIn.magicLinkSent");
40
+ case "done":
41
+ return t("signIn.checkOtherTab");
42
+ case "restart":
43
+ return t("error.generic");
44
+ case "collect_identifier":
45
+ case "collect_first_factor":
46
+ case "collect_second_factor":
47
+ case "enroll_second_factor":
48
+ case "collect_email_code":
49
+ case "collect_new_password":
50
+ return null;
51
+ default:
52
+ return t("error.generic");
53
+ }
54
+ })();
55
+ $: showSubmit = step.kind !== "done" && step.kind !== "await_oauth" && message === null;
56
+ function handleSubmit(event) {
57
+ event.preventDefault();
58
+ onSubmit(values);
59
+ }
60
+ </script>
61
+
62
+ <div class={cls('card', 'atlas-card')}>
63
+ <h1 class={cls('headerTitle', 'atlas-title')}>{t(titleKey)}</h1>
64
+
65
+ {#each errors.filter((e) => !e.param) as error (error.code)}
66
+ <p class={cls('formFieldError', 'atlas-error')} role="alert">{error.message}</p>
67
+ {/each}
68
+
69
+ <form on:submit={handleSubmit}>
70
+ {#if message !== null}
71
+ <p>{message}</p>
72
+ {:else}
73
+ {#each fields as f (f.name)}
74
+ <label class="atlas-field">
75
+ <span>{t(f.labelKey)}</span>
76
+ <input
77
+ class={cls('formFieldInput', 'atlas-input')}
78
+ type={f.type}
79
+ value={values[f.name] ?? ''}
80
+ on:input={(e) => (values[f.name] = e.currentTarget.value)}
81
+ />
82
+ {#each errors.filter((e) => e.param === f.name) as error (error.code)}
83
+ <span class={cls('formFieldError', 'atlas-error')}>{error.message}</span>
84
+ {/each}
85
+ </label>
86
+ {/each}
87
+ {/if}
88
+
89
+ {#if showSubmit}
90
+ <button class={cls('formButtonPrimary', 'atlas-button')} disabled={busy} type="submit">
91
+ {t('signIn.submit')}
92
+ </button>
93
+ {/if}
94
+ </form>
95
+ </div>
@@ -0,0 +1,30 @@
1
+ import { SvelteComponent } from "svelte";
2
+ import { type AttemptView, type FieldError } from '@atlasauth/js';
3
+ declare const __propDef: {
4
+ props: {
5
+ /**
6
+ * The server-driven flow shell — the Svelte peer of React's `AttemptFlow`.
7
+ *
8
+ * Every branch comes from `nextStep`, which is exhaustive (including the
9
+ * `unknown` case, rendered as an honest message rather than nothing). This
10
+ * component makes no decision about what comes next; it renders whatever
11
+ * `status` the server returned.
12
+ */ attempt?: AttemptView | null;
13
+ busy?: boolean;
14
+ errors?: FieldError[];
15
+ titleKey: string;
16
+ onSubmit: (values: Record<string, string>) => void;
17
+ };
18
+ events: {
19
+ [evt: string]: CustomEvent<any>;
20
+ };
21
+ slots: {};
22
+ exports?: {} | undefined;
23
+ bindings?: string | undefined;
24
+ };
25
+ export type AttemptFlowProps = typeof __propDef.props;
26
+ export type AttemptFlowEvents = typeof __propDef.events;
27
+ export type AttemptFlowSlots = typeof __propDef.slots;
28
+ export default class AttemptFlow extends SvelteComponent<AttemptFlowProps, AttemptFlowEvents, AttemptFlowSlots> {
29
+ }
30
+ export {};
@@ -0,0 +1,22 @@
1
+ <script>import { useAtlas } from "../context";
2
+ import { getOrganization } from "../accessors";
3
+ import { classFor } from "../appearance";
4
+ import { translate } from "../i18n";
5
+ import Protect from "./Protect.svelte";
6
+ const atlas = useAtlas();
7
+ const org = getOrganization();
8
+ const t = (key) => translate(atlas.catalog, key);
9
+ $: cardClass = classFor("card", atlas.appearance, "atlas-card");
10
+ </script>
11
+
12
+ {#if $org.organization}
13
+ <div class={cardClass}>
14
+ <h1>{$org.organization.name}</h1>
15
+ <p>{t('organization.roleLabel')}: {$org.membership?.role}</p>
16
+ <!-- Management controls are gated on the ACTIVE org role, matching the
17
+ server's §9.2 rule rather than duplicating a looser one. -->
18
+ <Protect permission="org:sys_memberships:manage">
19
+ <button>{t('organization.invite')}</button>
20
+ </Protect>
21
+ </div>
22
+ {/if}
@@ -0,0 +1,16 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ exports?: {} | undefined;
9
+ bindings?: string | undefined;
10
+ };
11
+ export type OrganizationProfileProps = typeof __propDef.props;
12
+ export type OrganizationProfileEvents = typeof __propDef.events;
13
+ export type OrganizationProfileSlots = typeof __propDef.slots;
14
+ export default class OrganizationProfile extends SvelteComponent<OrganizationProfileProps, OrganizationProfileEvents, OrganizationProfileSlots> {
15
+ }
16
+ export {};
@@ -0,0 +1,25 @@
1
+ <script>import { useAtlas } from "../context";
2
+ import { getOrganization } from "../accessors";
3
+ import { classFor } from "../appearance";
4
+ import { translate } from "../i18n";
5
+ const atlas = useAtlas();
6
+ const org = getOrganization();
7
+ const t = (key) => translate(atlas.catalog, key);
8
+ $: menuClass = classFor("menu", atlas.appearance, "atlas-menu");
9
+ $: itemClass = classFor("menuItem", atlas.appearance, "atlas-menu-item");
10
+ </script>
11
+
12
+ <div class={menuClass}>
13
+ <button class={itemClass} on:click={() => void $org.setActive(null)}>
14
+ {t('organization.personal')}
15
+ </button>
16
+ {#each $org.memberships as membership (membership.organization.id)}
17
+ <button
18
+ class={itemClass}
19
+ disabled={membership.organization.id === $org.organization?.id}
20
+ on:click={() => void $org.setActive(membership.organization.id)}
21
+ >
22
+ {membership.organization.name}
23
+ </button>
24
+ {/each}
25
+ </div>
@@ -0,0 +1,16 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ exports?: {} | undefined;
9
+ bindings?: string | undefined;
10
+ };
11
+ export type OrganizationSwitcherProps = typeof __propDef.props;
12
+ export type OrganizationSwitcherEvents = typeof __propDef.events;
13
+ export type OrganizationSwitcherSlots = typeof __propDef.slots;
14
+ export default class OrganizationSwitcher extends SvelteComponent<OrganizationSwitcherProps, OrganizationSwitcherEvents, OrganizationSwitcherSlots> {
15
+ }
16
+ export {};
@@ -0,0 +1,21 @@
1
+ <script>import { get } from "svelte/store";
2
+ import { useAtlas } from "../context";
3
+ import { evaluate } from "../protect";
4
+ export let permission = void 0;
5
+ export let role = void 0;
6
+ export let anyPermission = void 0;
7
+ export let allPermissions = void 0;
8
+ const atlas = useAtlas();
9
+ const { status, claims } = atlas;
10
+ $: condition = { permission, role, anyPermission, allPermissions };
11
+ $: allowed = $status !== "loading" && evaluate($claims, condition).allowed;
12
+ $: loading = $status === "loading";
13
+ </script>
14
+
15
+ {#if loading}
16
+ <!-- nothing while the SDK is still booting -->
17
+ {:else if allowed}
18
+ <slot />
19
+ {:else}
20
+ <slot name="fallback" />
21
+ {/if}
@@ -0,0 +1,32 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ /**
5
+ * §10.2 `<Protect permission="…">` — conditional rendering.
6
+ *
7
+ * A rendering helper, never an authorization boundary: anyone can flip the
8
+ * condition in devtools. The server checking the same permission is what
9
+ * actually stops them, and this component's job is only to avoid showing a
10
+ * button that would fail. The `default` slot renders when allowed; the
11
+ * `fallback` slot renders otherwise.
12
+ */ permission?: string | undefined;
13
+ role?: string | undefined;
14
+ anyPermission?: string[] | undefined;
15
+ allPermissions?: string[] | undefined;
16
+ };
17
+ events: {
18
+ [evt: string]: CustomEvent<any>;
19
+ };
20
+ slots: {
21
+ default: {};
22
+ fallback: {};
23
+ };
24
+ exports?: {} | undefined;
25
+ bindings?: string | undefined;
26
+ };
27
+ export type ProtectProps = typeof __propDef.props;
28
+ export type ProtectEvents = typeof __propDef.events;
29
+ export type ProtectSlots = typeof __propDef.slots;
30
+ export default class Protect extends SvelteComponent<ProtectProps, ProtectEvents, ProtectSlots> {
31
+ }
32
+ export {};
@@ -0,0 +1,16 @@
1
+ <script>import { onDestroy } from "svelte";
2
+ import { signIn } from "../accessors";
3
+ import AttemptFlow from "./AttemptFlow.svelte";
4
+ export let afterUrl = void 0;
5
+ const flow = signIn();
6
+ const flowState = flow.state;
7
+ onDestroy(() => flow.destroy());
8
+ </script>
9
+
10
+ <AttemptFlow
11
+ attempt={$flowState.attempt}
12
+ busy={$flowState.busy}
13
+ errors={$flowState.errors}
14
+ titleKey="signIn.title"
15
+ onSubmit={flow.submit}
16
+ />
@@ -0,0 +1,22 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ /**
5
+ * §10.2 `<SignIn/>` — a full multi-step flow driven entirely by the
6
+ * server-side attempt status. Contains no decision about what comes next; it
7
+ * renders whatever `status` the server returned.
8
+ */ afterUrl?: string | undefined;
9
+ };
10
+ events: {
11
+ [evt: string]: CustomEvent<any>;
12
+ };
13
+ slots: {};
14
+ exports?: {} | undefined;
15
+ bindings?: string | undefined;
16
+ };
17
+ export type SignInProps = typeof __propDef.props;
18
+ export type SignInEvents = typeof __propDef.events;
19
+ export type SignInSlots = typeof __propDef.slots;
20
+ export default class SignIn extends SvelteComponent<SignInProps, SignInEvents, SignInSlots> {
21
+ }
22
+ export {};
@@ -0,0 +1,16 @@
1
+ <script>import { onDestroy } from "svelte";
2
+ import { signUp } from "../accessors";
3
+ import AttemptFlow from "./AttemptFlow.svelte";
4
+ export let afterUrl = void 0;
5
+ const flow = signUp();
6
+ const flowState = flow.state;
7
+ onDestroy(() => flow.destroy());
8
+ </script>
9
+
10
+ <AttemptFlow
11
+ attempt={$flowState.attempt}
12
+ busy={$flowState.busy}
13
+ errors={$flowState.errors}
14
+ titleKey="signUp.title"
15
+ onSubmit={flow.submit}
16
+ />
@@ -0,0 +1,21 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: {
4
+ /**
5
+ * §10.2 `<SignUp/>` — the server-driven registration flow. Same shell as
6
+ * `<SignIn/>`, only the title differs; the step sequence comes from the server.
7
+ */ afterUrl?: string | undefined;
8
+ };
9
+ events: {
10
+ [evt: string]: CustomEvent<any>;
11
+ };
12
+ slots: {};
13
+ exports?: {} | undefined;
14
+ bindings?: string | undefined;
15
+ };
16
+ export type SignUpProps = typeof __propDef.props;
17
+ export type SignUpEvents = typeof __propDef.events;
18
+ export type SignUpSlots = typeof __propDef.slots;
19
+ export default class SignUp extends SvelteComponent<SignUpProps, SignUpEvents, SignUpSlots> {
20
+ }
21
+ export {};
@@ -0,0 +1,7 @@
1
+ <script>import { getUser } from "../accessors";
2
+ const user = getUser();
3
+ </script>
4
+
5
+ {#if $user.isLoaded && $user.isSignedIn}
6
+ <slot />
7
+ {/if}
@@ -0,0 +1,18 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {
8
+ default: {};
9
+ };
10
+ exports?: {} | undefined;
11
+ bindings?: string | undefined;
12
+ };
13
+ export type SignedInProps = typeof __propDef.props;
14
+ export type SignedInEvents = typeof __propDef.events;
15
+ export type SignedInSlots = typeof __propDef.slots;
16
+ export default class SignedIn extends SvelteComponent<SignedInProps, SignedInEvents, SignedInSlots> {
17
+ }
18
+ export {};
@@ -0,0 +1,7 @@
1
+ <script>import { getUser } from "../accessors";
2
+ const user = getUser();
3
+ </script>
4
+
5
+ {#if $user.isLoaded && !$user.isSignedIn}
6
+ <slot />
7
+ {/if}
@@ -0,0 +1,18 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {
8
+ default: {};
9
+ };
10
+ exports?: {} | undefined;
11
+ bindings?: string | undefined;
12
+ };
13
+ export type SignedOutProps = typeof __propDef.props;
14
+ export type SignedOutEvents = typeof __propDef.events;
15
+ export type SignedOutSlots = typeof __propDef.slots;
16
+ export default class SignedOut extends SvelteComponent<SignedOutProps, SignedOutEvents, SignedOutSlots> {
17
+ }
18
+ export {};
@@ -0,0 +1,40 @@
1
+ <script>import { useAtlas } from "../context";
2
+ import { getUser } from "../accessors";
3
+ import { classFor } from "../appearance";
4
+ import { translate } from "../i18n";
5
+ const atlas = useAtlas();
6
+ const user = getUser();
7
+ const cls = classFor;
8
+ const t = (key) => translate(atlas.catalog, key);
9
+ let open = false;
10
+ $: current = $user.user;
11
+ $: label = current ? [current.first_name, current.last_name].filter(Boolean).join(" ") || current.username || "" : "";
12
+ </script>
13
+
14
+ {#if current}
15
+ <div class="atlas-user-button">
16
+ <button
17
+ class={cls('avatar', atlas.appearance, 'atlas-avatar')}
18
+ on:click={() => (open = !open)}
19
+ aria-expanded={open}
20
+ >
21
+ {#if current.image_url}
22
+ <img alt="" src={current.image_url} />
23
+ {:else}
24
+ <span>{label.slice(0, 1)}</span>
25
+ {/if}
26
+ </button>
27
+
28
+ {#if open}
29
+ <div class={cls('menu', atlas.appearance, 'atlas-menu')} role="menu">
30
+ <span class={cls('menuItem', atlas.appearance, 'atlas-menu-item')}>{label}</span>
31
+ <button
32
+ class={cls('menuItem', atlas.appearance, 'atlas-menu-item')}
33
+ on:click={() => void atlas.signOut()}
34
+ >
35
+ {t('userButton.signOut')}
36
+ </button>
37
+ </div>
38
+ {/if}
39
+ </div>
40
+ {/if}
@@ -0,0 +1,16 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ exports?: {} | undefined;
9
+ bindings?: string | undefined;
10
+ };
11
+ export type UserButtonProps = typeof __propDef.props;
12
+ export type UserButtonEvents = typeof __propDef.events;
13
+ export type UserButtonSlots = typeof __propDef.slots;
14
+ export default class UserButton extends SvelteComponent<UserButtonProps, UserButtonEvents, UserButtonSlots> {
15
+ }
16
+ export {};
@@ -0,0 +1,35 @@
1
+ <script>import { useAtlas } from "../context";
2
+ import { getUser } from "../accessors";
3
+ import { classFor } from "../appearance";
4
+ import { translate } from "../i18n";
5
+ const atlas = useAtlas();
6
+ const user = getUser();
7
+ const t = (key) => translate(atlas.catalog, key);
8
+ $: current = $user.user;
9
+ $: cardClass = classFor("card", atlas.appearance, "atlas-card");
10
+ </script>
11
+
12
+ {#if current}
13
+ <div class={cardClass}>
14
+ <h1>{t('userProfile.title')}</h1>
15
+
16
+ <section>
17
+ <h2>{t('userProfile.emailsSection')}</h2>
18
+ <ul>
19
+ {#each current.email_addresses ?? [] as email (email.id)}
20
+ <li>
21
+ {email.email_address}
22
+ {#if !email.verified}
23
+ <em> — {t('userProfile.unverified')}</em>
24
+ {/if}
25
+ </li>
26
+ {/each}
27
+ </ul>
28
+ </section>
29
+
30
+ <section>
31
+ <h2>{t('userProfile.securitySection')}</h2>
32
+ <p>{current.mfa_enabled ? '2FA on' : '2FA off'}</p>
33
+ </section>
34
+ </div>
35
+ {/if}
@@ -0,0 +1,16 @@
1
+ import { SvelteComponent } from "svelte";
2
+ declare const __propDef: {
3
+ props: Record<string, never>;
4
+ events: {
5
+ [evt: string]: CustomEvent<any>;
6
+ };
7
+ slots: {};
8
+ exports?: {} | undefined;
9
+ bindings?: string | undefined;
10
+ };
11
+ export type UserProfileProps = typeof __propDef.props;
12
+ export type UserProfileEvents = typeof __propDef.events;
13
+ export type UserProfileSlots = typeof __propDef.slots;
14
+ export default class UserProfile extends SvelteComponent<UserProfileProps, UserProfileEvents, UserProfileSlots> {
15
+ }
16
+ export {};