@acms-subir/core 0.0.1
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/cli.mjs +75 -0
- package/integration.mjs +286 -0
- package/package.json +89 -0
- package/src/actions/index.ts +502 -0
- package/src/components/DesignManager.tsx +542 -0
- package/src/components/LinksManager.tsx +694 -0
- package/src/components/Modal.astro +65 -0
- package/src/components/NavManager.tsx +168 -0
- package/src/components/WidgetRenderer.astro +84 -0
- package/src/components/builder/PageBuilder.tsx +575 -0
- package/src/components/editor/ImagePicker.tsx +215 -0
- package/src/components/editor/PostEditor.tsx +1011 -0
- package/src/components/editor/PreviewOverlay.tsx +77 -0
- package/src/components/editor/extensions/calendar.tsx +230 -0
- package/src/components/editor/extensions/cards.tsx +488 -0
- package/src/components/editor/extensions/codeBlock.tsx +70 -0
- package/src/components/editor/extensions/infoCards.tsx +270 -0
- package/src/components/editor/extensions/mediaCards.tsx +376 -0
- package/src/components/editor/extensions/postList.tsx +130 -0
- package/src/components/editor/extensions/slash.tsx +250 -0
- package/src/components/editor/extensions/tableTyping.ts +63 -0
- package/src/components/editor/imaging.ts +146 -0
- package/src/components/media/CropModal.tsx +229 -0
- package/src/components/media/MediaLibrary.tsx +295 -0
- package/src/layouts/Admin.astro +119 -0
- package/src/layouts/Site.astro +218 -0
- package/src/lib/auth.ts +94 -0
- package/src/lib/backup/unzip.ts +38 -0
- package/src/lib/backup/zip.ts +105 -0
- package/src/lib/blocksToHtml.ts +68 -0
- package/src/lib/brand.ts +26 -0
- package/src/lib/calendar/ics.ts +402 -0
- package/src/lib/calendar/render.ts +275 -0
- package/src/lib/calendar/src.ts +68 -0
- package/src/lib/content.ts +53 -0
- package/src/lib/dates.ts +34 -0
- package/src/lib/dynamicBlocks.ts +115 -0
- package/src/lib/env.ts +6 -0
- package/src/lib/highlightCode.ts +44 -0
- package/src/lib/i18n.ts +40 -0
- package/src/lib/markdown.ts +7 -0
- package/src/lib/media/store.ts +95 -0
- package/src/lib/net.ts +51 -0
- package/src/lib/preview.ts +28 -0
- package/src/lib/repo/d1.ts +44 -0
- package/src/lib/repo/index.ts +23 -0
- package/src/lib/repo/migrations.ts +231 -0
- package/src/lib/repo/search.ts +14 -0
- package/src/lib/repo/sql.ts +721 -0
- package/src/lib/repo/sqlite.ts +43 -0
- package/src/lib/repo/types.ts +132 -0
- package/src/lib/schema.ts +286 -0
- package/src/lib/seo.ts +37 -0
- package/src/lib/theme.ts +206 -0
- package/src/lib/widgets.ts +108 -0
- package/src/middleware.ts +109 -0
- package/src/pages/[...slug].astro +43 -0
- package/src/pages/admin/c/[collection]/[id].astro +56 -0
- package/src/pages/admin/c/[collection]/index.astro +163 -0
- package/src/pages/admin/design.astro +42 -0
- package/src/pages/admin/index.astro +145 -0
- package/src/pages/admin/links.astro +21 -0
- package/src/pages/admin/login.astro +83 -0
- package/src/pages/admin/logout.ts +7 -0
- package/src/pages/admin/media.astro +13 -0
- package/src/pages/admin/navigation.astro +17 -0
- package/src/pages/admin/pages/[id].astro +49 -0
- package/src/pages/admin/pages/index.astro +100 -0
- package/src/pages/admin/posts/[id].astro +6 -0
- package/src/pages/admin/posts/index.astro +7 -0
- package/src/pages/admin/settings.astro +512 -0
- package/src/pages/admin/tags.astro +101 -0
- package/src/pages/admin/users.astro +149 -0
- package/src/pages/api/backup.ts +63 -0
- package/src/pages/api/drafts.ts +106 -0
- package/src/pages/api/media/upload.ts +89 -0
- package/src/pages/api/restore.ts +102 -0
- package/src/pages/author/[slug].astro +66 -0
- package/src/pages/blog/[slug].astro +240 -0
- package/src/pages/blog/index.astro +51 -0
- package/src/pages/blog/tag/[slug].astro +83 -0
- package/src/pages/embed/[pageId]/[blockId].ts +45 -0
- package/src/pages/go/[id].ts +10 -0
- package/src/pages/index.astro +52 -0
- package/src/pages/links.astro +110 -0
- package/src/pages/llms.txt.ts +47 -0
- package/src/pages/media/[...key].ts +18 -0
- package/src/pages/preview/[type]/[id].astro +52 -0
- package/src/pages/robots.txt.ts +28 -0
- package/src/pages/rss.xml.ts +58 -0
- package/src/pages/search.astro +83 -0
- package/src/pages/sitemap.xml.ts +55 -0
- package/src/styles/admin.css +652 -0
- package/src/styles/builder.css +121 -0
- package/src/styles/cards.css +176 -0
- package/src/styles/editor.css +596 -0
- package/src/styles/site.css +427 -0
- package/src/themes/editorial/templates/home.astro +127 -0
- package/src/themes/editorial/templates/post-minimal.astro +50 -0
- package/src/themes/editorial/theme.css +108 -0
- package/src/themes/editorial/theme.json +20 -0
- package/src/themes/field/theme.json +17 -0
- package/src/themes/ink/theme.json +17 -0
- package/src/themes/night/theme.css +7 -0
- package/src/themes/night/theme.json +17 -0
- package/src/virtual.d.ts +25 -0
- package/src/worker.ts +28 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// Versioned schema migrations shared by the two SQLite-dialect adapters
|
|
2
|
+
// (D1 and libSQL). Applied versions are recorded in the `migrations` table;
|
|
3
|
+
// each adapter's runner applies whatever is newer, in order, at startup.
|
|
4
|
+
//
|
|
5
|
+
// Rules: never edit a shipped migration — append a new version. Version 1 is
|
|
6
|
+
// the pre-migrations baseline; DBs created before this system exist get it
|
|
7
|
+
// marked as applied without running (detected via sqlite_master).
|
|
8
|
+
|
|
9
|
+
export interface Migration {
|
|
10
|
+
version: number;
|
|
11
|
+
statements: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const MIGRATIONS_TABLE = `CREATE TABLE IF NOT EXISTS migrations (
|
|
15
|
+
version INTEGER PRIMARY KEY, applied_at INTEGER NOT NULL
|
|
16
|
+
)`;
|
|
17
|
+
|
|
18
|
+
export const MIGRATIONS: Migration[] = [
|
|
19
|
+
{
|
|
20
|
+
version: 1, // baseline: the original four tables
|
|
21
|
+
statements: [
|
|
22
|
+
`CREATE TABLE IF NOT EXISTS pages (
|
|
23
|
+
id TEXT PRIMARY KEY, slug TEXT UNIQUE NOT NULL, title TEXT NOT NULL,
|
|
24
|
+
status TEXT NOT NULL DEFAULT 'draft', is_home INTEGER NOT NULL DEFAULT 0,
|
|
25
|
+
blocks TEXT NOT NULL DEFAULT '[]', seo_title TEXT DEFAULT '', seo_desc TEXT DEFAULT '',
|
|
26
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL
|
|
27
|
+
)`,
|
|
28
|
+
`CREATE TABLE IF NOT EXISTS posts (
|
|
29
|
+
id TEXT PRIMARY KEY, slug TEXT UNIQUE NOT NULL, title TEXT NOT NULL,
|
|
30
|
+
body TEXT DEFAULT '', tags TEXT DEFAULT '[]', cover TEXT DEFAULT '',
|
|
31
|
+
status TEXT NOT NULL DEFAULT 'draft', published_at INTEGER,
|
|
32
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL
|
|
33
|
+
)`,
|
|
34
|
+
`CREATE TABLE IF NOT EXISTS links (
|
|
35
|
+
id TEXT PRIMARY KEY, label TEXT NOT NULL, url TEXT NOT NULL,
|
|
36
|
+
icon TEXT DEFAULT '', ord INTEGER NOT NULL, clicks INTEGER NOT NULL DEFAULT 0
|
|
37
|
+
)`,
|
|
38
|
+
`CREATE TABLE IF NOT EXISTS settings (
|
|
39
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
40
|
+
site_title TEXT NOT NULL DEFAULT 'My Site', tagline TEXT DEFAULT ''
|
|
41
|
+
)`,
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
version: 2, // editor rework: rich post fields, scheduling, media
|
|
46
|
+
statements: [
|
|
47
|
+
`ALTER TABLE posts ADD COLUMN body_json TEXT DEFAULT ''`,
|
|
48
|
+
`ALTER TABLE posts ADD COLUMN body_html TEXT DEFAULT ''`,
|
|
49
|
+
`ALTER TABLE posts ADD COLUMN excerpt TEXT DEFAULT ''`,
|
|
50
|
+
`ALTER TABLE posts ADD COLUMN cover_alt TEXT DEFAULT ''`,
|
|
51
|
+
`ALTER TABLE posts ADD COLUMN seo_title TEXT DEFAULT ''`,
|
|
52
|
+
`ALTER TABLE posts ADD COLUMN seo_desc TEXT DEFAULT ''`,
|
|
53
|
+
`ALTER TABLE posts ADD COLUMN scheduled_at INTEGER`,
|
|
54
|
+
`CREATE TABLE IF NOT EXISTS media (
|
|
55
|
+
id TEXT PRIMARY KEY, key TEXT UNIQUE NOT NULL, filename TEXT NOT NULL,
|
|
56
|
+
mime TEXT NOT NULL, width INTEGER NOT NULL DEFAULT 0, height INTEGER NOT NULL DEFAULT 0,
|
|
57
|
+
size INTEGER NOT NULL DEFAULT 0, alt TEXT DEFAULT '', variants TEXT DEFAULT '[]',
|
|
58
|
+
created_at INTEGER NOT NULL
|
|
59
|
+
)`,
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
version: 3, // tags as entities + multi-author users
|
|
64
|
+
statements: [
|
|
65
|
+
`CREATE TABLE IF NOT EXISTS tags (
|
|
66
|
+
id TEXT PRIMARY KEY, name TEXT NOT NULL, slug TEXT UNIQUE NOT NULL,
|
|
67
|
+
description TEXT DEFAULT ''
|
|
68
|
+
)`,
|
|
69
|
+
`CREATE TABLE IF NOT EXISTS users (
|
|
70
|
+
id TEXT PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL,
|
|
71
|
+
role TEXT NOT NULL DEFAULT 'editor', pass_hash TEXT NOT NULL,
|
|
72
|
+
created_at INTEGER NOT NULL
|
|
73
|
+
)`,
|
|
74
|
+
`ALTER TABLE posts ADD COLUMN author_id TEXT`,
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
version: 4, // pages move from widget blocks to the TipTap editor
|
|
79
|
+
statements: [
|
|
80
|
+
`ALTER TABLE pages ADD COLUMN body_json TEXT DEFAULT ''`,
|
|
81
|
+
`ALTER TABLE pages ADD COLUMN body_html TEXT DEFAULT ''`,
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
version: 5, // links page items: custom HTML/JS blocks alongside link buttons
|
|
86
|
+
statements: [
|
|
87
|
+
`ALTER TABLE links ADD COLUMN kind TEXT NOT NULL DEFAULT 'link'`,
|
|
88
|
+
`ALTER TABLE links ADD COLUMN html TEXT DEFAULT ''`,
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
version: 6, // link-in-bio block types: per-item JSON meta (brand color, spacer size, vcard fields…)
|
|
93
|
+
statements: [`ALTER TABLE links ADD COLUMN meta TEXT DEFAULT '{}'`],
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
version: 7, // links page gets its own display name + bio, decoupled from site title/tagline
|
|
97
|
+
statements: [
|
|
98
|
+
`ALTER TABLE settings ADD COLUMN links_name TEXT DEFAULT ''`,
|
|
99
|
+
`ALTER TABLE settings ADD COLUMN links_bio TEXT DEFAULT ''`,
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
version: 8, // links page profile photo
|
|
104
|
+
statements: [`ALTER TABLE settings ADD COLUMN links_avatar TEXT DEFAULT ''`],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
version: 9, // editable site footer (markdown)
|
|
108
|
+
statements: [`ALTER TABLE settings ADD COLUMN footer_text TEXT DEFAULT ''`],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
version: 10, // theme engine: active theme + sparse token overrides + site logo
|
|
112
|
+
statements: [
|
|
113
|
+
`ALTER TABLE settings ADD COLUMN active_theme TEXT DEFAULT ''`,
|
|
114
|
+
`ALTER TABLE settings ADD COLUMN design_overrides TEXT DEFAULT '{}'`,
|
|
115
|
+
`ALTER TABLE settings ADD COLUMN site_logo TEXT DEFAULT ''`,
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
version: 11, // featured posts (homepage/featured sections)
|
|
120
|
+
statements: [`ALTER TABLE posts ADD COLUMN featured INTEGER NOT NULL DEFAULT 0`],
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
version: 12, // managed navigation (header / footer / social areas)
|
|
124
|
+
statements: [
|
|
125
|
+
`CREATE TABLE IF NOT EXISTS nav_items (
|
|
126
|
+
id TEXT PRIMARY KEY, label TEXT NOT NULL, url TEXT NOT NULL,
|
|
127
|
+
area TEXT NOT NULL DEFAULT 'header', ord INTEGER NOT NULL
|
|
128
|
+
)`,
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
version: 13, // author profiles: bio, avatar, public slug for /author/<slug>
|
|
133
|
+
statements: [
|
|
134
|
+
`ALTER TABLE users ADD COLUMN bio TEXT DEFAULT ''`,
|
|
135
|
+
`ALTER TABLE users ADD COLUMN avatar TEXT DEFAULT ''`,
|
|
136
|
+
`ALTER TABLE users ADD COLUMN slug TEXT DEFAULT ''`,
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
version: 14, // external drafts API: bearer key + CORS origin allowlist
|
|
141
|
+
statements: [
|
|
142
|
+
`ALTER TABLE settings ADD COLUMN drafts_api_key TEXT DEFAULT ''`,
|
|
143
|
+
`ALTER TABLE settings ADD COLUMN drafts_allowed_origins TEXT DEFAULT '[]'`,
|
|
144
|
+
],
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
version: 15, // SEO foundation: canonical site URL, favicon, default share image
|
|
148
|
+
statements: [
|
|
149
|
+
`ALTER TABLE settings ADD COLUMN site_url TEXT DEFAULT ''`,
|
|
150
|
+
`ALTER TABLE settings ADD COLUMN site_favicon TEXT DEFAULT ''`,
|
|
151
|
+
`ALTER TABLE settings ADD COLUMN site_cover TEXT DEFAULT ''`,
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
version: 16, // URL redirects (manual + auto-created on slug changes)
|
|
156
|
+
statements: [
|
|
157
|
+
`CREATE TABLE IF NOT EXISTS redirects (
|
|
158
|
+
id TEXT PRIMARY KEY, from_path TEXT UNIQUE NOT NULL, to_path TEXT NOT NULL,
|
|
159
|
+
code INTEGER NOT NULL DEFAULT 301, created_at INTEGER NOT NULL
|
|
160
|
+
)`,
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
version: 17, // content model: multi-author posts, per-doc templates, announcement bar
|
|
165
|
+
statements: [
|
|
166
|
+
`CREATE TABLE IF NOT EXISTS post_authors (
|
|
167
|
+
post_id TEXT NOT NULL, author_id TEXT NOT NULL, ord INTEGER NOT NULL DEFAULT 0,
|
|
168
|
+
PRIMARY KEY (post_id, author_id)
|
|
169
|
+
)`,
|
|
170
|
+
// existing single authors become the first (primary) entry
|
|
171
|
+
`INSERT OR IGNORE INTO post_authors (post_id, author_id, ord)
|
|
172
|
+
SELECT id, author_id, 0 FROM posts WHERE author_id IS NOT NULL`,
|
|
173
|
+
`ALTER TABLE posts ADD COLUMN template TEXT DEFAULT ''`,
|
|
174
|
+
`ALTER TABLE pages ADD COLUMN template TEXT DEFAULT ''`,
|
|
175
|
+
`ALTER TABLE settings ADD COLUMN announcement TEXT DEFAULT '{}'`,
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
version: 18, // site tools: code injection, publication timezone + locale
|
|
180
|
+
statements: [
|
|
181
|
+
`ALTER TABLE settings ADD COLUMN head_code TEXT DEFAULT ''`,
|
|
182
|
+
`ALTER TABLE settings ADD COLUMN footer_code TEXT DEFAULT ''`,
|
|
183
|
+
`ALTER TABLE settings ADD COLUMN timezone TEXT DEFAULT ''`,
|
|
184
|
+
`ALTER TABLE settings ADD COLUMN locale TEXT DEFAULT ''`,
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
// Multiple collections: posts gain a `collection` column keyed by the
|
|
189
|
+
// acms({ content.collections }) config key. Slug uniqueness becomes
|
|
190
|
+
// per-collection — v1 declared slug as column-level UNIQUE, which SQLite
|
|
191
|
+
// can't alter away, so this is a table rebuild (create → copy → swap).
|
|
192
|
+
// Column lists are explicit so the copy can never mispair values.
|
|
193
|
+
version: 19,
|
|
194
|
+
statements: [
|
|
195
|
+
`CREATE TABLE posts_v19 (
|
|
196
|
+
id TEXT PRIMARY KEY, slug TEXT NOT NULL, title TEXT NOT NULL,
|
|
197
|
+
body TEXT DEFAULT '', tags TEXT DEFAULT '[]', cover TEXT DEFAULT '',
|
|
198
|
+
status TEXT NOT NULL DEFAULT 'draft', published_at INTEGER,
|
|
199
|
+
created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL,
|
|
200
|
+
body_json TEXT DEFAULT '', body_html TEXT DEFAULT '', excerpt TEXT DEFAULT '',
|
|
201
|
+
cover_alt TEXT DEFAULT '', seo_title TEXT DEFAULT '', seo_desc TEXT DEFAULT '',
|
|
202
|
+
scheduled_at INTEGER, author_id TEXT, featured INTEGER NOT NULL DEFAULT 0,
|
|
203
|
+
template TEXT DEFAULT '',
|
|
204
|
+
collection TEXT NOT NULL DEFAULT 'posts',
|
|
205
|
+
UNIQUE(collection, slug)
|
|
206
|
+
)`,
|
|
207
|
+
`INSERT INTO posts_v19 (
|
|
208
|
+
id, slug, title, body, tags, cover, status, published_at, created_at, updated_at,
|
|
209
|
+
body_json, body_html, excerpt, cover_alt, seo_title, seo_desc,
|
|
210
|
+
scheduled_at, author_id, featured, template, collection
|
|
211
|
+
) SELECT
|
|
212
|
+
id, slug, title, body, tags, cover, status, published_at, created_at, updated_at,
|
|
213
|
+
body_json, body_html, excerpt, cover_alt, seo_title, seo_desc,
|
|
214
|
+
scheduled_at, author_id, featured, template, 'posts'
|
|
215
|
+
FROM posts`,
|
|
216
|
+
`DROP TABLE posts`,
|
|
217
|
+
`ALTER TABLE posts_v19 RENAME TO posts`,
|
|
218
|
+
`CREATE INDEX IF NOT EXISTS idx_posts_collection ON posts(collection)`,
|
|
219
|
+
],
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
// Bilingual foundation: pages gain a `locale` keyed by acms({ i18n })
|
|
223
|
+
// locale codes. '' means the default locale, so existing rows (and sites
|
|
224
|
+
// that never configure i18n) keep today's behavior. "Is home" becomes
|
|
225
|
+
// per-locale — one home page per language.
|
|
226
|
+
version: 20,
|
|
227
|
+
statements: [`ALTER TABLE pages ADD COLUMN locale TEXT NOT NULL DEFAULT ''`],
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
|
|
231
|
+
export const LATEST_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Post } from '../schema';
|
|
2
|
+
|
|
3
|
+
// Shared ranking for the LIKE-based search: title hits beat excerpt hits beat
|
|
4
|
+
// body hits; recency breaks ties. Swap the adapters' SQL for FTS later and
|
|
5
|
+
// this ranking can go — the repo method signature stays the same.
|
|
6
|
+
export function rankByQuery(posts: Post[], query: string): Post[] {
|
|
7
|
+
const q = query.toLowerCase();
|
|
8
|
+
const score = (p: Post) =>
|
|
9
|
+
(p.title.toLowerCase().includes(q) ? 4 : 0) +
|
|
10
|
+
(p.excerpt.toLowerCase().includes(q) ? 2 : 0) +
|
|
11
|
+
(p.tags.some((t) => t.toLowerCase().includes(q)) ? 2 : 0) +
|
|
12
|
+
1;
|
|
13
|
+
return [...posts].sort((a, b) => score(b) - score(a) || (b.publishedAt ?? 0) - (a.publishedAt ?? 0));
|
|
14
|
+
}
|