@glw907/cairn-cms 0.5.1 → 0.6.0-rc.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/dist/auth/crypto.d.ts +13 -0
- package/dist/auth/crypto.d.ts.map +1 -0
- package/dist/auth/crypto.js +31 -0
- package/dist/auth/store.d.ts +41 -0
- package/dist/auth/store.d.ts.map +1 -0
- package/dist/auth/store.js +115 -0
- package/dist/auth/types.d.ts +25 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +1 -0
- package/dist/components/AdminLayout.svelte +58 -164
- package/dist/components/AdminLayout.svelte.d.ts +14 -18
- package/dist/components/AdminLayout.svelte.d.ts.map +1 -1
- package/dist/components/ComponentPalette.svelte +36 -20
- package/dist/components/ComponentPalette.svelte.d.ts +11 -4
- package/dist/components/ComponentPalette.svelte.d.ts.map +1 -1
- package/dist/components/ConceptList.svelte +81 -0
- package/dist/components/ConceptList.svelte.d.ts +13 -0
- package/dist/components/ConceptList.svelte.d.ts.map +1 -0
- package/dist/components/ConfirmPage.svelte +23 -20
- package/dist/components/ConfirmPage.svelte.d.ts +6 -0
- package/dist/components/ConfirmPage.svelte.d.ts.map +1 -1
- package/dist/components/EditPage.svelte +155 -136
- package/dist/components/EditPage.svelte.d.ts +16 -8
- package/dist/components/EditPage.svelte.d.ts.map +1 -1
- package/dist/components/LoginPage.svelte +42 -52
- package/dist/components/LoginPage.svelte.d.ts +12 -0
- package/dist/components/LoginPage.svelte.d.ts.map +1 -1
- package/dist/components/ManageEditors.svelte +81 -0
- package/dist/components/ManageEditors.svelte.d.ts +24 -0
- package/dist/components/ManageEditors.svelte.d.ts.map +1 -0
- package/dist/components/MarkdownEditor.svelte +81 -0
- package/dist/components/MarkdownEditor.svelte.d.ts +20 -0
- package/dist/components/MarkdownEditor.svelte.d.ts.map +1 -0
- package/dist/components/NavTree.svelte +73 -63
- package/dist/components/NavTree.svelte.d.ts +13 -4
- package/dist/components/NavTree.svelte.d.ts.map +1 -1
- package/dist/components/cairn-admin.css +42 -0
- package/dist/components/index.d.ts +3 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -4
- package/dist/content/compose.d.ts +7 -0
- package/dist/content/compose.d.ts.map +1 -0
- package/dist/content/compose.js +32 -0
- package/dist/content/concepts.d.ts +17 -0
- package/dist/content/concepts.d.ts.map +1 -0
- package/dist/content/concepts.js +41 -0
- package/dist/content/frontmatter.d.ts +18 -0
- package/dist/content/frontmatter.d.ts.map +1 -0
- package/dist/content/frontmatter.js +58 -0
- package/dist/content/ids.d.ts +17 -0
- package/dist/content/ids.d.ts.map +1 -0
- package/dist/content/ids.js +33 -0
- package/dist/content/types.d.ts +210 -0
- package/dist/content/types.d.ts.map +1 -0
- package/dist/content/types.js +1 -0
- package/dist/content/validate.d.ts +13 -0
- package/dist/content/validate.d.ts.map +1 -0
- package/dist/content/validate.js +45 -0
- package/dist/email.d.ts +25 -12
- package/dist/email.d.ts.map +1 -1
- package/dist/email.js +24 -24
- package/dist/env.d.ts +24 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +29 -0
- package/dist/github/credentials.d.ts +12 -0
- package/dist/github/credentials.d.ts.map +1 -0
- package/dist/github/credentials.js +11 -0
- package/dist/github/repo.d.ts +49 -0
- package/dist/github/repo.d.ts.map +1 -0
- package/dist/github/repo.js +123 -0
- package/dist/github/signing.d.ts +17 -0
- package/dist/github/signing.d.ts.map +1 -0
- package/dist/github/signing.js +79 -0
- package/dist/github/types.d.ts +35 -0
- package/dist/github/types.d.ts.map +1 -0
- package/dist/github/types.js +19 -0
- package/dist/index.d.ts +27 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -10
- package/dist/{nav.d.ts → nav/site-config.d.ts} +16 -24
- package/dist/nav/site-config.d.ts.map +1 -0
- package/dist/{nav.js → nav/site-config.js} +27 -13
- package/dist/render/glyph.d.ts +1 -1
- package/dist/render/glyph.d.ts.map +1 -1
- package/dist/render/index.d.ts +5 -5
- package/dist/render/index.d.ts.map +1 -1
- package/dist/render/index.js +6 -6
- package/dist/render/pipeline.d.ts +3 -3
- package/dist/render/pipeline.d.ts.map +1 -1
- package/dist/render/pipeline.js +4 -4
- package/dist/render/registry.d.ts +6 -4
- package/dist/render/registry.d.ts.map +1 -1
- package/dist/render/registry.js +8 -6
- package/dist/render/rehype-dispatch.d.ts +1 -1
- package/dist/render/rehype-dispatch.d.ts.map +1 -1
- package/dist/render/remark-directives.d.ts +1 -1
- package/dist/render/remark-directives.d.ts.map +1 -1
- package/dist/render/sanitize.d.ts +8 -0
- package/dist/render/sanitize.d.ts.map +1 -0
- package/dist/render/sanitize.js +26 -0
- package/dist/sveltekit/auth-routes.d.ts +23 -0
- package/dist/sveltekit/auth-routes.d.ts.map +1 -0
- package/dist/sveltekit/auth-routes.js +85 -0
- package/dist/sveltekit/content-routes.d.ts +80 -0
- package/dist/sveltekit/content-routes.d.ts.map +1 -0
- package/dist/sveltekit/content-routes.js +183 -0
- package/dist/sveltekit/editors-routes.d.ts +24 -0
- package/dist/sveltekit/editors-routes.d.ts.map +1 -0
- package/dist/sveltekit/editors-routes.js +73 -0
- package/dist/sveltekit/guard.d.ts +9 -0
- package/dist/sveltekit/guard.d.ts.map +1 -0
- package/dist/sveltekit/guard.js +43 -0
- package/dist/sveltekit/health.d.ts +19 -0
- package/dist/sveltekit/health.d.ts.map +1 -0
- package/dist/sveltekit/health.js +12 -0
- package/dist/sveltekit/index.d.ts +9 -173
- package/dist/sveltekit/index.d.ts.map +1 -1
- package/dist/sveltekit/index.js +8 -348
- package/dist/sveltekit/nav-routes.d.ts +30 -0
- package/dist/sveltekit/nav-routes.d.ts.map +1 -0
- package/dist/sveltekit/nav-routes.js +103 -0
- package/dist/sveltekit/types.d.ts +32 -0
- package/dist/sveltekit/types.d.ts.map +1 -0
- package/dist/sveltekit/types.js +1 -0
- package/package.json +32 -57
- package/src/lib/auth/crypto.ts +37 -0
- package/src/lib/auth/store.ts +158 -0
- package/src/lib/auth/types.ts +27 -0
- package/src/lib/components/AdminLayout.svelte +58 -164
- package/src/lib/components/ComponentPalette.svelte +36 -20
- package/src/lib/components/ConceptList.svelte +81 -0
- package/src/lib/components/ConfirmPage.svelte +23 -20
- package/src/lib/components/EditPage.svelte +155 -136
- package/src/lib/components/LoginPage.svelte +42 -52
- package/src/lib/components/ManageEditors.svelte +81 -0
- package/src/lib/components/MarkdownEditor.svelte +81 -0
- package/src/lib/components/NavTree.svelte +73 -63
- package/src/lib/components/cairn-admin.css +42 -0
- package/src/lib/components/index.ts +5 -4
- package/src/lib/content/compose.ts +39 -0
- package/src/lib/content/concepts.ts +57 -0
- package/src/lib/content/frontmatter.ts +71 -0
- package/src/lib/content/ids.ts +38 -0
- package/src/lib/content/types.ts +235 -0
- package/src/lib/content/validate.ts +51 -0
- package/src/lib/email.ts +52 -38
- package/src/lib/env.ts +32 -0
- package/src/lib/github/credentials.ts +27 -0
- package/src/lib/github/repo.ts +138 -0
- package/src/lib/github/signing.ts +97 -0
- package/src/lib/github/types.ts +46 -0
- package/src/lib/index.ts +86 -10
- package/src/lib/{nav.ts → nav/site-config.ts} +31 -24
- package/src/lib/render/glyph.ts +6 -6
- package/src/lib/render/index.ts +6 -6
- package/src/lib/render/pipeline.ts +22 -22
- package/src/lib/render/registry.ts +33 -26
- package/src/lib/render/rehype-dispatch.ts +47 -47
- package/src/lib/render/remark-directives.ts +46 -46
- package/src/lib/render/sanitize.ts +27 -0
- package/src/lib/sveltekit/auth-routes.ts +107 -0
- package/src/lib/sveltekit/content-routes.ts +261 -0
- package/src/lib/sveltekit/editors-routes.ts +82 -0
- package/src/lib/sveltekit/guard.ts +47 -0
- package/src/lib/sveltekit/health.ts +24 -0
- package/src/lib/sveltekit/index.ts +19 -512
- package/src/lib/sveltekit/nav-routes.ts +139 -0
- package/src/lib/sveltekit/types.ts +33 -0
- package/dist/adapter.d.ts +0 -93
- package/dist/adapter.d.ts.map +0 -1
- package/dist/adapter.js +0 -30
- package/dist/auth/admins.d.ts +0 -33
- package/dist/auth/admins.d.ts.map +0 -1
- package/dist/auth/admins.js +0 -90
- package/dist/auth/capabilities.d.ts +0 -7
- package/dist/auth/capabilities.d.ts.map +0 -1
- package/dist/auth/capabilities.js +0 -26
- package/dist/auth/config.d.ts +0 -2097
- package/dist/auth/config.d.ts.map +0 -1
- package/dist/auth/config.js +0 -78
- package/dist/auth/guard.d.ts +0 -34
- package/dist/auth/guard.d.ts.map +0 -1
- package/dist/auth/guard.js +0 -47
- package/dist/auth/index.d.ts +0 -5
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js +0 -7
- package/dist/auth/schema.d.ts +0 -750
- package/dist/auth/schema.d.ts.map +0 -1
- package/dist/auth/schema.js +0 -93
- package/dist/carta.d.ts +0 -39
- package/dist/carta.d.ts.map +0 -1
- package/dist/carta.js +0 -30
- package/dist/components/CollectionList.svelte +0 -96
- package/dist/components/CollectionList.svelte.d.ts +0 -8
- package/dist/components/CollectionList.svelte.d.ts.map +0 -1
- package/dist/components/ManageAdmins.svelte +0 -84
- package/dist/components/ManageAdmins.svelte.d.ts +0 -10
- package/dist/components/ManageAdmins.svelte.d.ts.map +0 -1
- package/dist/content.d.ts +0 -3
- package/dist/content.d.ts.map +0 -1
- package/dist/content.js +0 -10
- package/dist/editor.d.ts +0 -25
- package/dist/editor.d.ts.map +0 -1
- package/dist/editor.js +0 -20
- package/dist/frontmatter.d.ts +0 -3
- package/dist/frontmatter.d.ts.map +0 -1
- package/dist/frontmatter.js +0 -16
- package/dist/github.d.ts +0 -72
- package/dist/github.d.ts.map +0 -1
- package/dist/github.js +0 -171
- package/dist/nav.d.ts.map +0 -1
- package/dist/slug.d.ts +0 -7
- package/dist/slug.d.ts.map +0 -1
- package/dist/slug.js +0 -15
- package/dist/utils.d.ts +0 -3
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -11
- package/src/lib/adapter.ts +0 -144
- package/src/lib/auth/admins.ts +0 -106
- package/src/lib/auth/capabilities.ts +0 -35
- package/src/lib/auth/config.ts +0 -108
- package/src/lib/auth/guard.ts +0 -60
- package/src/lib/auth/index.ts +0 -7
- package/src/lib/auth/schema.ts +0 -112
- package/src/lib/carta.ts +0 -59
- package/src/lib/components/CollectionList.svelte +0 -96
- package/src/lib/components/ManageAdmins.svelte +0 -84
- package/src/lib/content.ts +0 -11
- package/src/lib/editor.ts +0 -38
- package/src/lib/frontmatter.ts +0 -17
- package/src/lib/github.ts +0 -220
- package/src/lib/slug.ts +0 -16
- package/src/lib/utils.ts +0 -12
|
@@ -1,64 +1,54 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
The magic-link sign-in page. A plain form POST to the page's default action (the engine's
|
|
4
|
+
`requestAction`); no client SDK. The success message is identical whether or not the email is on
|
|
5
|
+
the allowlist, so the page never leaks membership (spec §7.1).
|
|
6
|
+
-->
|
|
1
7
|
<script lang="ts">
|
|
2
|
-
|
|
3
|
-
// origin). To avoid enumeration the UI shows the same neutral copy whether or not the email is
|
|
4
|
-
// on the allowlist. The server only emails actual editors (see auth/config.ts send gate).
|
|
5
|
-
import { createAuthClient } from 'better-auth/svelte';
|
|
6
|
-
import { magicLinkClient } from 'better-auth/client/plugins';
|
|
7
|
-
|
|
8
|
-
// The browser client lives in the one component that needs it (requesting a link). Sign-out
|
|
9
|
-
// and editor management go through server endpoints, so no shared client module is needed.
|
|
10
|
-
// A component-local const keeps better-auth's deep client types out of the packaged .d.ts.
|
|
11
|
-
const authClient = createAuthClient({ plugins: [magicLinkClient()] });
|
|
8
|
+
import './cairn-admin.css';
|
|
12
9
|
|
|
13
10
|
interface Props {
|
|
14
|
-
data:
|
|
11
|
+
/** The login load's data: the site name and an optional error. */
|
|
12
|
+
data: { siteName: string; error: string | null };
|
|
13
|
+
/** The action result: `sent` is true once a request was accepted. */
|
|
14
|
+
form: { sent?: boolean } | null;
|
|
15
15
|
}
|
|
16
|
-
let { data }: Props = $props();
|
|
17
|
-
|
|
18
|
-
let email = $state('');
|
|
19
|
-
let requested = $state(false);
|
|
20
|
-
let busy = $state(false);
|
|
21
16
|
|
|
22
|
-
|
|
23
|
-
event.preventDefault();
|
|
24
|
-
busy = true;
|
|
25
|
-
// The magic-link email points at our /admin/auth/confirm page (built in config.ts), not a
|
|
26
|
-
// GET-verify URL, so the result is the same regardless of allowlist membership.
|
|
27
|
-
await authClient.signIn.magicLink({ email });
|
|
28
|
-
busy = false;
|
|
29
|
-
requested = true;
|
|
30
|
-
}
|
|
17
|
+
let { data, form }: Props = $props();
|
|
31
18
|
</script>
|
|
32
19
|
|
|
33
20
|
<svelte:head>
|
|
34
|
-
<
|
|
21
|
+
<meta name="robots" content="noindex, nofollow" />
|
|
35
22
|
</svelte:head>
|
|
36
23
|
|
|
37
|
-
<div
|
|
38
|
-
<
|
|
39
|
-
|
|
24
|
+
<div data-theme="cairn-admin" class="bg-base-200 text-base-content flex min-h-screen items-center justify-center p-4">
|
|
25
|
+
<div class="rounded-box border border-base-300 bg-base-100 w-full max-w-sm p-6 shadow">
|
|
26
|
+
<h1 class="mb-1 text-lg font-semibold">Sign in to {data.siteName}</h1>
|
|
27
|
+
<p class="mb-4 text-sm text-[var(--color-muted)]">Enter your email and we'll send a sign-in link.</p>
|
|
40
28
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
29
|
+
{#if form?.sent}
|
|
30
|
+
<div role="status" class="alert alert-success text-sm">
|
|
31
|
+
Check your email for a sign-in link. It expires in 10 minutes.
|
|
32
|
+
</div>
|
|
33
|
+
{:else}
|
|
34
|
+
{#if data.error}
|
|
35
|
+
<div role="alert" class="alert alert-error mb-3 text-sm">That link expired. Request a new one.</div>
|
|
36
|
+
{/if}
|
|
37
|
+
<form method="POST" class="flex flex-col gap-3">
|
|
38
|
+
<label class="flex flex-col gap-1">
|
|
39
|
+
<span class="text-sm font-medium">Email</span>
|
|
40
|
+
<input
|
|
41
|
+
type="email"
|
|
42
|
+
name="email"
|
|
43
|
+
required
|
|
44
|
+
autocomplete="email"
|
|
45
|
+
aria-label="Email"
|
|
46
|
+
class="input w-full"
|
|
47
|
+
placeholder="you@example.com"
|
|
48
|
+
/>
|
|
49
|
+
</label>
|
|
50
|
+
<button type="submit" class="btn btn-primary">Send sign-in link</button>
|
|
51
|
+
</form>
|
|
52
|
+
{/if}
|
|
53
|
+
</div>
|
|
64
54
|
</div>
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
import './cairn-admin.css';
|
|
1
2
|
interface Props {
|
|
3
|
+
/** The login load's data: the site name and an optional error. */
|
|
2
4
|
data: {
|
|
3
5
|
siteName: string;
|
|
6
|
+
error: string | null;
|
|
4
7
|
};
|
|
8
|
+
/** The action result: `sent` is true once a request was accepted. */
|
|
9
|
+
form: {
|
|
10
|
+
sent?: boolean;
|
|
11
|
+
} | null;
|
|
5
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* The magic-link sign-in page. A plain form POST to the page's default action (the engine's
|
|
15
|
+
* `requestAction`); no client SDK. The success message is identical whether or not the email is on
|
|
16
|
+
* the allowlist, so the page never leaks membership (spec §7.1).
|
|
17
|
+
*/
|
|
6
18
|
declare const LoginPage: import("svelte").Component<Props, {}, "">;
|
|
7
19
|
type LoginPage = ReturnType<typeof LoginPage>;
|
|
8
20
|
export default LoginPage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LoginPage.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/LoginPage.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LoginPage.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/LoginPage.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,mBAAmB,CAAC;AAGzB,UAAU,KAAK;IACb,kEAAkE;IAClE,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACjD,qEAAqE;IACrE,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACjC;AAuCH;;;;GAIG;AACH,QAAA,MAAM,SAAS,2CAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
The owner-gated editor management surface: a table of editors with role-flip and remove actions,
|
|
4
|
+
and an add-editor form. The acting owner's own row disables its destructive controls; the
|
|
5
|
+
last-owner anti-lockout rule itself is enforced server-side (editors-routes). Actions post to the
|
|
6
|
+
named `?/setRole`, `?/remove`, and `?/add` actions.
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import type { Editor } from '../auth/types.js';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
/** The editors load's data, plus the site name. */
|
|
13
|
+
data: { editors: Editor[]; self: string; siteName: string };
|
|
14
|
+
/** The last action's result (an error message when it failed). */
|
|
15
|
+
form: { error?: string; ok?: boolean } | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { data, form }: Props = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<header class="mb-4">
|
|
22
|
+
<h1 class="text-xl font-semibold">Editors</h1>
|
|
23
|
+
</header>
|
|
24
|
+
|
|
25
|
+
{#if form?.error}
|
|
26
|
+
<div role="alert" class="alert alert-error mb-4 text-sm">{form.error}</div>
|
|
27
|
+
{/if}
|
|
28
|
+
|
|
29
|
+
<div class="overflow-x-auto rounded-box border border-base-300 bg-base-100 mb-6">
|
|
30
|
+
<table class="table">
|
|
31
|
+
<thead>
|
|
32
|
+
<tr><th scope="col">Name</th><th scope="col">Email</th><th scope="col">Role</th><th scope="col"><span class="sr-only">Actions</span></th></tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
{#each data.editors as editor (editor.email)}
|
|
36
|
+
{@const isSelf = editor.email === data.self}
|
|
37
|
+
<tr>
|
|
38
|
+
<td>{editor.displayName}</td>
|
|
39
|
+
<td>{editor.email}</td>
|
|
40
|
+
<td>
|
|
41
|
+
<span class="badge {editor.role === 'owner' ? 'badge-primary' : 'badge-ghost'}">{editor.role}</span>
|
|
42
|
+
</td>
|
|
43
|
+
<td class="flex justify-end gap-2">
|
|
44
|
+
<form method="POST" action="?/setRole">
|
|
45
|
+
<input type="hidden" name="email" value={editor.email} />
|
|
46
|
+
<input type="hidden" name="role" value={editor.role === 'owner' ? 'editor' : 'owner'} />
|
|
47
|
+
<button type="submit" class="btn btn-ghost btn-xs" disabled={isSelf} aria-label={`Toggle role for ${editor.displayName}`}>
|
|
48
|
+
{editor.role === 'owner' ? 'Make editor' : 'Make owner'}
|
|
49
|
+
</button>
|
|
50
|
+
</form>
|
|
51
|
+
<form method="POST" action="?/remove">
|
|
52
|
+
<input type="hidden" name="email" value={editor.email} />
|
|
53
|
+
<button type="submit" class="btn btn-ghost btn-xs text-error" disabled={isSelf} aria-label={`Remove ${editor.displayName}`}>
|
|
54
|
+
Remove
|
|
55
|
+
</button>
|
|
56
|
+
</form>
|
|
57
|
+
</td>
|
|
58
|
+
</tr>
|
|
59
|
+
{/each}
|
|
60
|
+
</tbody>
|
|
61
|
+
</table>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<form method="POST" action="?/add" class="rounded-box border border-base-300 bg-base-100 grid gap-3 p-4 sm:grid-cols-[1fr_1fr_auto_auto] sm:items-end">
|
|
65
|
+
<label class="flex flex-col gap-1">
|
|
66
|
+
<span class="text-sm font-medium">Name</span>
|
|
67
|
+
<input class="input" name="name" aria-label="Name" required />
|
|
68
|
+
</label>
|
|
69
|
+
<label class="flex flex-col gap-1">
|
|
70
|
+
<span class="text-sm font-medium">Email</span>
|
|
71
|
+
<input class="input" type="email" name="email" aria-label="Email" autocomplete="off" required />
|
|
72
|
+
</label>
|
|
73
|
+
<label class="flex flex-col gap-1">
|
|
74
|
+
<span class="text-sm font-medium">Role</span>
|
|
75
|
+
<select class="select" name="role" aria-label="Role">
|
|
76
|
+
<option value="editor">editor</option>
|
|
77
|
+
<option value="owner">owner</option>
|
|
78
|
+
</select>
|
|
79
|
+
</label>
|
|
80
|
+
<button type="submit" class="btn btn-primary">Add editor</button>
|
|
81
|
+
</form>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Editor } from '../auth/types.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** The editors load's data, plus the site name. */
|
|
4
|
+
data: {
|
|
5
|
+
editors: Editor[];
|
|
6
|
+
self: string;
|
|
7
|
+
siteName: string;
|
|
8
|
+
};
|
|
9
|
+
/** The last action's result (an error message when it failed). */
|
|
10
|
+
form: {
|
|
11
|
+
error?: string;
|
|
12
|
+
ok?: boolean;
|
|
13
|
+
} | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The owner-gated editor management surface: a table of editors with role-flip and remove actions,
|
|
17
|
+
* and an add-editor form. The acting owner's own row disables its destructive controls; the
|
|
18
|
+
* last-owner anti-lockout rule itself is enforced server-side (editors-routes). Actions post to the
|
|
19
|
+
* named `?/setRole`, `?/remove`, and `?/add` actions.
|
|
20
|
+
*/
|
|
21
|
+
declare const ManageEditors: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type ManageEditors = ReturnType<typeof ManageEditors>;
|
|
23
|
+
export default ManageEditors;
|
|
24
|
+
//# sourceMappingURL=ManageEditors.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ManageEditors.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/ManageEditors.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG7C,UAAU,KAAK;IACb,mDAAmD;IACnD,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,kEAAkE;IAClE,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/C;AAyEH;;;;;GAKG;AACH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
The `MarkdownEditor` seam (spec §6, seam 5): a thin wrapper over Carta exposing a bindable value
|
|
4
|
+
and a cursor-insert callback. Carta and Shiki are client-only, so the editor mounts after the
|
|
5
|
+
component does; until then the hidden field still carries the value so the form submits correctly.
|
|
6
|
+
Swapping Carta for a bare CodeMirror editor stays a one-file change.
|
|
7
|
+
-->
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import { onMount } from 'svelte';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
/** The markdown source; bindable so the parent reads edits back. */
|
|
13
|
+
value: string;
|
|
14
|
+
/** The hidden field name the value is mirrored to for form submit. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Carta extensions from the adapter, for the design-accurate preview. */
|
|
17
|
+
plugins?: unknown[];
|
|
18
|
+
/** Receives a `(text) => void` that inserts at the cursor; the palette calls it. */
|
|
19
|
+
registerInsert?: (insert: (text: string) => void) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let { value = $bindable(), name, plugins = [], registerInsert }: Props = $props();
|
|
23
|
+
|
|
24
|
+
// Local structural type for the Carta editing surface this seam uses. carta-md re-exports its
|
|
25
|
+
// Svelte components from the package entry, so its `Carta` class is not reachable as a named
|
|
26
|
+
// export under NodeNext; a structural type stays compatible without naming it (the shape
|
|
27
|
+
// legacy/src/lib/editor.ts relied on, verified against carta-md@4.11).
|
|
28
|
+
interface CartaInput {
|
|
29
|
+
getSelection(): { start: number };
|
|
30
|
+
insertAt(position: number, text: string): void;
|
|
31
|
+
update(): boolean;
|
|
32
|
+
}
|
|
33
|
+
interface CartaLike {
|
|
34
|
+
input?: CartaInput;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let mounted = $state(false);
|
|
38
|
+
// Carta and the MarkdownEditor component load only in the browser, after mount, so the server
|
|
39
|
+
// bundle never pulls in Carta or Shiki (guarded by the carta-boundary test). The component keeps
|
|
40
|
+
// its real type, so `value` stays bindable; the Carta constructor is reached through a cast
|
|
41
|
+
// because the package entry does not surface the class by name.
|
|
42
|
+
let Editor = $state<(typeof import('carta-md'))['MarkdownEditor'] | null>(null);
|
|
43
|
+
let carta = $state<CartaLike | null>(null);
|
|
44
|
+
|
|
45
|
+
onMount(async () => {
|
|
46
|
+
const mod = await import('carta-md');
|
|
47
|
+
const CartaCtor = (
|
|
48
|
+
mod as unknown as { Carta: new (options: { extensions?: unknown[]; sanitizer: false }) => CartaLike }
|
|
49
|
+
).Carta;
|
|
50
|
+
const instance = new CartaCtor({
|
|
51
|
+
extensions: plugins,
|
|
52
|
+
// Sanitization is the site adapter's concern; the seam passes raw markdown through.
|
|
53
|
+
sanitizer: false,
|
|
54
|
+
});
|
|
55
|
+
carta = instance;
|
|
56
|
+
Editor = mod.MarkdownEditor;
|
|
57
|
+
// Insert at the current cursor through carta.input once the editor is mounted; fall back to
|
|
58
|
+
// appending while input is not yet populated (the pre-mount textarea phase).
|
|
59
|
+
registerInsert?.((text: string) => {
|
|
60
|
+
const inp = instance.input;
|
|
61
|
+
if (inp) {
|
|
62
|
+
const pos = inp.getSelection().start;
|
|
63
|
+
const prefix = pos > 0 ? '\n\n' : '';
|
|
64
|
+
inp.insertAt(pos, `${prefix}${text}`);
|
|
65
|
+
inp.update();
|
|
66
|
+
} else {
|
|
67
|
+
value = value ? `${value}\n\n${text}` : text;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
mounted = true;
|
|
71
|
+
});
|
|
72
|
+
</script>
|
|
73
|
+
|
|
74
|
+
<input type="hidden" {name} value={value} />
|
|
75
|
+
|
|
76
|
+
{#if mounted && Editor && carta}
|
|
77
|
+
{@const EditorComponent = Editor}
|
|
78
|
+
<EditorComponent carta={carta as never} bind:value theme="default" mode="tabs" />
|
|
79
|
+
{:else}
|
|
80
|
+
<textarea class="textarea min-h-64 w-full font-mono text-sm" bind:value aria-label="Markdown source"></textarea>
|
|
81
|
+
{/if}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** The markdown source; bindable so the parent reads edits back. */
|
|
3
|
+
value: string;
|
|
4
|
+
/** The hidden field name the value is mirrored to for form submit. */
|
|
5
|
+
name: string;
|
|
6
|
+
/** Carta extensions from the adapter, for the design-accurate preview. */
|
|
7
|
+
plugins?: unknown[];
|
|
8
|
+
/** Receives a `(text) => void` that inserts at the cursor; the palette calls it. */
|
|
9
|
+
registerInsert?: (insert: (text: string) => void) => void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The `MarkdownEditor` seam (spec §6, seam 5): a thin wrapper over Carta exposing a bindable value
|
|
13
|
+
* and a cursor-insert callback. Carta and Shiki are client-only, so the editor mounts after the
|
|
14
|
+
* component does; until then the hidden field still carries the value so the form submits correctly.
|
|
15
|
+
* Swapping Carta for a bare CodeMirror editor stays a one-file change.
|
|
16
|
+
*/
|
|
17
|
+
declare const MarkdownEditor: import("svelte").Component<Props, {}, "value">;
|
|
18
|
+
type MarkdownEditor = ReturnType<typeof MarkdownEditor>;
|
|
19
|
+
export default MarkdownEditor;
|
|
20
|
+
//# sourceMappingURL=MarkdownEditor.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownEditor.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/MarkdownEditor.svelte.ts"],"names":[],"mappings":"AAME,UAAU,KAAK;IACb,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,oFAAoF;IACpF,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAC;CAC3D;AAuEH;;;;;GAKG;AACH,QAAA,MAAM,cAAc,gDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -1,18 +1,30 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
The navigation tree editor. It edits a flat working copy of the menu (each row carries an
|
|
4
|
+
explicit depth) and posts the whole tree as JSON to the save action. Vertical order comes from
|
|
5
|
+
svelte-sortable-list (mouse, and keyboard with Space to lift, arrows to move, Space to drop);
|
|
6
|
+
depth comes from the Indent and Outdent buttons, capped at the menu's maxDepth. The engine
|
|
7
|
+
validates on save.
|
|
8
|
+
-->
|
|
1
9
|
<script lang="ts">
|
|
2
|
-
// The navigation tree editor (Pass L). Edits a local copy of the menu tree and posts the whole
|
|
3
|
-
// tree as JSON to the `save` action. DaisyUI primitives under the Warm Stone admin theme. Drag a
|
|
4
|
-
// row up or down to reorder within its level; use Indent/Outdent to nest under the previous
|
|
5
|
-
// sibling or promote a level (capped at the menu's maxDepth). The engine validates on save.
|
|
6
10
|
import { untrack } from 'svelte';
|
|
7
|
-
import
|
|
8
|
-
import type {
|
|
11
|
+
import { SortableList, sortItems } from '@rodrigodagostino/svelte-sortable-list';
|
|
12
|
+
import type { SortableList as SortableListNS } from '@rodrigodagostino/svelte-sortable-list';
|
|
13
|
+
import '@rodrigodagostino/svelte-sortable-list/styles.css';
|
|
14
|
+
import type { NavLoadData } from '../sveltekit/nav-routes.js';
|
|
15
|
+
import type { NavNode } from '../nav/site-config.js';
|
|
9
16
|
|
|
10
|
-
|
|
17
|
+
interface Props {
|
|
18
|
+
/** The nav load's data: the menu meta, the current tree, page options, and flags. */
|
|
19
|
+
data: NavLoadData;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let { data }: Props = $props();
|
|
11
23
|
|
|
12
|
-
// A flat, ordered working model is
|
|
13
|
-
//
|
|
24
|
+
// A flat, ordered working model is simpler to reorder than a recursive one: each row carries an
|
|
25
|
+
// explicit depth, and the nested tree is rebuilt from order plus depth only at submit time.
|
|
14
26
|
interface Row {
|
|
15
|
-
id:
|
|
27
|
+
id: string;
|
|
16
28
|
depth: number;
|
|
17
29
|
label: string;
|
|
18
30
|
url: string;
|
|
@@ -21,14 +33,19 @@
|
|
|
21
33
|
let nextId = 1;
|
|
22
34
|
function flatten(nodes: NavNode[], depth: number, out: Row[]): Row[] {
|
|
23
35
|
for (const n of nodes) {
|
|
24
|
-
out.push({ id: nextId
|
|
36
|
+
out.push({ id: `row-${nextId++}`, depth, label: n.label, url: n.url ?? '' });
|
|
25
37
|
if (n.children?.length) flatten(n.children, depth + 1, out);
|
|
26
38
|
}
|
|
27
39
|
return out;
|
|
28
40
|
}
|
|
29
41
|
|
|
42
|
+
// untrack here is not for runtime behavior -- $state runs its initializer once regardless.
|
|
43
|
+
// It suppresses the Svelte compiler warning that `data` (a prop) is referenced outside a
|
|
44
|
+
// reactive context. The component is always remounted on save/error (both redirect), so
|
|
45
|
+
// a one-time snapshot of the initial tree is correct.
|
|
30
46
|
let rows = $state<Row[]>(untrack(() => flatten(data.tree, 0, [])));
|
|
31
|
-
|
|
47
|
+
// depth is 0-based internally; maxDepth in the config is 1-based (1 = flat, 2 = one nesting level)
|
|
48
|
+
const maxDepthIndex = $derived(data.menu.maxDepth - 1);
|
|
32
49
|
|
|
33
50
|
// Rebuild the nested tree from the flat rows by depth, then serialize for the hidden field.
|
|
34
51
|
function toTree(list: Row[]): NavNode[] {
|
|
@@ -48,9 +65,9 @@
|
|
|
48
65
|
const treeJson = $derived(JSON.stringify(toTree(rows)));
|
|
49
66
|
|
|
50
67
|
function addRow() {
|
|
51
|
-
rows = [...rows, { id: nextId
|
|
68
|
+
rows = [...rows, { id: `row-${nextId++}`, depth: 0, label: 'New item', url: '' }];
|
|
52
69
|
}
|
|
53
|
-
function removeRow(id:
|
|
70
|
+
function removeRow(id: string) {
|
|
54
71
|
rows = rows.filter((r) => r.id !== id);
|
|
55
72
|
}
|
|
56
73
|
function indent(i: number) {
|
|
@@ -63,66 +80,59 @@
|
|
|
63
80
|
if (rows[i].depth > 0) rows[i].depth -= 1;
|
|
64
81
|
}
|
|
65
82
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
next.splice(to, 0, moved);
|
|
72
|
-
rows = next;
|
|
73
|
-
dragFrom = null;
|
|
83
|
+
function handleDragEnd(e: SortableListNS.RootEvents['ondragend']) {
|
|
84
|
+
const { draggedItemIndex, targetItemIndex, isCanceled } = e;
|
|
85
|
+
if (!isCanceled && typeof targetItemIndex === 'number' && draggedItemIndex !== targetItemIndex) {
|
|
86
|
+
rows = sortItems(rows, draggedItemIndex, targetItemIndex);
|
|
87
|
+
}
|
|
74
88
|
}
|
|
75
89
|
</script>
|
|
76
90
|
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
<h1 class="mb-4 text-xl font-semibold">{data.menu.label}</h1>
|
|
92
|
+
|
|
93
|
+
{#if data.saved}
|
|
94
|
+
<div role="status" class="alert alert-success mb-4 text-sm">Navigation saved.</div>
|
|
95
|
+
{/if}
|
|
96
|
+
{#if data.error}
|
|
97
|
+
<div role="alert" class="alert alert-error mb-4 text-sm">{data.error}</div>
|
|
98
|
+
{/if}
|
|
99
|
+
|
|
100
|
+
<form method="POST" action="?/save">
|
|
101
|
+
<input type="hidden" name="tree" value={treeJson} />
|
|
102
|
+
|
|
103
|
+
<div class="mb-2">
|
|
80
104
|
<button type="button" class="btn btn-sm" onclick={addRow}>Add item</button>
|
|
81
105
|
</div>
|
|
82
106
|
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<form method="POST" action="?/save" class="mt-4">
|
|
91
|
-
<input type="hidden" name="tree" value={treeJson} />
|
|
92
|
-
<ul class="menu w-full gap-1">
|
|
93
|
-
{#each rows as row, i (row.id)}
|
|
94
|
-
<li
|
|
95
|
-
draggable="true"
|
|
96
|
-
ondragstart={() => (dragFrom = i)}
|
|
97
|
-
ondragover={(e) => e.preventDefault()}
|
|
98
|
-
ondrop={() => onDrop(i)}
|
|
99
|
-
style={`margin-left:${row.depth * 1.5}rem`}
|
|
100
|
-
>
|
|
101
|
-
<div class="flex items-center gap-2 p-2">
|
|
102
|
-
<span class="cursor-grab opacity-40" aria-hidden="true">⠿</span>
|
|
103
|
-
<input class="input input-sm input-bordered flex-1" placeholder="Label" bind:value={row.label} />
|
|
107
|
+
<div class="sortable-list-area" style="min-height:2.5rem">
|
|
108
|
+
<SortableList.Root ondragend={handleDragEnd} aria-label="Navigation items">
|
|
109
|
+
{#each rows as row, index (row.id)}
|
|
110
|
+
<SortableList.Item id={row.id} {index} aria-label={`${row.label || 'Untitled'}, level ${row.depth + 1}`}>
|
|
111
|
+
<div class="flex items-center gap-2 p-2" style={`margin-left:${row.depth * 1.5}rem`}>
|
|
112
|
+
<input class="input input-sm flex-1" placeholder="Label" aria-label="Label" bind:value={row.label} />
|
|
104
113
|
<input
|
|
105
|
-
class="input input-sm
|
|
106
|
-
placeholder="/path or https
|
|
114
|
+
class="input input-sm flex-1"
|
|
115
|
+
placeholder="/path or https://example.com"
|
|
107
116
|
list="cairn-nav-pages"
|
|
117
|
+
aria-label="URL"
|
|
108
118
|
bind:value={row.url}
|
|
109
119
|
/>
|
|
110
|
-
<button type="button" class="btn btn-xs btn-ghost" onclick={() => outdent(
|
|
111
|
-
<button type="button" class="btn btn-xs btn-ghost" onclick={() => indent(
|
|
112
|
-
<button type="button" class="btn btn-xs btn-ghost text-error" onclick={() => removeRow(row.id)} aria-label=
|
|
120
|
+
<button type="button" class="btn btn-xs btn-ghost" onclick={() => outdent(index)} aria-label="Outdent">←</button>
|
|
121
|
+
<button type="button" class="btn btn-xs btn-ghost" onclick={() => indent(index)} aria-label="Indent">→</button>
|
|
122
|
+
<button type="button" class="btn btn-xs btn-ghost text-error" onclick={() => removeRow(row.id)} aria-label={`Remove ${row.label}`}>×</button>
|
|
113
123
|
</div>
|
|
114
|
-
</
|
|
124
|
+
</SortableList.Item>
|
|
115
125
|
{/each}
|
|
116
|
-
</
|
|
126
|
+
</SortableList.Root>
|
|
127
|
+
</div>
|
|
117
128
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
129
|
+
<datalist id="cairn-nav-pages">
|
|
130
|
+
{#each data.pages as p (p.url)}
|
|
131
|
+
<option value={p.url}>{p.label}</option>
|
|
132
|
+
{/each}
|
|
133
|
+
</datalist>
|
|
123
134
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
</div>
|
|
135
|
+
<div class="mt-4">
|
|
136
|
+
<button type="submit" class="btn btn-primary btn-sm">Save navigation</button>
|
|
137
|
+
</div>
|
|
138
|
+
</form>
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
type
|
|
1
|
+
import '@rodrigodagostino/svelte-sortable-list/styles.css';
|
|
2
|
+
import type { NavLoadData } from '../sveltekit/nav-routes.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** The nav load's data: the menu meta, the current tree, page options, and flags. */
|
|
3
5
|
data: NavLoadData;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The navigation tree editor. It edits a flat working copy of the menu (each row carries an
|
|
9
|
+
* explicit depth) and posts the whole tree as JSON to the save action. Vertical order comes from
|
|
10
|
+
* svelte-sortable-list (mouse, and keyboard with Space to lift, arrows to move, Space to drop);
|
|
11
|
+
* depth comes from the Indent and Outdent buttons, capped at the menu's maxDepth. The engine
|
|
12
|
+
* validates on save.
|
|
13
|
+
*/
|
|
14
|
+
declare const NavTree: import("svelte").Component<Props, {}, "">;
|
|
6
15
|
type NavTree = ReturnType<typeof NavTree>;
|
|
7
16
|
export default NavTree;
|
|
8
17
|
//# sourceMappingURL=NavTree.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NavTree.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/NavTree.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"NavTree.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/NavTree.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,mDAAmD,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAI5D,UAAU,KAAK;IACb,qFAAqF;IACrF,IAAI,EAAE,WAAW,CAAC;CACnB;AA8HH;;;;;;GAMG;AACH,QAAA,MAAM,OAAO,2CAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* Warm Stone: the cairn admin theme. Self-contained, since DaisyUI v5 reads these vars at point
|
|
2
|
+
of use, so this fully overrides the host's theme with no @plugin and no host build step. */
|
|
3
|
+
[data-theme='cairn-admin'] {
|
|
4
|
+
color-scheme: light;
|
|
5
|
+
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
6
|
+
|
|
7
|
+
--color-base-100: oklch(98.5% 0.004 75);
|
|
8
|
+
--color-base-200: oklch(96% 0.005 75);
|
|
9
|
+
--color-base-300: oklch(92% 0.008 75);
|
|
10
|
+
--color-base-content: oklch(28% 0.012 75);
|
|
11
|
+
|
|
12
|
+
--color-primary: oklch(52% 0.2 293);
|
|
13
|
+
--color-primary-content: oklch(98% 0.012 293);
|
|
14
|
+
--color-secondary: oklch(45% 0.02 75);
|
|
15
|
+
--color-secondary-content: oklch(98% 0.004 75);
|
|
16
|
+
--color-accent: oklch(58% 0.16 300);
|
|
17
|
+
--color-accent-content: oklch(98% 0.012 300);
|
|
18
|
+
--color-neutral: oklch(32% 0.012 75);
|
|
19
|
+
--color-neutral-content: oklch(96% 0.004 75);
|
|
20
|
+
|
|
21
|
+
--color-info: oklch(60% 0.12 240);
|
|
22
|
+
--color-info-content: oklch(98% 0.012 240);
|
|
23
|
+
--color-success: oklch(58% 0.12 150);
|
|
24
|
+
--color-success-content: oklch(98% 0.012 150);
|
|
25
|
+
--color-warning: oklch(75% 0.15 70);
|
|
26
|
+
--color-warning-content: oklch(26% 0.05 70);
|
|
27
|
+
--color-error: oklch(58% 0.2 25);
|
|
28
|
+
--color-error-content: oklch(98% 0.012 25);
|
|
29
|
+
|
|
30
|
+
/* Accessible muted text tones: >= 4.5:1 contrast on base-100/base-200. */
|
|
31
|
+
--color-muted: oklch(48% 0.01 75);
|
|
32
|
+
--color-subtle: oklch(42% 0.01 75);
|
|
33
|
+
|
|
34
|
+
--radius-selector: 0.5rem;
|
|
35
|
+
--radius-field: 0.5rem;
|
|
36
|
+
--radius-box: 0.75rem;
|
|
37
|
+
--size-selector: 0.25rem;
|
|
38
|
+
--size-field: 0.25rem;
|
|
39
|
+
--border: 1px;
|
|
40
|
+
--depth: 1;
|
|
41
|
+
--noise: 0;
|
|
42
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { default as AdminLayout } from './AdminLayout.svelte';
|
|
2
|
-
export { default as CollectionList } from './CollectionList.svelte';
|
|
3
2
|
export { default as LoginPage } from './LoginPage.svelte';
|
|
4
3
|
export { default as ConfirmPage } from './ConfirmPage.svelte';
|
|
4
|
+
export { default as ConceptList } from './ConceptList.svelte';
|
|
5
5
|
export { default as EditPage } from './EditPage.svelte';
|
|
6
|
-
export { default as
|
|
6
|
+
export { default as ManageEditors } from './ManageEditors.svelte';
|
|
7
|
+
export { default as MarkdownEditor } from './MarkdownEditor.svelte';
|
|
7
8
|
export { default as ComponentPalette } from './ComponentPalette.svelte';
|
|
8
9
|
export { default as NavTree } from './NavTree.svelte';
|
|
9
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/components/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/components/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
|