create-kide-app 0.0.36 → 0.1.2
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 +12 -11
- package/index.js +95 -420
- package/package.json +2 -3
- package/templates/base/.env.example +0 -2
- package/templates/base/CLAUDE.md +0 -73
- package/templates/base/gitignore +0 -8
- package/templates/base/package.json +0 -39
- package/templates/base/src/cms/adapters/db.ts +0 -49
- package/templates/base/src/cms/adapters/email.ts +0 -34
- package/templates/base/src/cms/adapters/storage.ts +0 -38
- package/templates/base/src/cms/cms.config.ts +0 -7
- package/templates/base/src/cms/collections/users.ts +0 -20
- package/templates/base/src/cms/internals/create-admin.ts +0 -40
- package/templates/base/src/cms/internals/generator.ts +0 -10
- package/templates/base/src/cms/internals/runtime.ts +0 -76
- package/templates/base/src/components/BlockRenderer.astro +0 -28
- package/templates/base/src/env.d.ts +0 -12
- package/templates/base/src/pages/index.astro +0 -11
- package/templates/base/src/styles/admin.css +0 -253
- package/templates/base/src/styles/public.css +0 -2
- package/templates/base/tsconfig.json +0 -11
- package/templates/cloudflare/astro.config.mjs +0 -16
- package/templates/cloudflare/db.ts +0 -23
- package/templates/cloudflare/drizzle.config.ts +0 -24
- package/templates/cloudflare/storage.ts +0 -25
- package/templates/cloudflare/uploads-route.ts +0 -36
- package/templates/cloudflare/wrangler.toml +0 -17
- package/templates/demo/src/cms/cms.config.ts +0 -17
- package/templates/demo/src/cms/collections/authors.ts +0 -20
- package/templates/demo/src/cms/collections/front-page.ts +0 -37
- package/templates/demo/src/cms/collections/menus.ts +0 -18
- package/templates/demo/src/cms/collections/pages.ts +0 -59
- package/templates/demo/src/cms/collections/posts.ts +0 -55
- package/templates/demo/src/cms/collections/taxonomies.ts +0 -18
- package/templates/demo/src/cms/collections/users.ts +0 -20
- package/templates/demo/src/cms/internals/seed.data.ts +0 -506
- package/templates/demo/src/cms/internals/seed.ts +0 -7
- package/templates/demo/src/components/BlockRenderer.astro +0 -32
- package/templates/demo/src/components/RichTextContent.astro +0 -18
- package/templates/demo/src/components/blocks/Faq.astro +0 -22
- package/templates/demo/src/components/blocks/Hero.astro +0 -19
- package/templates/demo/src/components/blocks/Image.astro +0 -25
- package/templates/demo/src/components/blocks/Text.astro +0 -16
- package/templates/demo/src/layouts/PublicLayout.astro +0 -53
- package/templates/demo/src/pages/[...slug].astro +0 -31
- package/templates/demo/src/pages/blog/[slug].astro +0 -41
- package/templates/demo/src/pages/index.astro +0 -51
- package/templates/local/astro.config.mjs +0 -23
- package/templates/local/db.ts +0 -48
- package/templates/local/drizzle.config.ts +0 -15
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import "@/styles/public.css";
|
|
3
|
-
import { cms } from "@/cms/.generated/api";
|
|
4
|
-
|
|
5
|
-
const { title = "Kide CMS", description = "A code-first CMS built inside Astro." } = Astro.props;
|
|
6
|
-
type MenuItem = { id: string; label?: string; href?: string; target?: string; children: MenuItem[] };
|
|
7
|
-
|
|
8
|
-
const menu = await cms.menus.findOne({ slug: "main" });
|
|
9
|
-
const menuItems: MenuItem[] = menu?.items ? (Array.isArray(menu.items) ? menu.items : []) : [];
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<!doctype html>
|
|
13
|
-
<html lang="en">
|
|
14
|
-
<head>
|
|
15
|
-
<meta charset="utf-8" />
|
|
16
|
-
<meta name="viewport" content="width=device-width" />
|
|
17
|
-
<meta name="description" content={description} />
|
|
18
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
19
|
-
<link rel="icon" href="/favicon.ico" />
|
|
20
|
-
<title>{title}</title>
|
|
21
|
-
</head>
|
|
22
|
-
<body class="min-h-screen bg-white pb-24 text-gray-900 antialiased">
|
|
23
|
-
<header class="mx-auto flex max-w-4xl items-center gap-8 px-4 py-4">
|
|
24
|
-
<a href="/" class="text-lg font-semibold no-underline">Demo website</a>
|
|
25
|
-
{
|
|
26
|
-
menuItems.length > 0 && (
|
|
27
|
-
<nav>
|
|
28
|
-
<ul class="flex list-none gap-6 p-0">
|
|
29
|
-
{menuItems.map((item) => (
|
|
30
|
-
<li>
|
|
31
|
-
<a
|
|
32
|
-
href={String(item.href ?? "#")}
|
|
33
|
-
target={item.target || undefined}
|
|
34
|
-
class="text-sm text-gray-500 no-underline transition-colors hover:text-gray-900"
|
|
35
|
-
>
|
|
36
|
-
{String(item.label ?? "")}
|
|
37
|
-
</a>
|
|
38
|
-
</li>
|
|
39
|
-
))}
|
|
40
|
-
</ul>
|
|
41
|
-
</nav>
|
|
42
|
-
)
|
|
43
|
-
}
|
|
44
|
-
<a
|
|
45
|
-
href="/admin"
|
|
46
|
-
class="ml-auto rounded-md border border-teal-700 px-3 py-1.5 text-sm font-medium text-teal-700 no-underline transition-colors hover:bg-teal-50"
|
|
47
|
-
>
|
|
48
|
-
Open admin
|
|
49
|
-
</a>
|
|
50
|
-
</header>
|
|
51
|
-
<slot />
|
|
52
|
-
</body>
|
|
53
|
-
</html>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import PublicLayout from "@/layouts/PublicLayout.astro";
|
|
3
|
-
import BlockRenderer from "@/components/BlockRenderer.astro";
|
|
4
|
-
import { cms } from "@/cms/.generated/api";
|
|
5
|
-
import { cacheTags, parseBlocks } from "@kidecms/core";
|
|
6
|
-
|
|
7
|
-
const isPreview = Astro.url.searchParams.has("preview");
|
|
8
|
-
const doc = await cms.pages.findOne({ slug: Astro.params.slug!, status: isPreview ? "any" : "published" });
|
|
9
|
-
if (!doc) return Astro.redirect("/");
|
|
10
|
-
|
|
11
|
-
if (!isPreview) Astro.cache.set({ tags: cacheTags("pages", doc._id) });
|
|
12
|
-
|
|
13
|
-
const blocks = parseBlocks(doc.blocks);
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
<PublicLayout title={doc.title}>
|
|
17
|
-
<article class="mx-auto max-w-2xl px-4 py-8">
|
|
18
|
-
<a href="/" class="text-sm text-teal-700">← Back</a>
|
|
19
|
-
<h1 data-cms="title" class="mt-4 mb-2 text-2xl font-semibold">{doc.title}</h1>
|
|
20
|
-
{
|
|
21
|
-
doc.summary && (
|
|
22
|
-
<p data-cms="summary" class="mb-6 text-gray-500">
|
|
23
|
-
{doc.summary}
|
|
24
|
-
</p>
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
<div data-cms="blocks">
|
|
28
|
-
<BlockRenderer blocks={blocks} />
|
|
29
|
-
</div>
|
|
30
|
-
</article>
|
|
31
|
-
</PublicLayout>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import PublicLayout from "@/layouts/PublicLayout.astro";
|
|
3
|
-
import RichTextContent from "@/components/RichTextContent.astro";
|
|
4
|
-
import { cms } from "@/cms/.generated/api";
|
|
5
|
-
import { cacheTags, cmsImage, cmsSrcset } from "@kidecms/core";
|
|
6
|
-
|
|
7
|
-
const isPreview = Astro.url.searchParams.has("preview");
|
|
8
|
-
const doc = await cms.posts.findOne({ slug: Astro.params.slug!, status: isPreview ? "any" : "published" });
|
|
9
|
-
if (!doc) return Astro.redirect("/");
|
|
10
|
-
|
|
11
|
-
if (!isPreview) Astro.cache.set({ tags: cacheTags("posts", doc._id) });
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
<PublicLayout title={doc.title}>
|
|
15
|
-
<article class="mx-auto max-w-2xl px-4 py-8">
|
|
16
|
-
<a href="/" class="text-sm text-teal-700">← Back</a>
|
|
17
|
-
<h1 data-cms="title" class="mt-4 mb-2 text-2xl font-semibold">{doc.title}</h1>
|
|
18
|
-
{
|
|
19
|
-
doc.image && (
|
|
20
|
-
<img
|
|
21
|
-
src={cmsImage(doc.image, 1024)}
|
|
22
|
-
srcset={cmsSrcset(doc.image)}
|
|
23
|
-
sizes="(max-width: 640px) 100vw, 640px"
|
|
24
|
-
alt={doc.title}
|
|
25
|
-
loading="eager"
|
|
26
|
-
class="mb-6 h-auto w-full rounded-lg"
|
|
27
|
-
/>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
{
|
|
31
|
-
doc.excerpt && (
|
|
32
|
-
<p data-cms="excerpt" class="mb-6 text-gray-500">
|
|
33
|
-
{doc.excerpt}
|
|
34
|
-
</p>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
<div data-cms="body" class="prose">
|
|
38
|
-
<RichTextContent content={doc.body} />
|
|
39
|
-
</div>
|
|
40
|
-
</article>
|
|
41
|
-
</PublicLayout>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import PublicLayout from "@/layouts/PublicLayout.astro";
|
|
3
|
-
import BlockRenderer from "@/components/BlockRenderer.astro";
|
|
4
|
-
import type { PostsDocument } from "@/cms/.generated/types";
|
|
5
|
-
import { cms } from "@/cms/.generated/api";
|
|
6
|
-
import { parseBlocks } from "@kidecms/core";
|
|
7
|
-
|
|
8
|
-
const isPreview = Astro.url.searchParams.has("preview");
|
|
9
|
-
const page = await cms["front-page"].findOne({ status: isPreview ? "any" : "published" });
|
|
10
|
-
const blocks = parseBlocks(page?.blocks);
|
|
11
|
-
|
|
12
|
-
// Resolve hero ctaHref relation (page ID → slug URL)
|
|
13
|
-
for (const block of blocks) {
|
|
14
|
-
if (block.type === "hero" && block.ctaHref) {
|
|
15
|
-
const linked = await cms.pages.findOne({ where: { _id: String(block.ctaHref) } });
|
|
16
|
-
if (linked) block.ctaHref = `/${linked.slug}`;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const posts = await cms.posts.find({
|
|
21
|
-
status: "published",
|
|
22
|
-
sort: { field: "sortOrder", direction: "desc" },
|
|
23
|
-
limit: 10,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
if (!isPreview) Astro.cache.set({ tags: ["front-page", "posts", "home"] });
|
|
27
|
-
---
|
|
28
|
-
|
|
29
|
-
<PublicLayout title="Kide CMS">
|
|
30
|
-
<div class="mx-auto flex max-w-4xl gap-8 px-4 py-8">
|
|
31
|
-
<main class="min-w-0 flex-1">
|
|
32
|
-
{blocks.length > 0 ? <BlockRenderer blocks={blocks} /> : <p class="text-gray-500">No content yet.</p>}
|
|
33
|
-
</main>
|
|
34
|
-
|
|
35
|
-
<aside class="hidden w-64 shrink-0 lg:block">
|
|
36
|
-
<h2 class="mb-3 text-sm font-semibold text-gray-900">Recent posts</h2>
|
|
37
|
-
<ul class="space-y-2">
|
|
38
|
-
{
|
|
39
|
-
posts.map((post: PostsDocument) => (
|
|
40
|
-
<li>
|
|
41
|
-
<a href={`/blog/${post.slug}`} class="text-sm text-teal-700 hover:underline">
|
|
42
|
-
{post.title}
|
|
43
|
-
</a>
|
|
44
|
-
</li>
|
|
45
|
-
))
|
|
46
|
-
}
|
|
47
|
-
</ul>
|
|
48
|
-
{posts.length === 0 && <p class="text-sm text-gray-500">No published posts yet.</p>}
|
|
49
|
-
</aside>
|
|
50
|
-
</div>
|
|
51
|
-
</PublicLayout>
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
import node from "@astrojs/node";
|
|
3
|
-
import react from "@astrojs/react";
|
|
4
|
-
import tailwindcss from "@tailwindcss/vite";
|
|
5
|
-
import { defineConfig, memoryCache } from "astro/config";
|
|
6
|
-
import cmsIntegration from "@kidecms/core/integration";
|
|
7
|
-
|
|
8
|
-
// https://astro.build/config
|
|
9
|
-
export default defineConfig({
|
|
10
|
-
output: "server",
|
|
11
|
-
integrations: [react(), cmsIntegration()],
|
|
12
|
-
adapter: node({
|
|
13
|
-
mode: "standalone",
|
|
14
|
-
}),
|
|
15
|
-
vite: {
|
|
16
|
-
plugins: [tailwindcss()],
|
|
17
|
-
},
|
|
18
|
-
experimental: {
|
|
19
|
-
cache: {
|
|
20
|
-
provider: memoryCache(),
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
});
|
package/templates/local/db.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { createClient, type Client } from "@libsql/client";
|
|
4
|
-
import { drizzle } from "drizzle-orm/libsql";
|
|
5
|
-
import { migrate } from "drizzle-orm/libsql/migrator";
|
|
6
|
-
|
|
7
|
-
let dbInstance: ReturnType<typeof drizzle> | null = null;
|
|
8
|
-
let clientInstance: Client | null = null;
|
|
9
|
-
let migrated = false;
|
|
10
|
-
|
|
11
|
-
const getDbUrl = () => {
|
|
12
|
-
const url = process.env.CMS_DATABASE_URL;
|
|
13
|
-
if (url) return url;
|
|
14
|
-
const dbPath = path.join(process.cwd(), "data", "cms.db");
|
|
15
|
-
mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
16
|
-
return `file:${dbPath}`;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const getDb = async () => {
|
|
20
|
-
if (dbInstance) return dbInstance;
|
|
21
|
-
|
|
22
|
-
clientInstance = createClient({ url: getDbUrl() });
|
|
23
|
-
await clientInstance.execute("PRAGMA journal_mode = WAL");
|
|
24
|
-
await clientInstance.execute("PRAGMA foreign_keys = ON");
|
|
25
|
-
dbInstance = drizzle(clientInstance);
|
|
26
|
-
|
|
27
|
-
// Auto-run pending migrations on first connection (production only — dev uses drizzle-kit push)
|
|
28
|
-
if (!migrated) {
|
|
29
|
-
const migrationsFolder = path.join(process.cwd(), "src/cms/migrations");
|
|
30
|
-
try {
|
|
31
|
-
await migrate(dbInstance, { migrationsFolder });
|
|
32
|
-
} catch {
|
|
33
|
-
// Ignore migration errors — tables may already exist via drizzle-kit push in dev
|
|
34
|
-
}
|
|
35
|
-
migrated = true;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return dbInstance;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const closeDb = () => {
|
|
42
|
-
if (clientInstance) {
|
|
43
|
-
clientInstance.close();
|
|
44
|
-
clientInstance = null;
|
|
45
|
-
dbInstance = null;
|
|
46
|
-
migrated = false;
|
|
47
|
-
}
|
|
48
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { defineConfig } from "drizzle-kit";
|
|
4
|
-
|
|
5
|
-
const dbPath = path.resolve("./data/cms.db");
|
|
6
|
-
mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
7
|
-
|
|
8
|
-
export default defineConfig({
|
|
9
|
-
schema: "./src/cms/.generated/schema.ts",
|
|
10
|
-
out: "./src/cms/migrations",
|
|
11
|
-
dialect: "sqlite",
|
|
12
|
-
dbCredentials: {
|
|
13
|
-
url: process.env.CMS_DATABASE_URL ?? `file:${dbPath}`,
|
|
14
|
-
},
|
|
15
|
-
});
|