autoblogger 0.1.4 → 0.1.5
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/dist/ui.js +108 -32
- package/dist/ui.js.map +1 -1
- package/dist/ui.mjs +109 -33
- package/dist/ui.mjs.map +1 -1
- package/package.json +1 -1
package/dist/ui.js
CHANGED
|
@@ -41,6 +41,10 @@ __export(ui_exports, {
|
|
|
41
41
|
});
|
|
42
42
|
module.exports = __toCommonJS(ui_exports);
|
|
43
43
|
|
|
44
|
+
// src/ui/dashboard.tsx
|
|
45
|
+
var import_react19 = require("react");
|
|
46
|
+
var import_lucide_react13 = require("lucide-react");
|
|
47
|
+
|
|
44
48
|
// src/ui/context.tsx
|
|
45
49
|
var import_react = require("react");
|
|
46
50
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
@@ -6798,8 +6802,9 @@ function AutoResizeTextarea({
|
|
|
6798
6802
|
}
|
|
6799
6803
|
);
|
|
6800
6804
|
}
|
|
6801
|
-
function EditorPage({ slug }) {
|
|
6802
|
-
const { apiBasePath, styles, fields, navigate, basePath,
|
|
6805
|
+
function EditorPage({ slug, onEditorStateChange: onEditorStateChangeProp }) {
|
|
6806
|
+
const { apiBasePath, styles, fields, navigate, basePath, onRegisterEditHandler } = useDashboardContext();
|
|
6807
|
+
const onEditorStateChange = onEditorStateChangeProp;
|
|
6803
6808
|
const [post, setPost] = (0, import_react16.useState)({
|
|
6804
6809
|
title: "",
|
|
6805
6810
|
subtitle: "",
|
|
@@ -6905,7 +6910,7 @@ function EditorPage({ slug }) {
|
|
|
6905
6910
|
return () => {
|
|
6906
6911
|
onEditorStateChange(null);
|
|
6907
6912
|
};
|
|
6908
|
-
}, [hasUnsavedChanges, post.status, savingAs, post.title, post.subtitle, post.markdown, onEditorStateChange]);
|
|
6913
|
+
}, [hasUnsavedChanges, post.status, savingAs, post.title, post.subtitle, post.markdown, onEditorStateChange, savePost, handlePublish]);
|
|
6909
6914
|
(0, import_react16.useEffect)(() => {
|
|
6910
6915
|
if (!onRegisterEditHandler) return;
|
|
6911
6916
|
const handleEdit = (edit) => {
|
|
@@ -7000,29 +7005,79 @@ function EditorPage({ slug }) {
|
|
|
7000
7005
|
hasTriggeredGeneration.current = true;
|
|
7001
7006
|
setGenerating(true);
|
|
7002
7007
|
const wordCount = urlParams.length ? parseInt(urlParams.length) : 500;
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7008
|
+
if (typeof window !== "undefined") {
|
|
7009
|
+
window.history.replaceState({}, "", `${basePath}/editor`);
|
|
7010
|
+
}
|
|
7011
|
+
const runGenerate = async () => {
|
|
7012
|
+
try {
|
|
7013
|
+
const res = await fetch(`${apiBasePath}/ai/generate`, {
|
|
7014
|
+
method: "POST",
|
|
7015
|
+
headers: { "Content-Type": "application/json" },
|
|
7016
|
+
body: JSON.stringify({
|
|
7017
|
+
prompt: urlParams.idea,
|
|
7018
|
+
wordCount,
|
|
7019
|
+
model: urlParams.model
|
|
7020
|
+
})
|
|
7021
|
+
});
|
|
7022
|
+
if (!res.ok) {
|
|
7023
|
+
const error = await res.json().catch(() => ({ error: "Generation failed" }));
|
|
7024
|
+
console.error("Generation failed:", error);
|
|
7025
|
+
return;
|
|
7026
|
+
}
|
|
7027
|
+
const reader = res.body?.getReader();
|
|
7028
|
+
if (!reader) return;
|
|
7029
|
+
const decoder = new TextDecoder();
|
|
7030
|
+
let fullContent = "";
|
|
7031
|
+
while (true) {
|
|
7032
|
+
const { done, value } = await reader.read();
|
|
7033
|
+
if (done) break;
|
|
7034
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
7035
|
+
const lines2 = chunk.split("\n");
|
|
7036
|
+
for (const line of lines2) {
|
|
7037
|
+
if (line.startsWith("data: ")) {
|
|
7038
|
+
const data = line.slice(6);
|
|
7039
|
+
if (data === "[DONE]") continue;
|
|
7040
|
+
try {
|
|
7041
|
+
const parsed = JSON.parse(data);
|
|
7042
|
+
if (parsed.text) {
|
|
7043
|
+
fullContent += parsed.text;
|
|
7044
|
+
setPost((prev) => ({ ...prev, markdown: fullContent }));
|
|
7045
|
+
}
|
|
7046
|
+
} catch {
|
|
7047
|
+
}
|
|
7048
|
+
}
|
|
7049
|
+
}
|
|
7050
|
+
}
|
|
7051
|
+
const lines = fullContent.trim().split("\n");
|
|
7052
|
+
let title = "";
|
|
7053
|
+
let subtitle = "";
|
|
7054
|
+
let markdownStart = 0;
|
|
7055
|
+
if (lines[0]?.startsWith("# ")) {
|
|
7056
|
+
title = lines[0].slice(2).trim();
|
|
7057
|
+
markdownStart = 1;
|
|
7058
|
+
const nextLine = lines[1]?.trim();
|
|
7059
|
+
if (nextLine) {
|
|
7060
|
+
const italicMatch = nextLine.match(/^\*(.+)\*$/) || nextLine.match(/^_(.+)_$/);
|
|
7061
|
+
if (italicMatch) {
|
|
7062
|
+
subtitle = italicMatch[1];
|
|
7063
|
+
markdownStart = 2;
|
|
7064
|
+
}
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
7067
|
+
const remainingMarkdown = lines.slice(markdownStart).join("\n").trim();
|
|
7015
7068
|
setPost((prev) => ({
|
|
7016
7069
|
...prev,
|
|
7017
|
-
title:
|
|
7018
|
-
subtitle:
|
|
7019
|
-
markdown:
|
|
7070
|
+
title: title || prev.title,
|
|
7071
|
+
subtitle: subtitle || prev.subtitle,
|
|
7072
|
+
markdown: remainingMarkdown || fullContent
|
|
7020
7073
|
}));
|
|
7074
|
+
} catch (err) {
|
|
7075
|
+
console.error("Generation error:", err);
|
|
7076
|
+
} finally {
|
|
7077
|
+
setGenerating(false);
|
|
7021
7078
|
}
|
|
7022
|
-
}
|
|
7023
|
-
|
|
7024
|
-
window.history.replaceState({}, "", `${basePath}/editor`);
|
|
7025
|
-
}
|
|
7079
|
+
};
|
|
7080
|
+
runGenerate();
|
|
7026
7081
|
}
|
|
7027
7082
|
}, [urlParams, slug, loading, apiBasePath, basePath]);
|
|
7028
7083
|
const fetchRevisions = (0, import_react16.useCallback)(async () => {
|
|
@@ -7065,7 +7120,7 @@ function EditorPage({ slug }) {
|
|
|
7065
7120
|
setPreviewingRevision(null);
|
|
7066
7121
|
await savePost();
|
|
7067
7122
|
}, [previewingRevision]);
|
|
7068
|
-
const savePost = async (silent = false) => {
|
|
7123
|
+
const savePost = (0, import_react16.useCallback)(async (silent = false) => {
|
|
7069
7124
|
if (!silent) {
|
|
7070
7125
|
setSaving(true);
|
|
7071
7126
|
setSavingAs("draft");
|
|
@@ -7102,8 +7157,8 @@ function EditorPage({ slug }) {
|
|
|
7102
7157
|
setSavingAs(null);
|
|
7103
7158
|
}
|
|
7104
7159
|
}
|
|
7105
|
-
};
|
|
7106
|
-
const handlePublish = async () => {
|
|
7160
|
+
}, [post.id, post.title, post.subtitle, post.slug, post.markdown, post.status, post.tags, apiBasePath, fields, navigate]);
|
|
7161
|
+
const handlePublish = (0, import_react16.useCallback)(async () => {
|
|
7107
7162
|
if (!confirm("Publish this essay?")) return;
|
|
7108
7163
|
setSaving(true);
|
|
7109
7164
|
setSavingAs("published");
|
|
@@ -7127,7 +7182,7 @@ function EditorPage({ slug }) {
|
|
|
7127
7182
|
setSaving(false);
|
|
7128
7183
|
setSavingAs(null);
|
|
7129
7184
|
}
|
|
7130
|
-
};
|
|
7185
|
+
}, [post.id, post.title, apiBasePath, fields, navigate]);
|
|
7131
7186
|
const handleUnpublish = async () => {
|
|
7132
7187
|
if (!confirm("Unpublish this essay?")) return;
|
|
7133
7188
|
await fetch(`${apiBasePath}/posts/${post.id}`, {
|
|
@@ -7230,7 +7285,7 @@ function EditorPage({ slug }) {
|
|
|
7230
7285
|
className: `${styles.subtitle} w-full bg-transparent border-none outline-none placeholder-gray-300 dark:placeholder-gray-700 ${generating || previewingRevision ? "opacity-60 cursor-not-allowed" : ""}`
|
|
7231
7286
|
}
|
|
7232
7287
|
),
|
|
7233
|
-
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "!mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `${styles.byline} underline ${generating ? "opacity-60" : ""}`, children: "Author" }) })
|
|
7288
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "!mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: `${styles.byline} underline ${generating ? "opacity-60" : ""}`, children: session?.user?.name || session?.user?.email || "Author" }) })
|
|
7234
7289
|
] }),
|
|
7235
7290
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "mt-8", children: generating && !post.markdown ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "space-y-3", children: [
|
|
7236
7291
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Skeleton2, { className: "h-4 w-full" }),
|
|
@@ -9435,8 +9490,14 @@ function DashboardLayout({
|
|
|
9435
9490
|
theme,
|
|
9436
9491
|
navbarRightSlot
|
|
9437
9492
|
}) {
|
|
9438
|
-
const { basePath, currentPath, navigate } = useDashboardContext();
|
|
9493
|
+
const { basePath, currentPath, navigate, onEditorStateChange } = useDashboardContext();
|
|
9494
|
+
const [editorState, setEditorState] = (0, import_react19.useState)(null);
|
|
9439
9495
|
const editorSlug = currentPath.startsWith("/editor/") ? currentPath.replace("/editor/", "") : currentPath === "/editor" ? void 0 : void 0;
|
|
9496
|
+
const isEditorPage = currentPath.startsWith("/editor");
|
|
9497
|
+
const handleEditorStateChange = (state) => {
|
|
9498
|
+
setEditorState(state);
|
|
9499
|
+
onEditorStateChange?.(state);
|
|
9500
|
+
};
|
|
9440
9501
|
useDashboardKeyboard({
|
|
9441
9502
|
basePath,
|
|
9442
9503
|
onToggleView: onToggleView ? () => onToggleView(currentPath, editorSlug) : void 0,
|
|
@@ -9451,6 +9512,21 @@ function DashboardLayout({
|
|
|
9451
9512
|
if (currentPath !== "/" && currentPath !== "") navigate("/");
|
|
9452
9513
|
}
|
|
9453
9514
|
});
|
|
9515
|
+
const rightSlotWithSave = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
|
|
9516
|
+
isEditorPage && editorState && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
9517
|
+
"button",
|
|
9518
|
+
{
|
|
9519
|
+
type: "button",
|
|
9520
|
+
onClick: () => editorState.onSave("draft"),
|
|
9521
|
+
disabled: !editorState.hasUnsavedChanges || !!editorState.savingAs,
|
|
9522
|
+
className: "w-9 h-9 rounded-md border border-border hover:bg-accent text-muted-foreground flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed",
|
|
9523
|
+
"aria-label": "Save",
|
|
9524
|
+
title: editorState.hasUnsavedChanges ? "Save changes (\u2318S)" : "No unsaved changes",
|
|
9525
|
+
children: editorState.savingAs ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react13.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_lucide_react13.Save, { className: "h-4 w-4" })
|
|
9526
|
+
}
|
|
9527
|
+
),
|
|
9528
|
+
navbarRightSlot
|
|
9529
|
+
] });
|
|
9454
9530
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "min-h-screen bg-background flex flex-col", children: [
|
|
9455
9531
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
9456
9532
|
Navbar,
|
|
@@ -9458,18 +9534,18 @@ function DashboardLayout({
|
|
|
9458
9534
|
onSignOut,
|
|
9459
9535
|
onThemeToggle,
|
|
9460
9536
|
theme,
|
|
9461
|
-
rightSlot:
|
|
9537
|
+
rightSlot: rightSlotWithSave
|
|
9462
9538
|
}
|
|
9463
9539
|
),
|
|
9464
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("main", { className: "flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DashboardRouter, { path: currentPath }) })
|
|
9540
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("main", { className: "flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DashboardRouter, { path: currentPath, onEditorStateChange: handleEditorStateChange }) })
|
|
9465
9541
|
] });
|
|
9466
9542
|
}
|
|
9467
|
-
function DashboardRouter({ path }) {
|
|
9543
|
+
function DashboardRouter({ path, onEditorStateChange }) {
|
|
9468
9544
|
const pathWithoutQuery = path.split("?")[0];
|
|
9469
9545
|
if (pathWithoutQuery === "/" || pathWithoutQuery === "") return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(WriterDashboard, {});
|
|
9470
9546
|
if (pathWithoutQuery.startsWith("/editor")) {
|
|
9471
9547
|
const slug = pathWithoutQuery.replace("/editor/", "").replace("/editor", "");
|
|
9472
|
-
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EditorPage, { slug: slug || void 0 }, path);
|
|
9548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EditorPage, { slug: slug || void 0, onEditorStateChange }, path);
|
|
9473
9549
|
}
|
|
9474
9550
|
if (pathWithoutQuery.startsWith("/settings")) return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SettingsPage, { subPath: pathWithoutQuery.replace("/settings", "") });
|
|
9475
9551
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className: "max-w-4xl mx-auto px-6 py-8", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("p", { className: "text-muted-foreground", children: [
|