diff --git a/framework/bundle.ts b/framework/bundle.ts index 762b2a4..df9025d 100644 --- a/framework/bundle.ts +++ b/framework/bundle.ts @@ -23,7 +23,8 @@ export async function bundleClientJavaScript( } const clientPlugins: esbuild.Plugin[] = [ - // There are currently no plugins needed by 'paperclover.net' + projectRelativeResolution(), + markoViaBuildCache(incr), ]; const bundle = await esbuild.build({ @@ -42,6 +43,9 @@ export async function bundleClientJavaScript( jsx: "automatic", jsxImportSource: "#ssr", jsxDev: dev, + define: { + "ASSERT": "console.assert", + }, }); if (bundle.errors.length || bundle.warnings.length) { throw new AggregateError( @@ -50,11 +54,15 @@ export async function bundleClientJavaScript( ); } const publicScriptRoutes = extraPublicScripts.map((file) => - path.basename(file).replace(/\.client\.[tj]sx?/, "") + "/js/" + + path.relative(hot.projectSrc, file).replaceAll("\\", "/").replace( + /\.client\.[tj]sx?/, + ".js", + ) ); - const { metafile } = bundle; + const { metafile, outputFiles } = bundle; const promises: Promise[] = []; - for (const file of bundle.outputFiles) { + for (const file of outputFiles) { const { text } = file; let route = file.path.replace(/^.*!/, "").replaceAll("\\", "/"); const { inputs } = UNWRAP(metafile.outputs["out!" + route]); @@ -63,8 +71,8 @@ export async function bundleClientJavaScript( // Register non-chunks as script entries. const chunk = route.startsWith("/js/c."); if (!chunk) { - const key = hot.getScriptId(path.resolve(sources[0])); - route = "/js/" + key + ".js"; + const key = hot.getScriptId(path.resolve(sources[sources.length - 1])); + route = "/js/" + key.replace(/\.client\.tsx?/, ".js"); incr.put({ sources, kind: "script", @@ -123,27 +131,7 @@ export async function bundleServerJavaScript( "$views": viewSource, }), projectRelativeResolution(), - { - name: "marko via build cache", - setup(b) { - b.onLoad( - { filter: /\.marko$/ }, - async ({ path: file }) => { - const key = path.relative(hot.projectRoot, file) - .replaceAll("\\", "/"); - const cacheEntry = incr.out.serverMarko.get(key); - if (!cacheEntry) { - throw new Error("Marko file not in cache: " + file); - } - return ({ - loader: "ts", - contents: cacheEntry.src, - resolveDir: path.dirname(file), - }); - }, - ); - }, - }, + markoViaBuildCache(incr), { name: "replace client references", setup(b) { @@ -168,6 +156,9 @@ export async function bundleServerJavaScript( }, }, ]; + const pkg = await fs.readJson("package.json") as { + dependencies: Record; + }; const { metafile, outputFiles } = await esbuild.build({ bundle: true, chunkNames: "c.[hash]", @@ -186,6 +177,8 @@ export async function bundleServerJavaScript( jsx: "automatic", jsxImportSource: "#ssr", jsxDev: false, + external: Object.keys(pkg.dependencies) + .filter((x) => !x.startsWith("@paperclover")), }); const files: Record = {}; @@ -279,6 +272,29 @@ export async function finalizeServerJavaScript( }); } +function markoViaBuildCache(incr: Incremental): esbuild.Plugin { + return { + name: "marko via build cache", + setup(b) { + b.onLoad( + { filter: /\.marko$/ }, + async ({ path: file }) => { + const key = path.relative(hot.projectRoot, file) + .replaceAll("\\", "/"); + const cacheEntry = incr.out.serverMarko.get(key); + if (!cacheEntry) { + throw new Error("Marko file not in cache: " + file); + } + return ({ + loader: "ts", + contents: cacheEntry.src, + resolveDir: path.dirname(file), + }); + }, + ); + }, + }; +} import * as esbuild from "esbuild"; import * as path from "node:path"; import process from "node:process"; diff --git a/framework/engine/marko-runtime.ts b/framework/engine/marko-runtime.ts index e063754..477847f 100644 --- a/framework/engine/marko-runtime.ts +++ b/framework/engine/marko-runtime.ts @@ -52,7 +52,6 @@ export const dynamicTag = ( if (typeof tag === "function") { clover: { const unwrapped = (tag as any).unwrapped; - console.log({ tag, unwrapped }); if (unwrapped) { tag = unwrapped; break clover; @@ -130,7 +129,7 @@ export function escapeXML(input: unknown) { ) { throw new Error( `Unexpected object in template placeholder: '` + - util.inspect({ name: "clover" }) + "'. " + + engine.inspect({ name: "clover" }) + "'. " + `To emit a literal '[object Object]', use \${String(value)}`, ); } @@ -145,4 +144,3 @@ import * as engine from "./ssr.ts"; import type { ServerRenderer } from "marko/html/template"; import { type Accessor } from "marko/common/types"; import * as marko from "#marko/html"; -import * as util from "node:util"; diff --git a/framework/generate.ts b/framework/generate.ts index f2c9812..53c2fff 100644 --- a/framework/generate.ts +++ b/framework/generate.ts @@ -8,9 +8,9 @@ export function main() { successText, failureText: () => "sitegen FAIL", }, async (spinner) => { - const incr = Incremental.fromDisk(); - await incr.statAllFiles(); - // const incr = new Incremental(); + // const incr = Incremental.fromDisk(); + // await incr.statAllFiles(); + const incr = new Incremental(); const result = await sitegen(spinner, incr); incr.toDisk(); // Allows picking up this state again return result; @@ -122,7 +122,6 @@ export async function sitegen( } } } - scripts = scripts.filter(({ file }) => !file.match(/\.client\.[tj]sx?/)); const globalCssPath = join("global.css"); // TODO: make sure that `static` and `pages` does not overlap @@ -311,8 +310,12 @@ export async function sitegen( maxJobs: 2, }); viewQueue.addMany(neededViews); - await pageQueue.done({ method: "stop" }); - await viewQueue.done({ method: "stop" }); + const pageAndViews = [ + pageQueue.done({ method: "stop" }), + viewQueue.done({ method: "stop" }), + ]; + await Promise.allSettled(pageAndViews); + await Promise.all(pageAndViews); status.format = spinnerFormat; // -- bundle server javascript (backend and views) -- diff --git a/framework/hot.ts b/framework/hot.ts index a60ff6f..b375e84 100644 --- a/framework/hot.ts +++ b/framework/hot.ts @@ -63,7 +63,7 @@ Module.prototype._compile = function ( if (shouldTrackPath(filename)) { const cssImportsMaybe: string[] = []; const imports: string[] = []; - for (const { filename: file } of this.children) { + for (const { filename: file, cloverClientRefs } of this.children) { if (file.endsWith(".css")) cssImportsMaybe.push(file); else { const child = fileStats.get(file); @@ -71,6 +71,10 @@ Module.prototype._compile = function ( const { cssImportsRecursive } = child; if (cssImportsRecursive) cssImportsMaybe.push(...cssImportsRecursive); imports.push(file); + if (cloverClientRefs && cloverClientRefs.length > 0) { + (this.cloverClientRefs ??= []) + .push(...cloverClientRefs); + } } } fileStats.set(filename, { diff --git a/framework/incremental.ts b/framework/incremental.ts index 1c87544..7846fa6 100644 --- a/framework/incremental.ts +++ b/framework/incremental.ts @@ -148,7 +148,7 @@ export class Incremental { for (const key of map.keys()) { if (!this.round.referenced.has(`${kind}\0${key}`)) { unreferenced.push({ kind: kind as ArtifactKind, key }); - this.out[kind as ArtifactKind].delete(key); + // this.out[kind as ArtifactKind].delete(key); } } } diff --git a/framework/lib/assets.ts b/framework/lib/assets.ts index 2c24e1d..bc55963 100644 --- a/framework/lib/assets.ts +++ b/framework/lib/assets.ts @@ -11,7 +11,6 @@ export async function reload() { fs.readFile(path.join(import.meta.dirname, "static.json"), "utf8"), fs.readFile(path.join(import.meta.dirname, "static.blob")), ]); - console.log("new buffer loaded"); assets = { map: JSON.parse(map), buf, @@ -110,7 +109,6 @@ function assetInner(c: Context, asset: BuiltAsset, status: StatusCode) { } process.on("message", (msg: any) => { - console.log({ msg }); if (msg?.type === "clover.assets.reload") reload(); }); diff --git a/framework/watch.ts b/framework/watch.ts index 2621b81..24ff96e 100644 --- a/framework/watch.ts +++ b/framework/watch.ts @@ -58,8 +58,8 @@ export async function main() { successText: generate.successText, failureText: () => "sitegen FAIL", }, async (spinner) => { - console.log("---"); - console.log( + console.info("---"); + console.info( "Updated" + (changed.length === 1 ? " " + changed[0] diff --git a/package-lock.json b/package-lock.json index 5a90bec..27bf157 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "@hono/node-server": "^1.14.3", "@mdx-js/mdx": "^3.1.0", "@paperclover/console": "git+https://git.paperclover.net/clo/console.git", + "codemirror": "^6.0.1", + "devalue": "^5.1.1", "esbuild": "^0.25.5", "hls.js": "^1.6.5", "hono": "^4.7.11", @@ -404,6 +406,87 @@ "node": ">=6.9.0" } }, + "node_modules/@codemirror/autocomplete": { + "version": "6.18.6", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz", + "integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.17.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz", + "integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==", + "license": "MIT", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.4.0", + "@codemirror/view": "^6.27.0", + "@lezer/common": "^1.1.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.1.tgz", + "integrity": "sha512-5kS1U7emOGV84vxC+ruBty5sUgcD0te6dyupyRVG2zaSjhTDM73LhVKUtVwiqSe6QwmEoA4SCiU8AKPFyumAWQ==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.23.0", + "@lezer/common": "^1.1.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz", + "integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.35.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.5.11", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz", + "integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz", + "integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==", + "license": "MIT", + "dependencies": { + "@marijn/find-cluster-break": "^1.0.0" + } + }, + "node_modules/@codemirror/view": { + "version": "6.37.2", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.2.tgz", + "integrity": "sha512-XD3LdgQpxQs5jhOOZ2HRVT+Rj59O4Suc7g2ULvZ+Yi8eCkickrkZ5JFuoDhs2ST1mNI5zSsNYgR3NGa4OUrbnw==", + "license": "MIT", + "dependencies": { + "@codemirror/state": "^6.5.0", + "crelt": "^1.0.6", + "style-mod": "^4.1.0", + "w3c-keyname": "^2.2.4" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", @@ -864,6 +947,30 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lezer/common": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz", + "integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==", + "license": "MIT" + }, + "node_modules/@lezer/highlight": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz", + "integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz", + "integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==", + "license": "MIT", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, "node_modules/@luxass/strip-json-comments": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@luxass/strip-json-comments/-/strip-json-comments-1.4.0.tgz", @@ -873,6 +980,12 @@ "node": ">=18" } }, + "node_modules/@marijn/find-cluster-break": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz", + "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", + "license": "MIT" + }, "node_modules/@marko/compiler": { "version": "5.39.21", "resolved": "https://registry.npmjs.org/@marko/compiler/-/compiler-5.39.21.tgz", @@ -1458,6 +1571,21 @@ "node": ">=8" } }, + "node_modules/codemirror": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "license": "MIT", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } + }, "node_modules/collapse-white-space": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz", @@ -1537,6 +1665,12 @@ } } }, + "node_modules/crelt": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", + "integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -1605,6 +1739,12 @@ "node": ">=6" } }, + "node_modules/devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "license": "MIT" + }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -3748,6 +3888,12 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/style-mod": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz", + "integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==", + "license": "MIT" + }, "node_modules/style-to-js": { "version": "1.1.16", "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.16.tgz", @@ -4020,6 +4166,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 565989d..2efd584 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,8 @@ "@hono/node-server": "^1.14.3", "@mdx-js/mdx": "^3.1.0", "@paperclover/console": "git+https://git.paperclover.net/clo/console.git", + "codemirror": "^6.0.1", + "devalue": "^5.1.1", "esbuild": "^0.25.5", "hls.js": "^1.6.5", "hono": "^4.7.11", diff --git a/src/q+a/backend.ts b/src/q+a/backend.ts index ccd36d5..ce00d69 100644 --- a/src/q+a/backend.ts +++ b/src/q+a/backend.ts @@ -127,9 +127,9 @@ app.get("/q+a/:id", async (c, next) => { const question = Question.getByDate(timestamp); if (!question) return next(); - // if (image) { - // return getQuestionImage(question, c.req.method === "HEAD"); - // } + if (image) { + return getQuestionImage(question, c.req.method === "HEAD"); + } return renderView(c, "q+a/permalink", { question }); }); @@ -193,11 +193,6 @@ app.get("/q+a/things/random", async (c) => { c.res = await renderView(c, "q+a/things-random", {}); }); -// 404 -app.get("/q+a/*", async (c) => { - return serveAsset(c, "/q+a/404", 404); -}); - async function questionFailure( c: Context, status: ContentfulStatusCode, @@ -229,5 +224,5 @@ import { } from "./models/PendingQuestion.ts"; import { Question, QuestionType } from "./models/Question.ts"; import { renderView } from "#sitegen/view"; -// import { getQuestionImage } from "./question_image"; +import { getQuestionImage } from "./image.tsx"; import { formatQuestionId, questionIdToTimestamp } from "./format.ts"; diff --git a/src/q+a/clover-markdown.tsx b/src/q+a/clover-markdown.tsx index 674ef48..426051e 100644 --- a/src/q+a/clover-markdown.tsx +++ b/src/q+a/clover-markdown.tsx @@ -211,7 +211,7 @@ function renderNode(node: string | ASTNode | ASTNode[]): any { if (typeof node === "string") { return node; } else if (Array.isArray(node)) { - return node.flatMap((item) => renderNode(item)); + return node.map((item) => renderNode(item)); } else if (node.type === "text") { return node.content; } else { diff --git a/src/q+a/header.client.ts b/src/q+a/header.client.ts index 8335b71..0abe95f 100644 --- a/src/q+a/header.client.ts +++ b/src/q+a/header.client.ts @@ -1,4 +1,12 @@ const h1 = document.querySelector("h1")!; +const key = "net.paperclover.q+a.header"; +const state = localStorage?.getItem(key); +if (state === "detrevni ton") h1.classList.toggle("invert"); h1.addEventListener("click", () => { h1.classList.toggle("invert"); + localStorage?.setItem( + key, + (localStorage.getItem?.(key) ?? "not inverted") + .split("").reverse().join(""), + ); }); diff --git a/src/q+a/image.tsx b/src/q+a/image.tsx index 956edb4..dac9a54 100644 --- a/src/q+a/image.tsx +++ b/src/q+a/image.tsx @@ -5,14 +5,13 @@ const cacheImageDir = path.resolve(".clover/question_images"); const getBrowser = RefCountedExpirable( () => puppeteer.launch({ - // headless: false, args: ["--no-sandbox", "--disable-setuid-sandbox"], }), (b) => b.close(), ); export async function renderQuestionImage(question: Question) { - const html = await renderViewToString("q+a/embed-image", { question }); + const html = await renderViewToString("q+a/image-embed", { question }); // this browser session will be reused if multiple images are generated // either at the same time or within a 5-minute time span. the dispose diff --git a/src/q+a/pages/admin.q+a.marko b/src/q+a/pages/admin.q+a.marko index 7069080..fee66aa 100644 --- a/src/q+a/pages/admin.q+a.marko +++ b/src/q+a/pages/admin.q+a.marko @@ -6,6 +6,9 @@ export const meta: Metadata = { title: "paper clover q+a", description: "ask clover a question", }; +export const regenerate = { + manual: true, +}; 0)> diff --git a/src/q+a/pages/q+a.404.marko b/src/q+a/pages/q+a.404.marko index 767f558..ecf69f6 100644 --- a/src/q+a/pages/q+a.404.marko +++ b/src/q+a/pages/q+a.404.marko @@ -4,6 +4,7 @@ export const meta: Metadata = { };

sound the alarms

+

this page doesn't exist

return to the questions list

diff --git a/src/q+a/pages/q+a.marko b/src/q+a/pages/q+a.marko index 0e1ede7..37fdfe7 100644 --- a/src/q+a/pages/q+a.marko +++ b/src/q+a/pages/q+a.marko @@ -1,4 +1,7 @@ export * as layout from "../layout.tsx"; +export const regenerate = { + manual: true, +}; export interface Input { admin?: boolean; @@ -11,7 +14,7 @@ export const meta: Metadata = { - + diff --git a/src/q+a/scripts/editor.client.tsx b/src/q+a/scripts/editor.client.tsx index c4597d3..139ba0e 100644 --- a/src/q+a/scripts/editor.client.tsx +++ b/src/q+a/scripts/editor.client.tsx @@ -1,9 +1,8 @@ -import { basicSetup, EditorState, EditorView } from "codemirror"; +import { EditorState } from "@codemirror/state"; +import { basicSetup, EditorView } from "codemirror"; import { ssrSync } from "#ssr"; -// @ts-ignore -import type { ScriptPayload } from "../views/editor.marko"; -// @ts-ignore -import QuestionRender from "@/q+a/components/Question.marko"; +import { ScriptPayload } from "@/q+a/view/editor.marko"; +import QuestionRender from "@/q+a/tags/question.marko"; declare const payload: ScriptPayload; const date = new Date(payload.date); @@ -21,9 +20,11 @@ function updatePreview(text: string) { type: payload.type, date, }} + editor />, ).text; } +updatePreview(payload.text); const startState = EditorState.create({ doc: payload.text, diff --git a/src/q+a/tags/question.marko b/src/q+a/tags/question.marko index 49ea82d..e8ce4e8 100644 --- a/src/q+a/tags/question.marko +++ b/src/q+a/tags/question.marko @@ -2,12 +2,13 @@ export interface Input { question: Question; admin?: boolean; + editor?: boolean; } // 2024-12-31 05:00:00 EST export const transitionDate = 1735639200000; - + <${"e-"} @@ -30,8 +31,11 @@ export const transitionDate = 1735639200000; // this singleton script will make all the '