@rimelight/cms 0.0.2 → 0.0.3
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/LICENSE +21 -0
- package/package.json +16 -14
- package/src/admin/api/media-file.ts +39 -0
- package/src/admin/api/media.ts +199 -0
- package/src/admin/layouts/CMSDashboardLayout.astro +178 -0
- package/src/admin/layouts/DefaultParentLayout.astro +50 -0
- package/src/admin/pages/assets.astro +424 -0
- package/src/admin/pages/byline-schema.astro +62 -0
- package/src/admin/pages/bylines.astro +16 -0
- package/src/admin/pages/categories.astro +21 -0
- package/src/admin/pages/content-types.astro +55 -0
- package/src/admin/pages/dashboard.astro +61 -0
- package/src/admin/pages/pages-edit.astro +595 -0
- package/src/admin/pages/pages-index.astro +146 -0
- package/src/admin/pages/pages-new.astro +130 -0
- package/src/admin/pages/pages-preview.astro +111 -0
- package/src/admin/pages/pages-review.astro +236 -0
- package/src/admin/pages/settings.astro +203 -0
- package/src/admin/pages/tags.astro +21 -0
- package/src/admin/pages/templates-edit.astro +234 -0
- package/src/admin/pages/templates-index.astro +95 -0
- package/src/admin/pages/templates-new.astro +193 -0
- package/src/admin/pages/users.astro +74 -0
- package/src/admin/pages/versions.astro +74 -0
- package/src/astro/BlockRenderer.astro +44 -102
- package/src/astro/PageRenderer.astro +9 -2
- package/src/astro/blocks/CalloutBlock.astro +7 -7
- package/src/astro/blocks/CardBlock.astro +5 -5
- package/src/astro/blocks/CodeBlock.astro +2 -2
- package/src/astro/blocks/FileTreeBlock.astro +7 -7
- package/src/astro/blocks/ImageBlock.astro +2 -2
- package/src/astro/blocks/OrderedListBlock.astro +2 -2
- package/src/astro/blocks/ParagraphBlock.astro +3 -3
- package/src/astro/blocks/SectionBlock.astro +6 -6
- package/src/astro/blocks/StepItemBlock.astro +3 -3
- package/src/astro/blocks/StepsBlock.astro +1 -1
- package/src/astro/blocks/TableBlock.astro +6 -6
- package/src/astro/blocks/TabsBlock.astro +9 -9
- package/src/astro/blocks/UnorderedListBlock.astro +2 -2
- package/src/astro/blocks/index.ts +35 -0
- package/src/client/components/RimelightBlock.tsx +19 -19
- package/src/client/components/RimelightBlockPicker.tsx +9 -13
- package/src/client/components/RimelightBylinesManager.tsx +438 -0
- package/src/client/components/RimelightEditor.tsx +3 -3
- package/src/client/components/RimelightPreview.tsx +37 -45
- package/src/client/components/RimelightPropertiesPanel.tsx +368 -26
- package/src/client/components/RimelightTaxonomyManager.tsx +369 -0
- package/src/client/components/RimelightTaxonomyMasterDetail.tsx +412 -0
- package/src/client/components/RimelightTemplateEditor.tsx +6 -8
- package/src/client/components/editors/CalloutEditor.tsx +2 -4
- package/src/client/components/editors/CardsEditor.tsx +2 -4
- package/src/client/components/editors/CodeEditor.tsx +1 -3
- package/src/client/components/editors/FileTreeEditor.tsx +2 -4
- package/src/client/components/editors/ImageEditor.tsx +3 -3
- package/src/client/components/editors/ParagraphEditor.tsx +2 -2
- package/src/client/components/editors/SceneEditor.tsx +6 -12
- package/src/client/components/editors/ScriptEditor.tsx +8 -16
- package/src/client/components/editors/SectionEditor.tsx +4 -4
- package/src/client/components/editors/StepItemEditor.tsx +2 -2
- package/src/client/components/editors/StepsEditor.tsx +2 -4
- package/src/client/components/editors/TabItemEditor.tsx +3 -3
- package/src/client/components/editors/TableEditor.tsx +5 -5
- package/src/client/components/editors/TabsEditor.tsx +2 -4
- package/src/client/components/index.ts +3 -0
- package/src/client/loader.ts +3 -0
- package/src/core/diff.ts +145 -0
- package/src/core/excerpt.ts +159 -0
- package/src/core/preview.ts +87 -0
- package/src/core/registry.ts +0 -86
- package/src/core/types/blocks.ts +6 -1
- package/src/core/types/bylines.ts +14 -0
- package/src/core/types/media.ts +13 -0
- package/src/core/types/taxonomies.ts +20 -0
- package/src/cron/scheduled.ts +57 -0
- package/src/docs/agent.ts +116 -0
- package/src/docs/config.ts +25 -0
- package/src/docs/index.ts +5 -0
- package/src/docs/routing.ts +104 -0
- package/src/docs/sidebar.ts +251 -0
- package/src/docs/toc.ts +47 -0
- package/src/env.d.ts +13 -0
- package/src/index.ts +40 -8
- package/src/integration.ts +196 -0
- package/src/loader/live.ts +254 -0
- package/src/markdown/index.ts +0 -1
- package/src/mcp/index.ts +228 -0
- package/src/schema/bylines.ts +23 -0
- package/src/schema/index.ts +3 -4
- package/src/schema/page_versions.ts +2 -0
- package/src/schema/pages.ts +2 -0
- package/src/schema/site_settings.ts +41 -0
- package/src/schema/taxonomies.ts +49 -0
- package/src/services/bylines.ts +74 -0
- package/src/services/search-indexer.ts +61 -0
- package/src/services/site-settings.ts +108 -0
- package/src/services/taxonomies.ts +276 -0
- package/src/storage/index.ts +253 -0
- package/src/astro/blocks/ApiDocumentationBlock.astro +0 -350
- package/src/astro/blocks/DialogueBlock.astro +0 -23
- package/src/astro/blocks/LivePreviewBlock.astro +0 -27
- package/src/astro/blocks/SceneBlock.astro +0 -65
- package/src/astro/blocks/ScriptBlock.astro +0 -59
- package/src/core/template-sync.ts +0 -75
- package/src/markdown/parser.ts +0 -347
- package/src/migration-tools.ts +0 -334
- package/src/migration.ts +0 -155
- package/src/schema/component_dependencies.ts +0 -21
- package/src/schema/component_metadata.ts +0 -31
- package/src/schema/component_metadata_cache.ts +0 -15
- package/src/schema/component_versions.ts +0 -19
- package/src/search/sync.ts +0 -32
- package/src/services/component-metadata.ts +0 -134
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import type { DocsConfig, SidebarItem, SidebarScope, BadgeProps } from "./config"
|
|
2
|
+
|
|
3
|
+
export interface ResolvedSidebarItem {
|
|
4
|
+
label: string
|
|
5
|
+
href?: string | undefined
|
|
6
|
+
icon?: string | undefined
|
|
7
|
+
badge?: string | BadgeProps | undefined
|
|
8
|
+
active?: boolean | undefined
|
|
9
|
+
children?: ResolvedSidebarItem[] | undefined
|
|
10
|
+
collapsed?: boolean | undefined
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResolvedScope {
|
|
14
|
+
id: string
|
|
15
|
+
label: string
|
|
16
|
+
href: string
|
|
17
|
+
icon?: string | undefined
|
|
18
|
+
active?: boolean | undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function formatDocsUrl(
|
|
22
|
+
href: string,
|
|
23
|
+
locale: string,
|
|
24
|
+
activeVersion?: string,
|
|
25
|
+
includeVersionInUrl?: boolean
|
|
26
|
+
): string {
|
|
27
|
+
let url = href.replace("{locale}", locale)
|
|
28
|
+
if (activeVersion && includeVersionInUrl) {
|
|
29
|
+
if (url.includes(`/${activeVersion}/`) || url.endsWith(`/${activeVersion}`)) {
|
|
30
|
+
return url
|
|
31
|
+
}
|
|
32
|
+
const docsPattern = new RegExp(`(/${locale}/docs)(/|$)`)
|
|
33
|
+
const companyDocsPattern = new RegExp(`(/${locale}/company/docs)(/|$)`)
|
|
34
|
+
|
|
35
|
+
if (companyDocsPattern.test(url)) {
|
|
36
|
+
url = url.replace(companyDocsPattern, `$1/${activeVersion}$2`)
|
|
37
|
+
} else if (docsPattern.test(url)) {
|
|
38
|
+
url = url.replace(docsPattern, `$1/${activeVersion}$2`)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
url = url.replace(/\/{2,}/g, "/")
|
|
42
|
+
}
|
|
43
|
+
return url
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function findFirstHref(
|
|
47
|
+
items: SidebarItem[],
|
|
48
|
+
locale: string,
|
|
49
|
+
activeVersion?: string,
|
|
50
|
+
includeVersionInUrl?: boolean
|
|
51
|
+
): string | undefined {
|
|
52
|
+
for (const item of items) {
|
|
53
|
+
if (item.href) return formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl)
|
|
54
|
+
const childItems = item.children || item.items
|
|
55
|
+
if (childItems) {
|
|
56
|
+
const found = findFirstHref(childItems, locale, activeVersion, includeVersionInUrl)
|
|
57
|
+
if (found) return found
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return undefined
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getScopePrefix(
|
|
64
|
+
items: SidebarItem[],
|
|
65
|
+
locale: string,
|
|
66
|
+
activeVersion?: string,
|
|
67
|
+
includeVersionInUrl?: boolean
|
|
68
|
+
): string {
|
|
69
|
+
const allHrefs: string[] = []
|
|
70
|
+
|
|
71
|
+
function collect(item: SidebarItem) {
|
|
72
|
+
if (item.href)
|
|
73
|
+
allHrefs.push(formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl))
|
|
74
|
+
const childItems = item.children || item.items
|
|
75
|
+
if (childItems) childItems.forEach(collect)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
items.forEach(collect)
|
|
79
|
+
if (allHrefs.length === 0) return ""
|
|
80
|
+
|
|
81
|
+
const parts = allHrefs.map((h) => h.split("/").filter(Boolean))
|
|
82
|
+
let commonLen = 0
|
|
83
|
+
const firstPart = parts[0]
|
|
84
|
+
if (!firstPart) return ""
|
|
85
|
+
for (let i = 0; i < firstPart.length; i++) {
|
|
86
|
+
if (parts.every((p) => p[i] === firstPart[i])) commonLen++
|
|
87
|
+
else break
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return "/" + firstPart.slice(0, commonLen).join("/") + "/"
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hasPath(
|
|
94
|
+
items: SidebarItem[],
|
|
95
|
+
locale: string,
|
|
96
|
+
normPath: string,
|
|
97
|
+
activeVersion?: string,
|
|
98
|
+
includeVersionInUrl?: boolean
|
|
99
|
+
): boolean {
|
|
100
|
+
for (const item of items) {
|
|
101
|
+
if (
|
|
102
|
+
item.href &&
|
|
103
|
+
formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl)
|
|
104
|
+
.replace(/\/$/, "")
|
|
105
|
+
.toLowerCase() === normPath
|
|
106
|
+
) {
|
|
107
|
+
return true
|
|
108
|
+
}
|
|
109
|
+
const childItems = item.children || item.items
|
|
110
|
+
if (childItems && hasPath(childItems, locale, normPath, activeVersion, includeVersionInUrl)) {
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function getDocsSidebar(
|
|
118
|
+
config: DocsConfig,
|
|
119
|
+
locale: string,
|
|
120
|
+
currentPath: string,
|
|
121
|
+
activeVersion?: string,
|
|
122
|
+
includeVersionInUrl?: boolean
|
|
123
|
+
): Promise<{
|
|
124
|
+
items: ResolvedSidebarItem[]
|
|
125
|
+
scopes: ResolvedScope[]
|
|
126
|
+
activeScope?: ResolvedScope | undefined
|
|
127
|
+
}> {
|
|
128
|
+
const normPath = currentPath.replace(/\/$/, "").toLowerCase()
|
|
129
|
+
|
|
130
|
+
const sidebarScopes: SidebarScope[] = Array.isArray(config.sidebar)
|
|
131
|
+
? config.sidebar.filter((item): item is SidebarScope => "id" in item || "scopes" in item)
|
|
132
|
+
: config.sidebar.scopes || []
|
|
133
|
+
|
|
134
|
+
const scopes: ResolvedScope[] = sidebarScopes.map((scope) => {
|
|
135
|
+
const id = scope.id || scope.label
|
|
136
|
+
let href = scope.href || ""
|
|
137
|
+
if (!href && scope.items && scope.items.length > 0) {
|
|
138
|
+
href = findFirstHref(scope.items, locale, activeVersion, includeVersionInUrl) || ""
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
id,
|
|
142
|
+
label: scope.label,
|
|
143
|
+
href: formatDocsUrl(href, locale, activeVersion, includeVersionInUrl),
|
|
144
|
+
icon: scope.icon
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const scopePrefixes: string[] = sidebarScopes.map((scope) =>
|
|
149
|
+
scope.items ? getScopePrefix(scope.items, locale, activeVersion, includeVersionInUrl) : ""
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
let activeScope = scopes.find((s) => normPath === s.href.replace(/\/$/, "").toLowerCase())
|
|
153
|
+
if (!activeScope) {
|
|
154
|
+
for (let i = 0; i < sidebarScopes.length; i++) {
|
|
155
|
+
const scope = sidebarScopes[i]
|
|
156
|
+
if (
|
|
157
|
+
scope &&
|
|
158
|
+
scope.items &&
|
|
159
|
+
hasPath(scope.items, locale, normPath, activeVersion, includeVersionInUrl)
|
|
160
|
+
) {
|
|
161
|
+
activeScope = scopes[i]
|
|
162
|
+
break
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (!activeScope) {
|
|
167
|
+
const sorted = [...scopePrefixes.entries()]
|
|
168
|
+
.filter(([, p]) => p)
|
|
169
|
+
.toSorted(([, a], [, b]) => b.length - a.length)
|
|
170
|
+
for (const [i] of sorted) {
|
|
171
|
+
const prefix = scopePrefixes[i]
|
|
172
|
+
if (prefix && normPath.startsWith(prefix.toLowerCase())) {
|
|
173
|
+
activeScope = scopes[i]
|
|
174
|
+
break
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (!activeScope && scopes.length > 0) {
|
|
179
|
+
activeScope = scopes[0]
|
|
180
|
+
}
|
|
181
|
+
if (activeScope) activeScope.active = true
|
|
182
|
+
|
|
183
|
+
const sidebarConfig = sidebarScopes.find(
|
|
184
|
+
(item) => activeScope && (item.id === activeScope.id || item.label === activeScope.id)
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
const items = sidebarConfig?.items || []
|
|
188
|
+
|
|
189
|
+
async function resolveItem(item: SidebarItem): Promise<ResolvedSidebarItem[]> {
|
|
190
|
+
const resolved: ResolvedSidebarItem = {
|
|
191
|
+
label: item.label || "",
|
|
192
|
+
href: item.href
|
|
193
|
+
? formatDocsUrl(item.href, locale, activeVersion, includeVersionInUrl)
|
|
194
|
+
: undefined,
|
|
195
|
+
icon: item.icon,
|
|
196
|
+
badge: item.badge,
|
|
197
|
+
collapsed: item.collapsed
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (resolved.href) {
|
|
201
|
+
resolved.active = normPath === resolved.href.replace(/\/$/, "").toLowerCase()
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const childItems = item.children || item.items
|
|
205
|
+
if (childItems) {
|
|
206
|
+
const children: ResolvedSidebarItem[] = []
|
|
207
|
+
const resolvedChildren = await Promise.all(childItems.map((child) => resolveItem(child)))
|
|
208
|
+
for (const res of resolvedChildren) {
|
|
209
|
+
children.push(...res)
|
|
210
|
+
}
|
|
211
|
+
resolved.children = children
|
|
212
|
+
if (!resolved.active) {
|
|
213
|
+
resolved.active = children.some((c) => c.active)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return [resolved]
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const resolvedItems: ResolvedSidebarItem[] = []
|
|
221
|
+
const resolvedAllItems = await Promise.all(items.map((item) => resolveItem(item)))
|
|
222
|
+
for (const res of resolvedAllItems) {
|
|
223
|
+
resolvedItems.push(...res)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return { items: resolvedItems, scopes, activeScope }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function getSurroundItems(sidebar: ResolvedSidebarItem[], currentPath: string) {
|
|
230
|
+
const flatItems: { label: string; href: string }[] = []
|
|
231
|
+
|
|
232
|
+
function flatten(items: ResolvedSidebarItem[]) {
|
|
233
|
+
for (const item of items) {
|
|
234
|
+
if (item.href) flatItems.push({ label: item.label, href: item.href })
|
|
235
|
+
if (item.children) flatten(item.children)
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
flatten(sidebar)
|
|
240
|
+
|
|
241
|
+
const normPath = currentPath.replace(/\/$/, "").toLowerCase()
|
|
242
|
+
const currentIndex = flatItems.findIndex(
|
|
243
|
+
(item) => item.href.replace(/\/$/, "").toLowerCase() === normPath
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
prev: currentIndex > 0 ? flatItems[currentIndex - 1] : null,
|
|
248
|
+
next:
|
|
249
|
+
currentIndex >= 0 && currentIndex < flatItems.length - 1 ? flatItems[currentIndex + 1] : null
|
|
250
|
+
}
|
|
251
|
+
}
|
package/src/docs/toc.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface TableOfContentsHeading {
|
|
2
|
+
depth: number
|
|
3
|
+
slug: string
|
|
4
|
+
text: string
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function slugifyHeading(text: string): string {
|
|
8
|
+
return text
|
|
9
|
+
.toString()
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.normalize("NFD")
|
|
12
|
+
.replace(/[\u0300-\u036f]/g, "")
|
|
13
|
+
.replace(/\s+/g, "-")
|
|
14
|
+
.replace(/[^\w-]+/g, "")
|
|
15
|
+
.replace(/-{2,}/g, "-")
|
|
16
|
+
.replace(/^-+/, "")
|
|
17
|
+
.replace(/-+$/, "")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function extractHeadingsFromBlocks(
|
|
21
|
+
blocks: any[] = [],
|
|
22
|
+
currentDepth = 2
|
|
23
|
+
): TableOfContentsHeading[] {
|
|
24
|
+
if (!Array.isArray(blocks)) return []
|
|
25
|
+
const headings: TableOfContentsHeading[] = []
|
|
26
|
+
|
|
27
|
+
for (const block of blocks) {
|
|
28
|
+
if (!block) continue
|
|
29
|
+
if (block.type === "SectionBlock") {
|
|
30
|
+
const title = block.props?.title || ""
|
|
31
|
+
const level = Number(block.props?.level) || currentDepth
|
|
32
|
+
if (title) {
|
|
33
|
+
headings.push({
|
|
34
|
+
depth: level,
|
|
35
|
+
slug: slugifyHeading(title),
|
|
36
|
+
text: title
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
const children = block.children || block.props?.children || []
|
|
40
|
+
if (Array.isArray(children) && children.length > 0) {
|
|
41
|
+
headings.push(...extractHeadingsFromBlocks(children, Math.min(6, level + 1)))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return headings
|
|
47
|
+
}
|
package/src/env.d.ts
CHANGED
|
@@ -2,3 +2,16 @@ declare module "*.astro" {
|
|
|
2
2
|
const component: any
|
|
3
3
|
export default component
|
|
4
4
|
}
|
|
5
|
+
|
|
6
|
+
declare module "virtual:rimelight-cms/parent-layout" {
|
|
7
|
+
const layout: any
|
|
8
|
+
export default layout
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare module "virtual:rimelight-cms/db" {
|
|
12
|
+
export const db: any
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module "virtual:rimelight-cms/storage" {
|
|
16
|
+
export const storageConfig: any
|
|
17
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,6 +6,9 @@ export * from "./core/types/templates.ts"
|
|
|
6
6
|
export * from "./core/types/versioning.ts"
|
|
7
7
|
export * from "./core/page-definitions.ts"
|
|
8
8
|
|
|
9
|
+
// Markdown Serialization & Parsing
|
|
10
|
+
export * from "./markdown/index.ts"
|
|
11
|
+
|
|
9
12
|
// Re-export specific types for convenience
|
|
10
13
|
export type {
|
|
11
14
|
TimeOfDay,
|
|
@@ -19,8 +22,6 @@ export type {
|
|
|
19
22
|
// Core Services & Registries
|
|
20
23
|
export * from "./core/registry.ts"
|
|
21
24
|
export * from "./core/validator.ts"
|
|
22
|
-
export * from "./core/template-sync.ts"
|
|
23
|
-
export * from "./services/component-metadata.ts"
|
|
24
25
|
|
|
25
26
|
// Auth & Security Guards
|
|
26
27
|
export * from "./auth/permissions.ts"
|
|
@@ -31,15 +32,9 @@ export * from "./auth/filter-templates.ts"
|
|
|
31
32
|
// Edge Cache & Search
|
|
32
33
|
export * from "./cache/purge.ts"
|
|
33
34
|
export * from "./search/query.ts"
|
|
34
|
-
export * from "./search/sync.ts"
|
|
35
35
|
|
|
36
36
|
// Database Schemas & Migration
|
|
37
37
|
export * from "./schema/index.ts"
|
|
38
|
-
export * from "./migration.ts"
|
|
39
|
-
|
|
40
|
-
// Markdown Serialization & Parsing
|
|
41
|
-
export * from "./markdown/index.ts"
|
|
42
|
-
export * from "./migration-tools.ts"
|
|
43
38
|
|
|
44
39
|
// Astro Components
|
|
45
40
|
export { default as PageRenderer } from "./astro/PageRenderer.astro"
|
|
@@ -47,3 +42,40 @@ export { default as BlockRenderer } from "./astro/BlockRenderer.astro"
|
|
|
47
42
|
|
|
48
43
|
// Toast API
|
|
49
44
|
export * from "./client/toast.ts"
|
|
45
|
+
|
|
46
|
+
// Excerpts & Summaries
|
|
47
|
+
export * from "./core/excerpt.ts"
|
|
48
|
+
|
|
49
|
+
// Dynamic Site Settings
|
|
50
|
+
export * from "./services/site-settings.ts"
|
|
51
|
+
|
|
52
|
+
// Astro Live Loader & Collections
|
|
53
|
+
export * from "./loader/live.ts"
|
|
54
|
+
|
|
55
|
+
// Cloudflare Worker Cron Dispatcher
|
|
56
|
+
export * from "./cron/scheduled.ts"
|
|
57
|
+
|
|
58
|
+
// Model Context Protocol (MCP) Tools
|
|
59
|
+
export * from "./mcp/index.ts"
|
|
60
|
+
|
|
61
|
+
// Media & Bylines
|
|
62
|
+
export * from "./core/types/media.ts"
|
|
63
|
+
export * from "./core/types/bylines.ts"
|
|
64
|
+
export * from "./services/bylines.ts"
|
|
65
|
+
|
|
66
|
+
// Preview Tokens & Block Diffs
|
|
67
|
+
export * from "./core/preview.ts"
|
|
68
|
+
export * from "./core/diff.ts"
|
|
69
|
+
|
|
70
|
+
// Search Indexer
|
|
71
|
+
export * from "./services/search-indexer.ts"
|
|
72
|
+
|
|
73
|
+
// Taxonomies Engine
|
|
74
|
+
export * from "./core/types/taxonomies.ts"
|
|
75
|
+
export * from "./services/taxonomies.ts"
|
|
76
|
+
|
|
77
|
+
// Documentation Engine & Navigation
|
|
78
|
+
export * from "./docs/index.ts"
|
|
79
|
+
|
|
80
|
+
// Storage Adapters (R2, etc.)
|
|
81
|
+
export * from "./storage/index.ts"
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import type { AstroIntegration } from "astro"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import fs from "node:fs"
|
|
4
|
+
import { fileURLToPath } from "node:url"
|
|
5
|
+
import type { StorageConfig } from "./storage/index"
|
|
6
|
+
|
|
7
|
+
export interface RimelightCmsOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Route prefix for CMS admin pages. Defaults to "/[locale]/cms" (or "/cms" if no locale routing).
|
|
10
|
+
*/
|
|
11
|
+
routePrefix?: string | undefined
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Optional outer layout to wrap the CMS dashboard in (e.g. "./src/layouts/AppLayout.astro"). When
|
|
15
|
+
* omitted, renders as a dedicated standalone full-viewport dashboard.
|
|
16
|
+
*/
|
|
17
|
+
parentLayout?: string | undefined
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Path to the app database instance module exporting `db`. Defaults to "./src/db/index.ts" or
|
|
21
|
+
* "./src/db".
|
|
22
|
+
*/
|
|
23
|
+
db?: string | undefined
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Storage backend configuration (e.g. r2({ binding: "BLOB", publicUrl:
|
|
27
|
+
* "https://media.example.com" })).
|
|
28
|
+
*/
|
|
29
|
+
storage?: StorageConfig | undefined
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function rimelightCms(options: RimelightCmsOptions = {}): AstroIntegration {
|
|
33
|
+
const routePrefix = options.routePrefix ?? "/[locale]/cms"
|
|
34
|
+
const storageConfig = {
|
|
35
|
+
provider: options.storage?.provider ?? "r2",
|
|
36
|
+
binding: options.storage?.binding ?? "BLOB",
|
|
37
|
+
publicUrl: options.storage?.publicUrl,
|
|
38
|
+
prefix: options.storage?.prefix ?? "media/"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
name: "@rimelight/cms",
|
|
43
|
+
hooks: {
|
|
44
|
+
"astro:config:setup": ({ injectRoute, updateConfig, config }) => {
|
|
45
|
+
const rootDir = fileURLToPath(config.root)
|
|
46
|
+
|
|
47
|
+
// Resolve parent layout if provided
|
|
48
|
+
let resolvedParentLayout: string | null = null
|
|
49
|
+
if (options.parentLayout) {
|
|
50
|
+
resolvedParentLayout = path.isAbsolute(options.parentLayout)
|
|
51
|
+
? options.parentLayout
|
|
52
|
+
: path.resolve(rootDir, options.parentLayout)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Resolve db module if exists
|
|
56
|
+
let resolvedDb: string | null = null
|
|
57
|
+
if (options.db) {
|
|
58
|
+
resolvedDb = path.isAbsolute(options.db) ? options.db : path.resolve(rootDir, options.db)
|
|
59
|
+
} else {
|
|
60
|
+
const defaultDbTs = path.resolve(rootDir, "src/db/index.ts")
|
|
61
|
+
const defaultDbJs = path.resolve(rootDir, "src/db/index.js")
|
|
62
|
+
if (fs.existsSync(defaultDbTs)) {
|
|
63
|
+
resolvedDb = defaultDbTs
|
|
64
|
+
} else if (fs.existsSync(defaultDbJs)) {
|
|
65
|
+
resolvedDb = defaultDbJs
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 1. Inject CMS admin routes
|
|
70
|
+
injectRoute({
|
|
71
|
+
pattern: `${routePrefix}`,
|
|
72
|
+
entrypoint: "@rimelight/cms/admin/pages/dashboard.astro"
|
|
73
|
+
})
|
|
74
|
+
injectRoute({
|
|
75
|
+
pattern: `${routePrefix}/pages`,
|
|
76
|
+
entrypoint: "@rimelight/cms/admin/pages/pages-index.astro"
|
|
77
|
+
})
|
|
78
|
+
injectRoute({
|
|
79
|
+
pattern: `${routePrefix}/pages/new`,
|
|
80
|
+
entrypoint: "@rimelight/cms/admin/pages/pages-new.astro"
|
|
81
|
+
})
|
|
82
|
+
injectRoute({
|
|
83
|
+
pattern: `${routePrefix}/pages/[id]/edit`,
|
|
84
|
+
entrypoint: "@rimelight/cms/admin/pages/pages-edit.astro"
|
|
85
|
+
})
|
|
86
|
+
injectRoute({
|
|
87
|
+
pattern: `${routePrefix}/pages/[id]/preview`,
|
|
88
|
+
entrypoint: "@rimelight/cms/admin/pages/pages-preview.astro"
|
|
89
|
+
})
|
|
90
|
+
injectRoute({
|
|
91
|
+
pattern: `${routePrefix}/pages/[id]/review`,
|
|
92
|
+
entrypoint: "@rimelight/cms/admin/pages/pages-review.astro"
|
|
93
|
+
})
|
|
94
|
+
injectRoute({
|
|
95
|
+
pattern: `${routePrefix}/templates`,
|
|
96
|
+
entrypoint: "@rimelight/cms/admin/pages/templates-index.astro"
|
|
97
|
+
})
|
|
98
|
+
injectRoute({
|
|
99
|
+
pattern: `${routePrefix}/templates/new`,
|
|
100
|
+
entrypoint: "@rimelight/cms/admin/pages/templates-new.astro"
|
|
101
|
+
})
|
|
102
|
+
injectRoute({
|
|
103
|
+
pattern: `${routePrefix}/templates/[id]/edit`,
|
|
104
|
+
entrypoint: "@rimelight/cms/admin/pages/templates-edit.astro"
|
|
105
|
+
})
|
|
106
|
+
injectRoute({
|
|
107
|
+
pattern: `${routePrefix}/assets`,
|
|
108
|
+
entrypoint: "@rimelight/cms/admin/pages/assets.astro"
|
|
109
|
+
})
|
|
110
|
+
injectRoute({
|
|
111
|
+
pattern: `${routePrefix}/categories`,
|
|
112
|
+
entrypoint: "@rimelight/cms/admin/pages/categories.astro"
|
|
113
|
+
})
|
|
114
|
+
injectRoute({
|
|
115
|
+
pattern: `${routePrefix}/tags`,
|
|
116
|
+
entrypoint: "@rimelight/cms/admin/pages/tags.astro"
|
|
117
|
+
})
|
|
118
|
+
injectRoute({
|
|
119
|
+
pattern: `${routePrefix}/bylines`,
|
|
120
|
+
entrypoint: "@rimelight/cms/admin/pages/bylines.astro"
|
|
121
|
+
})
|
|
122
|
+
injectRoute({
|
|
123
|
+
pattern: `${routePrefix}/versions`,
|
|
124
|
+
entrypoint: "@rimelight/cms/admin/pages/versions.astro"
|
|
125
|
+
})
|
|
126
|
+
injectRoute({
|
|
127
|
+
pattern: `${routePrefix}/content-types`,
|
|
128
|
+
entrypoint: "@rimelight/cms/admin/pages/content-types.astro"
|
|
129
|
+
})
|
|
130
|
+
injectRoute({
|
|
131
|
+
pattern: `${routePrefix}/byline-schema`,
|
|
132
|
+
entrypoint: "@rimelight/cms/admin/pages/byline-schema.astro"
|
|
133
|
+
})
|
|
134
|
+
injectRoute({
|
|
135
|
+
pattern: `${routePrefix}/users`,
|
|
136
|
+
entrypoint: "@rimelight/cms/admin/pages/users.astro"
|
|
137
|
+
})
|
|
138
|
+
injectRoute({
|
|
139
|
+
pattern: `${routePrefix}/settings`,
|
|
140
|
+
entrypoint: "@rimelight/cms/admin/pages/settings.astro"
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
// Media API Routes
|
|
144
|
+
injectRoute({
|
|
145
|
+
pattern: `${routePrefix}/api/media`,
|
|
146
|
+
entrypoint: "@rimelight/cms/admin/api/media.ts"
|
|
147
|
+
})
|
|
148
|
+
injectRoute({
|
|
149
|
+
pattern: `${routePrefix}/api/media/file/[...key]`,
|
|
150
|
+
entrypoint: "@rimelight/cms/admin/api/media-file.ts"
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// 2. Vite plugin for virtual modules
|
|
154
|
+
updateConfig({
|
|
155
|
+
vite: {
|
|
156
|
+
plugins: [
|
|
157
|
+
{
|
|
158
|
+
name: "vite-plugin-rimelight-cms-virtuals",
|
|
159
|
+
resolveId(id) {
|
|
160
|
+
if (id === "virtual:rimelight-cms/parent-layout") {
|
|
161
|
+
return "\0virtual:rimelight-cms/parent-layout"
|
|
162
|
+
}
|
|
163
|
+
if (id === "virtual:rimelight-cms/db") {
|
|
164
|
+
return "\0virtual:rimelight-cms/db"
|
|
165
|
+
}
|
|
166
|
+
if (id === "virtual:rimelight-cms/storage") {
|
|
167
|
+
return "\0virtual:rimelight-cms/storage"
|
|
168
|
+
}
|
|
169
|
+
return undefined
|
|
170
|
+
},
|
|
171
|
+
load(id) {
|
|
172
|
+
if (id === "\0virtual:rimelight-cms/parent-layout") {
|
|
173
|
+
if (resolvedParentLayout && fs.existsSync(resolvedParentLayout)) {
|
|
174
|
+
return `export { default } from ${JSON.stringify(resolvedParentLayout)};`
|
|
175
|
+
}
|
|
176
|
+
return `export { default } from "@rimelight/cms/admin/layouts/DefaultParentLayout.astro";`
|
|
177
|
+
}
|
|
178
|
+
if (id === "\0virtual:rimelight-cms/db") {
|
|
179
|
+
if (resolvedDb && fs.existsSync(resolvedDb)) {
|
|
180
|
+
return `export * from ${JSON.stringify(resolvedDb)};`
|
|
181
|
+
}
|
|
182
|
+
return `export const db = null;`
|
|
183
|
+
}
|
|
184
|
+
if (id === "\0virtual:rimelight-cms/storage") {
|
|
185
|
+
return `export const storageConfig = ${JSON.stringify(storageConfig)};`
|
|
186
|
+
}
|
|
187
|
+
return undefined
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|