MOdular
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 8s

This commit is contained in:
2026-05-05 22:44:16 +02:00
parent fb8c5eabd2
commit e7e3def5ed
13 changed files with 178 additions and 156 deletions

View File

@@ -1,20 +1,66 @@
// src/editor.js
import { $, isFunc, h } from "./sigpro.js";
import { $ as $2, isFunc as isFunc2, h as h2 } from "./sigpro.js";
// src/helpers.js
// src/sigpro-ui.js
import { $, watch, h, mount, when, each, isFunc } from "./sigpro.js";
var val = (val2) => typeof val2 === "function" ? val2() : val2;
var cls = (...classes) => classes.filter(Boolean).join(" ").trim();
var currentLocale = $("en");
var c1 = (tag, cls2) => (p) => h(tag, { ...p, class: `${cls2} ${p?.class || ""}`.trim() });
var c2 = (tag, cls2) => (p, c) => h(tag, { ...p, class: `${cls2} ${p?.class || ""}`.trim() }, c);
var ct = (tag, cls2, type) => (p) => h(tag, { type, ...p, class: `${cls2} ${p?.class || ""}`.trim() });
var Alert = c2("div", "alert");
var AvatarGroup = c2("div", "avatar-group -space-x-6");
var Badge = c2("span", "badge");
var Breadcrumbs = c2("div", "breadcrumbs");
var Button = c2("button", "btn");
var Card = c2("div", "card");
var CardTitle = c2("div", "card-title");
var CardBody = c2("div", "card-body");
var CardActions = c2("div", "card-actions");
var Carousel = c2("div", "carousel");
var CarouselItem = c2("div", "carousel-item");
var Chat = c2("div", "chat");
var ChatBubble = c2("div", "chat-bubble");
var ChatFooter = c2("div", "chat-footer");
var ChatHeader = c2("div", "chat-header");
var Checkbox = ct("input", "checkbox", "checkbox");
var Drawer = c2("div", "drawer");
var DrawerContent = c2("div", "drawer-content");
var DrawerSide = c2("div", "drawer-side");
var Divider = c1("div", "divider");
var Dropdown = c2("div", "dropdown");
var Kbd = c2("kbd", "kbd");
var List = c2("ul", "list");
var Loading = c2("span", "loading loading-spinner");
var Navbar = c2("div", "navbar");
var Progress = c1("progress", "progress");
var Radio = ct("input", "radio", "radio");
var Range = ct("input", "range", "range");
var Rating = c2("div", "rating");
var Skeleton = c1("div", "skeleton");
var SkeletonText = c1("span", "skeleton skeleton-text");
var Stack = c2("div", "stack");
var Stats = c2("div", "stats shadow");
var Steps = c2("ul", "steps");
var Swap = c2("label", "swap");
var SwapOn = c2("div", "swap-on");
var SwapOff = c2("div", "swap-off");
var Table = c2("table", "table");
var Textarea = c1("textarea", "textarea");
var Timeline = c2("ul", "timeline");
var Toggle = ct("input", "toggle", "checkbox");
// src/editor.js
var Editor = (p) => {
const { value, class: extraClass } = p;
let editorRef = null;
let savedRange = null;
const isSource = $(false);
const source = $("");
const count = $(0);
const refreshTick = $(0);
const showEmojis = $(false);
const isSource = $2(false);
const source = $2("");
const count = $2(0);
const refreshTick = $2(0);
const showEmojis = $2(false);
const emojis = ["\uD83D\uDE00", "\uD83D\uDE0A", "\uD83D\uDE09", "\uD83E\uDDD0", "\uD83D\uDE2E", "\uD83E\uDD14", "\uD83D\uDE05", "\uD83D\uDE02", "\uD83D\uDE0D", "\uD83D\uDE18", "\uD83E\uDD70", "\uD83D\uDC4D", "\uD83D\uDC4E", "\uD83D\uDC4C", "\uD83E\uDD1D", "\uD83E\uDD1E", "\uD83D\uDC4B", "\uD83D\uDC4F", "\uD83D\uDE4C", "\uD83D\uDE4F", "\uD83D\uDCAA", "☝️", "\uD83D\uDC47", "\uD83D\uDC48", "\uD83D\uDC49", "\uD83D\uDD95", "✅", "⚠️", "\uD83D\uDE80", "\uD83D\uDCE2", "✉️", "❤️"];
const saveSelection = () => {
const sel = window.getSelection();
@@ -37,7 +83,7 @@ var Editor = (p) => {
if (!editorRef)
return;
const html = editorRef.innerHTML;
if (isFunc(value))
if (isFunc2(value))
value(html);
else
p.onchange?.(html);
@@ -97,63 +143,63 @@ var Editor = (p) => {
return false;
}
};
const toolbar = h("div", { class: "flex flex-wrap items-center gap-1 p-2 border-b border-base-300 bg-base-200 sticky top-0 z-20" }, [
h("div", { class: "flex flex-wrap gap-1 flex-1 items-center" }, [
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("bold") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("bold") }, h("span", { class: "icon-[lucide--bold]" })),
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("italic") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("italic") }, h("span", { class: "icon-[lucide--italic]" })),
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("underline") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("underline") }, h("span", { class: "icon-[lucide--underline]" })),
h("input", { type: "color", class: "w-5 h-5 p-0 border-0 bg-transparent cursor-pointer", oninput: (e) => exec("foreColor", e.target.value) }),
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h("button", {
const toolbar = h2("div", { class: "flex flex-wrap items-center gap-1 p-2 border-b border-base-300 bg-base-200 sticky top-0 z-20" }, [
h2("div", { class: "flex flex-wrap gap-1 flex-1 items-center" }, [
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("bold") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("bold") }, h2("span", { class: "icon-[lucide--bold]" })),
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("italic") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("italic") }, h2("span", { class: "icon-[lucide--italic]" })),
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("underline") ? "btn-active bg-primary/20" : ""}`, onclick: () => exec("underline") }, h2("span", { class: "icon-[lucide--underline]" })),
h2("input", { type: "color", class: "w-5 h-5 p-0 border-0 bg-transparent cursor-pointer", oninput: (e) => exec("foreColor", e.target.value) }),
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h2("button", {
type: "button",
class: "btn btn-ghost btn-xs",
onclick: () => exec("justifyLeft")
}, h("span", { class: "icon-[lucide--align-left]" })),
h("button", {
}, h2("span", { class: "icon-[lucide--align-left]" })),
h2("button", {
type: "button",
class: "btn btn-ghost btn-xs",
onclick: () => exec("justifyCenter")
}, h("span", { class: "icon-[lucide--align-center]" })),
h("button", {
}, h2("span", { class: "icon-[lucide--align-center]" })),
h2("button", {
type: "button",
class: "btn btn-ghost btn-xs",
onclick: () => exec("justifyRight")
}, h("span", { class: "icon-[lucide--align-right]" })),
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertUnorderedList") }, h("span", { class: "icon-[lucide--list]" })),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertOrderedList") }, h("span", { class: "icon-[lucide--list-ordered]" })),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("outdent") }, h("span", { class: "icon-[lucide--indent-decrease]" })),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("indent") }, h("span", { class: "icon-[lucide--indent-increase]" })),
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("formatBlock", "BLOCKQUOTE") ? "btn-active" : ""}`, onclick: () => exec("formatBlock", queryState("formatBlock", "BLOCKQUOTE") ? "P" : "BLOCKQUOTE") }, h("span", { class: "icon-[lucide--quote]" })),
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => {
}, h2("span", { class: "icon-[lucide--align-right]" })),
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertUnorderedList") }, h2("span", { class: "icon-[lucide--list]" })),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("insertOrderedList") }, h2("span", { class: "icon-[lucide--list-ordered]" })),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("outdent") }, h2("span", { class: "icon-[lucide--indent-decrease]" })),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("indent") }, h2("span", { class: "icon-[lucide--indent-increase]" })),
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${queryState("formatBlock", "BLOCKQUOTE") ? "btn-active" : ""}`, onclick: () => exec("formatBlock", queryState("formatBlock", "BLOCKQUOTE") ? "P" : "BLOCKQUOTE") }, h2("span", { class: "icon-[lucide--quote]" })),
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => {
const url = window.prompt("URL:");
if (url)
exec("createLink", url);
} }, h("span", { class: "icon-[lucide--link]" })),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => {
const input = document.createElement("input");
input.type = "file";
input.onchange = (e) => handleUpload(e.target.files[0]);
input.click();
} }, h("span", { class: "icon-[lucide--paperclip]" })),
h("div", { class: "relative" }, [
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: (e) => {
} }, h2("span", { class: "icon-[lucide--link]" })),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => {
const input2 = document.createElement("input");
input2.type = "file";
input2.onchange = (e) => handleUpload(e.target.files[0]);
input2.click();
} }, h2("span", { class: "icon-[lucide--paperclip]" })),
h2("div", { class: "relative" }, [
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: (e) => {
e.stopPropagation();
saveSelection();
showEmojis(!showEmojis());
} }, h("span", { class: "icon-[lucide--smile]" })),
h("div", { class: "absolute top-full left-0 mt-1 p-2 bg-base-100 border border-base-300 shadow-xl rounded-box w-52 z-50 flex flex-wrap gap-1", style: () => showEmojis() ? "display:flex" : "display:none" }, emojis.map((emo) => h("span", { class: "cursor-pointer hover:bg-base-200 p-1 rounded text-lg", onclick: (e) => {
} }, h2("span", { class: "icon-[lucide--smile]" })),
h2("div", { class: "absolute top-full left-0 mt-1 p-2 bg-base-100 border border-base-300 shadow-xl rounded-box w-52 z-50 flex flex-wrap gap-1", style: () => showEmojis() ? "display:flex" : "display:none" }, emojis.map((emo) => h2("span", { class: "cursor-pointer hover:bg-base-200 p-1 rounded text-lg", onclick: (e) => {
e.stopPropagation();
exec("insertText", emo);
showEmojis(false);
} }, emo)))
]),
h("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("undo") }, h("span", { class: "icon-[lucide--undo-2]" })),
h("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("redo") }, h("span", { class: "icon-[lucide--redo-2]" }))
h2("span", { class: "w-px h-5 bg-base-300 mx-1" }),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("undo") }, h2("span", { class: "icon-[lucide--undo-2]" })),
h2("button", { type: "button", class: "btn btn-ghost btn-xs", onclick: () => exec("redo") }, h2("span", { class: "icon-[lucide--redo-2]" }))
]),
h("button", { type: "button", class: () => `btn btn-ghost btn-xs ${isSource() ? "btn-active" : ""}`, onclick: () => {
h2("button", { type: "button", class: () => `btn btn-ghost btn-xs ${isSource() ? "btn-active" : ""}`, onclick: () => {
if (!isSource())
source(editorRef?.innerHTML || "");
else if (editorRef) {
@@ -161,7 +207,7 @@ var Editor = (p) => {
notify();
}
isSource(!isSource());
} }, h("span", { class: "icon-[lucide--code-2]" }))
} }, h2("span", { class: "icon-[lucide--code-2]" }))
]);
if (typeof document !== "undefined" && !document.getElementById("editor-styles")) {
const style = document.createElement("style");
@@ -175,10 +221,10 @@ var Editor = (p) => {
`;
document.head.appendChild(style);
}
return h("div", { class: cls("border border-base-300 rounded-box bg-base-100 overflow-hidden shadow-sm flex flex-col", extraClass) }, [
return h2("div", { class: cls("border border-base-300 rounded-box bg-base-100 overflow-hidden shadow-sm flex flex-col", extraClass) }, [
toolbar,
h("div", { class: "relative flex-1 flex flex-col", onclick: () => showEmojis(false) }, [
h("div", {
h2("div", { class: "relative flex-1 flex flex-col", onclick: () => showEmojis(false) }, [
h2("div", {
ref: (el) => {
if (!editorRef && el) {
editorRef = el;
@@ -228,7 +274,7 @@ var Editor = (p) => {
handleUpload(e.dataTransfer.files[0]);
}
}),
h("textarea", {
h2("textarea", {
class: "w-full flex-1 min-h-[22rem] p-4 outline-none font-mono text-sm bg-base-200 border-0",
style: () => isSource() ? "" : "display:none",
value: source,
@@ -240,8 +286,8 @@ var Editor = (p) => {
}
})
]),
h("div", { class: "px-3 py-1 border-t border-base-300 bg-base-100/50 text-[10px] text-right text-base-content/60 italic" }, [
h("span", () => `${count()}`)
h2("div", { class: "px-3 py-1 border-t border-base-300 bg-base-100/50 text-[10px] text-right text-base-content/60 italic" }, [
h2("span", () => `${count()}`)
])
]);
};