@kidecms/core 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.
- package/README.md +28 -0
- package/admin/components/AdminCard.astro +25 -0
- package/admin/components/AiGenerateButton.tsx +102 -0
- package/admin/components/AssetsGrid.tsx +711 -0
- package/admin/components/BlockEditor.tsx +996 -0
- package/admin/components/CheckboxField.tsx +31 -0
- package/admin/components/DocumentActions.tsx +317 -0
- package/admin/components/DocumentLock.tsx +54 -0
- package/admin/components/DocumentsDataTable.tsx +804 -0
- package/admin/components/FieldControl.astro +397 -0
- package/admin/components/FocalPointSelector.tsx +100 -0
- package/admin/components/ImageBrowseDialog.tsx +176 -0
- package/admin/components/ImagePicker.tsx +149 -0
- package/admin/components/InternalLinkPicker.tsx +80 -0
- package/admin/components/LiveHeading.tsx +17 -0
- package/admin/components/MobileSidebar.tsx +29 -0
- package/admin/components/RelationField.tsx +204 -0
- package/admin/components/RichTextEditor.tsx +685 -0
- package/admin/components/SelectField.tsx +65 -0
- package/admin/components/SidebarUserMenu.tsx +99 -0
- package/admin/components/SlugField.tsx +77 -0
- package/admin/components/TaxonomySelect.tsx +52 -0
- package/admin/components/Toast.astro +40 -0
- package/admin/components/TreeItemsEditor.tsx +790 -0
- package/admin/components/TreeSelect.tsx +166 -0
- package/admin/components/UnsavedGuard.tsx +181 -0
- package/admin/components/tree-utils.ts +86 -0
- package/admin/components/ui/alert-dialog.tsx +92 -0
- package/admin/components/ui/badge.tsx +83 -0
- package/admin/components/ui/button.tsx +53 -0
- package/admin/components/ui/card.tsx +70 -0
- package/admin/components/ui/checkbox.tsx +28 -0
- package/admin/components/ui/collapsible.tsx +26 -0
- package/admin/components/ui/command.tsx +88 -0
- package/admin/components/ui/dialog.tsx +92 -0
- package/admin/components/ui/dropdown-menu.tsx +259 -0
- package/admin/components/ui/input.tsx +20 -0
- package/admin/components/ui/label.tsx +20 -0
- package/admin/components/ui/popover.tsx +42 -0
- package/admin/components/ui/select.tsx +165 -0
- package/admin/components/ui/separator.tsx +21 -0
- package/admin/components/ui/sheet.tsx +104 -0
- package/admin/components/ui/skeleton.tsx +7 -0
- package/admin/components/ui/table.tsx +74 -0
- package/admin/components/ui/textarea.tsx +18 -0
- package/admin/components/ui/tooltip.tsx +52 -0
- package/admin/layouts/AdminLayout.astro +340 -0
- package/admin/lib/utils.ts +19 -0
- package/dist/admin.js +92 -0
- package/dist/ai.js +67 -0
- package/dist/api.js +827 -0
- package/dist/assets.js +163 -0
- package/dist/auth.js +132 -0
- package/dist/blocks.js +110 -0
- package/dist/content.js +29 -0
- package/dist/create-admin.js +23 -0
- package/dist/define.js +36 -0
- package/dist/generator.js +370 -0
- package/dist/image.js +69 -0
- package/dist/index.js +16 -0
- package/dist/integration.js +256 -0
- package/dist/locks.js +37 -0
- package/dist/richtext.js +1 -0
- package/dist/runtime.js +26 -0
- package/dist/schema.js +13 -0
- package/dist/seed.js +84 -0
- package/dist/values.js +102 -0
- package/middleware/auth.ts +100 -0
- package/package.json +102 -0
- package/routes/api/cms/[collection]/[...path].ts +366 -0
- package/routes/api/cms/ai/alt-text.ts +25 -0
- package/routes/api/cms/ai/seo.ts +25 -0
- package/routes/api/cms/ai/translate.ts +31 -0
- package/routes/api/cms/assets/[id].ts +82 -0
- package/routes/api/cms/assets/folders.ts +81 -0
- package/routes/api/cms/assets/index.ts +23 -0
- package/routes/api/cms/assets/upload.ts +112 -0
- package/routes/api/cms/auth/invite.ts +166 -0
- package/routes/api/cms/auth/login.ts +124 -0
- package/routes/api/cms/auth/logout.ts +33 -0
- package/routes/api/cms/auth/setup.ts +77 -0
- package/routes/api/cms/cron/publish.ts +33 -0
- package/routes/api/cms/img/[...path].ts +24 -0
- package/routes/api/cms/locks/[...path].ts +37 -0
- package/routes/api/cms/preview/render.ts +36 -0
- package/routes/api/cms/references/[collection]/[id].ts +60 -0
- package/routes/pages/admin/[...path].astro +1104 -0
- package/routes/pages/admin/assets/[id].astro +183 -0
- package/routes/pages/admin/assets/index.astro +58 -0
- package/routes/pages/admin/invite.astro +116 -0
- package/routes/pages/admin/login.astro +57 -0
- package/routes/pages/admin/setup.astro +91 -0
- package/virtual.d.ts +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# `@kidecms/core`
|
|
2
|
+
|
|
3
|
+
Kide's runtime and admin package.
|
|
4
|
+
|
|
5
|
+
## Install shape
|
|
6
|
+
|
|
7
|
+
The goal is to keep onboarding simple:
|
|
8
|
+
|
|
9
|
+
- `@kidecms/core` brings its own CMS runtime, generator, and admin UI dependencies.
|
|
10
|
+
- The host app provides `react` and `react-dom`.
|
|
11
|
+
- Some features are optional:
|
|
12
|
+
- `@ai-sdk/openai` only when AI generation is enabled
|
|
13
|
+
- `sharp` only when local image transforms are enabled
|
|
14
|
+
|
|
15
|
+
## Why some packages still exist in the app
|
|
16
|
+
|
|
17
|
+
Kide keeps project-specific code inside the app:
|
|
18
|
+
|
|
19
|
+
- database adapters
|
|
20
|
+
- storage adapters
|
|
21
|
+
- email adapters
|
|
22
|
+
- generated schema files
|
|
23
|
+
- framework route glue
|
|
24
|
+
|
|
25
|
+
Because those files live in the app, the app may still depend on packages like
|
|
26
|
+
`drizzle-orm`, `zod`, or `nanoid` when it imports them directly.
|
|
27
|
+
|
|
28
|
+
That is separate from `@kidecms/core`'s own package contract.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./ui/card";
|
|
3
|
+
|
|
4
|
+
const {
|
|
5
|
+
title,
|
|
6
|
+
description,
|
|
7
|
+
compact = false,
|
|
8
|
+
class: className = "",
|
|
9
|
+
} = Astro.props as {
|
|
10
|
+
title: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
compact?: boolean;
|
|
13
|
+
class?: string;
|
|
14
|
+
};
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
<Card className={className}>
|
|
18
|
+
<CardHeader className={compact ? "px-3 py-3" : "border-b"}>
|
|
19
|
+
<CardTitle className={compact ? "text-sm" : undefined}>{title}</CardTitle>
|
|
20
|
+
{description && <CardDescription>{description}</CardDescription>}
|
|
21
|
+
</CardHeader>
|
|
22
|
+
<CardContent className={compact ? "px-3 pb-3" : undefined}>
|
|
23
|
+
<slot />
|
|
24
|
+
</CardContent>
|
|
25
|
+
</Card>
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Sparkles, Loader2 } from "lucide-react";
|
|
3
|
+
import { Button } from "./ui/button";
|
|
4
|
+
|
|
5
|
+
interface AiGenerateButtonProps {
|
|
6
|
+
endpoint: string;
|
|
7
|
+
payload: Record<string, unknown>;
|
|
8
|
+
targetField: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function setFieldValue(name: string, value: string) {
|
|
13
|
+
const field = document.querySelector<HTMLInputElement | HTMLTextAreaElement>(`[name="${name}"]`);
|
|
14
|
+
if (!field) return;
|
|
15
|
+
|
|
16
|
+
// Rich text fields use a custom event to update the Tiptap editor
|
|
17
|
+
if (field.type === "hidden") {
|
|
18
|
+
field.dispatchEvent(new CustomEvent("cms:set-value", { detail: value }));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const nativeSetter = Object.getOwnPropertyDescriptor(
|
|
23
|
+
field instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : HTMLInputElement.prototype,
|
|
24
|
+
"value",
|
|
25
|
+
)?.set;
|
|
26
|
+
|
|
27
|
+
if (nativeSetter) {
|
|
28
|
+
nativeSetter.call(field, value);
|
|
29
|
+
} else {
|
|
30
|
+
field.value = value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
field.dispatchEvent(new Event("input", { bubbles: true }));
|
|
34
|
+
field.dispatchEvent(new Event("change", { bubbles: true }));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default function AiGenerateButton({
|
|
38
|
+
endpoint,
|
|
39
|
+
payload,
|
|
40
|
+
targetField,
|
|
41
|
+
label = "Generate with AI",
|
|
42
|
+
}: AiGenerateButtonProps) {
|
|
43
|
+
const [loading, setLoading] = useState(false);
|
|
44
|
+
const [error, setError] = useState<string | null>(null);
|
|
45
|
+
|
|
46
|
+
const handleGenerate = async () => {
|
|
47
|
+
setLoading(true);
|
|
48
|
+
setError(null);
|
|
49
|
+
try {
|
|
50
|
+
const livePayload = { ...payload };
|
|
51
|
+
for (const key of Object.keys(livePayload)) {
|
|
52
|
+
const el = document.querySelector<HTMLInputElement | HTMLTextAreaElement>(`[name="${key}"]`);
|
|
53
|
+
if (el) livePayload[key] = el.value;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const response = await fetch(endpoint, {
|
|
57
|
+
method: "POST",
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify(livePayload),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
const err = await response.json().catch(() => ({ error: "Generation failed" }));
|
|
64
|
+
throw new Error(err.error || "Generation failed");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const reader = response.body?.getReader();
|
|
68
|
+
if (!reader) throw new Error("No response stream");
|
|
69
|
+
|
|
70
|
+
const decoder = new TextDecoder();
|
|
71
|
+
let accumulated = "";
|
|
72
|
+
|
|
73
|
+
while (true) {
|
|
74
|
+
const { done, value } = await reader.read();
|
|
75
|
+
if (done) break;
|
|
76
|
+
accumulated += decoder.decode(value, { stream: true });
|
|
77
|
+
setFieldValue(targetField, accumulated);
|
|
78
|
+
}
|
|
79
|
+
} catch (e) {
|
|
80
|
+
setError(e instanceof Error ? e.message : "Generation failed");
|
|
81
|
+
} finally {
|
|
82
|
+
setLoading(false);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div>
|
|
88
|
+
<Button
|
|
89
|
+
type="button"
|
|
90
|
+
variant="outline"
|
|
91
|
+
size="sm"
|
|
92
|
+
onClick={handleGenerate}
|
|
93
|
+
disabled={loading}
|
|
94
|
+
className="text-foreground/70"
|
|
95
|
+
>
|
|
96
|
+
{loading ? <Loader2 className="size-3 animate-spin" /> : <Sparkles className="size-4 stroke-1" />}
|
|
97
|
+
{label}
|
|
98
|
+
</Button>
|
|
99
|
+
{error && <p className="text-destructive mt-1 text-xs">{error}</p>}
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|