Monorepo: consolidate 7 repos into one
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m5s
Combines shared, blog, market, cart, events, federation, and account into a single repository. Eliminates submodule sync, sibling model copying at build time, and per-app CI orchestration. Changes: - Remove per-app .git, .gitmodules, .gitea, submodule shared/ dirs - Remove stale sibling model copies from each app - Update all 6 Dockerfiles for monorepo build context (root = .) - Add build directives to docker-compose.yml - Add single .gitea/workflows/ci.yml with change detection - Add .dockerignore for monorepo build context - Create __init__.py for federation and account (cross-app imports)
This commit is contained in:
81
shared/editor/src/Editor.jsx
Normal file
81
shared/editor/src/Editor.jsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { useMemo, useState, useEffect, useCallback } from "react";
|
||||
import { KoenigComposer, KoenigEditor, CardMenuPlugin } from "@tryghost/koenig-lexical";
|
||||
import "koenig-styles";
|
||||
import makeFileUploader from "./useFileUpload";
|
||||
|
||||
export default function Editor({ initialState, onChange, csrfToken, uploadUrls, oembedUrl, unsplashApiKey, snippetsUrl }) {
|
||||
const fileUploader = useMemo(() => makeFileUploader(csrfToken, uploadUrls), [csrfToken, uploadUrls]);
|
||||
|
||||
const [snippets, setSnippets] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!snippetsUrl) return;
|
||||
fetch(snippetsUrl, { headers: { "X-CSRFToken": csrfToken || "" } })
|
||||
.then((r) => r.ok ? r.json() : [])
|
||||
.then(setSnippets)
|
||||
.catch(() => {});
|
||||
}, [snippetsUrl, csrfToken]);
|
||||
|
||||
const createSnippet = useCallback(async ({ name, value }) => {
|
||||
if (!snippetsUrl) return;
|
||||
const resp = await fetch(snippetsUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": csrfToken || "",
|
||||
},
|
||||
body: JSON.stringify({ name, value: JSON.stringify(value) }),
|
||||
});
|
||||
if (!resp.ok) return;
|
||||
const created = await resp.json();
|
||||
setSnippets((prev) => {
|
||||
const idx = prev.findIndex((s) => s.name === created.name);
|
||||
if (idx >= 0) {
|
||||
const next = [...prev];
|
||||
next[idx] = created;
|
||||
return next;
|
||||
}
|
||||
return [...prev, created].sort((a, b) => a.name.localeCompare(b.name));
|
||||
});
|
||||
}, [snippetsUrl, csrfToken]);
|
||||
|
||||
const cardConfig = useMemo(() => ({
|
||||
fetchEmbed: async (url, { type } = {}) => {
|
||||
const params = new URLSearchParams({ url });
|
||||
if (type) params.set("type", type);
|
||||
const resp = await fetch(`${oembedUrl}?${params}`, {
|
||||
headers: { "X-CSRFToken": csrfToken || "" },
|
||||
});
|
||||
if (!resp.ok) return {};
|
||||
return resp.json();
|
||||
},
|
||||
unsplash: unsplashApiKey
|
||||
? { defaultHeaders: { Authorization: `Client-ID ${unsplashApiKey}` } }
|
||||
: false,
|
||||
membersEnabled: true,
|
||||
snippets: snippets.map((s) => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
value: typeof s.value === "string" ? JSON.parse(s.value) : s.value,
|
||||
})),
|
||||
createSnippet,
|
||||
}), [oembedUrl, csrfToken, unsplashApiKey, snippets, createSnippet]);
|
||||
|
||||
return (
|
||||
<KoenigComposer
|
||||
initialEditorState={initialState || undefined}
|
||||
fileUploader={fileUploader}
|
||||
cardConfig={cardConfig}
|
||||
>
|
||||
<KoenigEditor
|
||||
onChange={(serializedState) => {
|
||||
if (onChange) {
|
||||
onChange(JSON.stringify(serializedState));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<CardMenuPlugin />
|
||||
</KoenigEditor>
|
||||
</KoenigComposer>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user