@burdenoff/microfe-store 2026.720.2 → 2026.720.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/dist/components/MarkdownEditor.d.ts +12 -0
- package/dist/components/MarkdownEditor.js +117 -0
- package/dist/components/MarkdownEditor.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/pages/AdminStoresPage.js +203 -207
- package/dist/pages/AdminStoresPage.js.map +1 -1
- package/dist/pages/AdminSubmissionsQueuePage.js +85 -84
- package/dist/pages/AdminSubmissionsQueuePage.js.map +1 -1
- package/dist/pages/ProductDetailPage.js +94 -93
- package/dist/pages/ProductDetailPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface MarkdownEditorProps {
|
|
4
|
+
id?: string;
|
|
5
|
+
value: string;
|
|
6
|
+
onChange: (value: string) => void;
|
|
7
|
+
label?: ReactNode;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
rows?: number;
|
|
10
|
+
className?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const MarkdownEditor: FC<MarkdownEditorProps>;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { useMemo as e, useRef as t, useState as n } from "react";
|
|
2
|
+
import { Markdown as r } from "@burdenoff/fe-libs/shared/components";
|
|
3
|
+
import { Bold as i, Code as a, Italic as o, Link as s, List as c } from "lucide-react";
|
|
4
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
5
|
+
//#region src/components/MarkdownEditor.tsx
|
|
6
|
+
var d = (e, t, n = t) => {
|
|
7
|
+
let r = e.current;
|
|
8
|
+
if (!r) return;
|
|
9
|
+
let { selectionStart: i, selectionEnd: a, value: o } = r, s = o.slice(0, i), c = o.slice(i, a), l = o.slice(a);
|
|
10
|
+
r.value = `${s}${`${t}${c}${n}`}${l}`, r.focus();
|
|
11
|
+
let u = i + (c.length === 0 ? t.length : c.length + t.length);
|
|
12
|
+
r.setSelectionRange(u, u), r.dispatchEvent(new Event("input", { bubbles: !0 }));
|
|
13
|
+
}, f = (e, t) => {
|
|
14
|
+
let n = e.current;
|
|
15
|
+
if (!n) return;
|
|
16
|
+
let { selectionStart: r, selectionEnd: i, value: a } = n, o = a.slice(0, r), s = a.slice(r, i), c = a.slice(i), l = s.split("\n"), u = l.every((e) => e === "" || e.startsWith(t)) ? l.map((e) => e.startsWith(t) ? e.slice(t.length) : e).join("\n") : l.map((e) => `${t}${e}`).join("\n");
|
|
17
|
+
n.value = `${o}${u}${c}`, n.focus();
|
|
18
|
+
let d = r, f = r + u.length;
|
|
19
|
+
n.setSelectionRange(d, f), n.dispatchEvent(new Event("input", { bubbles: !0 }));
|
|
20
|
+
}, p = ({ id: p, value: m, onChange: h, label: g, placeholder: _, rows: v = 5, className: y = "" }) => {
|
|
21
|
+
let b = t(null), [x, S] = n("write"), C = (e) => `rounded-md px-2.5 py-1 text-xs font-medium transition-colors ${x === e ? "bg-surface-accent text-text-on-accent" : "text-text-secondary hover:bg-surface-hover hover:text-text-primary"}`, w = "inline-flex items-center justify-center rounded-md p-1.5 text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary", T = e(() => m, [m]);
|
|
22
|
+
return /* @__PURE__ */ u("div", {
|
|
23
|
+
className: `space-y-2 ${y}`,
|
|
24
|
+
children: [g && /* @__PURE__ */ l("label", {
|
|
25
|
+
htmlFor: p,
|
|
26
|
+
className: "block text-xs text-text-secondary",
|
|
27
|
+
children: g
|
|
28
|
+
}), /* @__PURE__ */ u("div", {
|
|
29
|
+
className: "overflow-hidden rounded-lg border border-border-default bg-surface-default",
|
|
30
|
+
children: [/* @__PURE__ */ u("div", {
|
|
31
|
+
className: "flex items-center justify-between border-b border-border-default px-2 py-1.5",
|
|
32
|
+
children: [/* @__PURE__ */ u("div", {
|
|
33
|
+
className: "flex items-center gap-1",
|
|
34
|
+
children: [/* @__PURE__ */ l("button", {
|
|
35
|
+
type: "button",
|
|
36
|
+
onClick: () => S("write"),
|
|
37
|
+
className: C("write"),
|
|
38
|
+
"aria-pressed": x === "write",
|
|
39
|
+
children: "Write"
|
|
40
|
+
}), /* @__PURE__ */ l("button", {
|
|
41
|
+
type: "button",
|
|
42
|
+
onClick: () => S("preview"),
|
|
43
|
+
className: C("preview"),
|
|
44
|
+
"aria-pressed": x === "preview",
|
|
45
|
+
children: "Preview"
|
|
46
|
+
})]
|
|
47
|
+
}), /* @__PURE__ */ u("div", {
|
|
48
|
+
className: "flex items-center gap-0.5",
|
|
49
|
+
"aria-label": "Markdown formatting",
|
|
50
|
+
children: [
|
|
51
|
+
/* @__PURE__ */ l("button", {
|
|
52
|
+
type: "button",
|
|
53
|
+
onClick: () => d(b, "**"),
|
|
54
|
+
className: w,
|
|
55
|
+
title: "Bold",
|
|
56
|
+
"aria-label": "Bold",
|
|
57
|
+
children: /* @__PURE__ */ l(i, { className: "size-3.5" })
|
|
58
|
+
}),
|
|
59
|
+
/* @__PURE__ */ l("button", {
|
|
60
|
+
type: "button",
|
|
61
|
+
onClick: () => d(b, "_"),
|
|
62
|
+
className: w,
|
|
63
|
+
title: "Italic",
|
|
64
|
+
"aria-label": "Italic",
|
|
65
|
+
children: /* @__PURE__ */ l(o, { className: "size-3.5" })
|
|
66
|
+
}),
|
|
67
|
+
/* @__PURE__ */ l("button", {
|
|
68
|
+
type: "button",
|
|
69
|
+
onClick: () => d(b, "[", "](url)"),
|
|
70
|
+
className: w,
|
|
71
|
+
title: "Link",
|
|
72
|
+
"aria-label": "Link",
|
|
73
|
+
children: /* @__PURE__ */ l(s, { className: "size-3.5" })
|
|
74
|
+
}),
|
|
75
|
+
/* @__PURE__ */ l("button", {
|
|
76
|
+
type: "button",
|
|
77
|
+
onClick: () => d(b, "`"),
|
|
78
|
+
className: w,
|
|
79
|
+
title: "Inline code",
|
|
80
|
+
"aria-label": "Inline code",
|
|
81
|
+
children: /* @__PURE__ */ l(a, { className: "size-3.5" })
|
|
82
|
+
}),
|
|
83
|
+
/* @__PURE__ */ l("button", {
|
|
84
|
+
type: "button",
|
|
85
|
+
onClick: () => f(b, "- "),
|
|
86
|
+
className: w,
|
|
87
|
+
title: "Bullet list",
|
|
88
|
+
"aria-label": "Bullet list",
|
|
89
|
+
children: /* @__PURE__ */ l(c, { className: "size-3.5" })
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
})]
|
|
93
|
+
}), x === "write" ? /* @__PURE__ */ l("textarea", {
|
|
94
|
+
ref: b,
|
|
95
|
+
id: p,
|
|
96
|
+
value: m,
|
|
97
|
+
onChange: (e) => h(e.target.value),
|
|
98
|
+
placeholder: _,
|
|
99
|
+
rows: v,
|
|
100
|
+
className: "w-full resize-y bg-surface-default px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]"
|
|
101
|
+
}) : /* @__PURE__ */ l("div", {
|
|
102
|
+
className: "min-h-[theme(spacing.32)] bg-surface-default px-3 py-2",
|
|
103
|
+
children: m.trim() ? /* @__PURE__ */ l(r, {
|
|
104
|
+
className: "text-sm text-text-primary",
|
|
105
|
+
children: T
|
|
106
|
+
}) : /* @__PURE__ */ l("p", {
|
|
107
|
+
className: "text-sm text-text-muted italic",
|
|
108
|
+
children: "Nothing to preview."
|
|
109
|
+
})
|
|
110
|
+
})]
|
|
111
|
+
})]
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
//#endregion
|
|
115
|
+
export { p as MarkdownEditor };
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=MarkdownEditor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarkdownEditor.js","names":[],"sources":["../../src/components/MarkdownEditor.tsx"],"sourcesContent":["import type { FC, ReactNode, RefObject } from 'react';\nimport { useMemo, useRef, useState } from 'react';\nimport { Bold, Italic, Link, Code, List } from 'lucide-react';\nimport { Markdown } from '@burdenoff/fe-libs/shared/components';\n\nexport interface MarkdownEditorProps {\n id?: string;\n value: string;\n onChange: (value: string) => void;\n label?: ReactNode;\n placeholder?: string;\n rows?: number;\n className?: string;\n}\n\ntype Tab = 'write' | 'preview';\n\nconst applyWrap = (\n textareaRef: RefObject<HTMLTextAreaElement | null>,\n prefix: string,\n suffix: string = prefix\n) => {\n const el = textareaRef.current;\n if (!el) return;\n\n const { selectionStart, selectionEnd, value } = el;\n const before = value.slice(0, selectionStart);\n const selected = value.slice(selectionStart, selectionEnd);\n const after = value.slice(selectionEnd);\n\n const replacement = `${prefix}${selected}${suffix}`;\n const nextValue = `${before}${replacement}${after}`;\n\n el.value = nextValue;\n el.focus();\n\n const cursorOffset = selected.length === 0 ? prefix.length : selected.length + prefix.length;\n const nextCursor = selectionStart + cursorOffset;\n el.setSelectionRange(nextCursor, nextCursor);\n\n // Dispatch an input event so parent onChange handlers are notified.\n el.dispatchEvent(new Event('input', { bubbles: true }));\n};\n\nconst applyLinePrefix = (textareaRef: RefObject<HTMLTextAreaElement | null>, prefix: string) => {\n const el = textareaRef.current;\n if (!el) return;\n\n const { selectionStart, selectionEnd, value } = el;\n const before = value.slice(0, selectionStart);\n const selected = value.slice(selectionStart, selectionEnd);\n const after = value.slice(selectionEnd);\n\n const lines = selected.split('\\n');\n const prefixedLines = lines.every((line) => line === '' || line.startsWith(prefix))\n ? lines.map((line) => (line.startsWith(prefix) ? line.slice(prefix.length) : line)).join('\\n')\n : lines.map((line) => `${prefix}${line}`).join('\\n');\n\n const replacement = prefixedLines;\n const nextValue = `${before}${replacement}${after}`;\n\n el.value = nextValue;\n el.focus();\n\n const nextCursorStart = selectionStart;\n const nextCursorEnd = selectionStart + replacement.length;\n el.setSelectionRange(nextCursorStart, nextCursorEnd);\n\n el.dispatchEvent(new Event('input', { bubbles: true }));\n};\n\nexport const MarkdownEditor: FC<MarkdownEditorProps> = ({\n id,\n value,\n onChange,\n label,\n placeholder,\n rows = 5,\n className = '',\n}) => {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [activeTab, setActiveTab] = useState<Tab>('write');\n\n const tabButtonClass = (tab: Tab) =>\n `rounded-md px-2.5 py-1 text-xs font-medium transition-colors ${\n activeTab === tab\n ? 'bg-surface-accent text-text-on-accent'\n : 'text-text-secondary hover:bg-surface-hover hover:text-text-primary'\n }`;\n\n const toolbarButtonClass =\n 'inline-flex items-center justify-center rounded-md p-1.5 text-text-secondary transition-colors hover:bg-surface-hover hover:text-text-primary';\n\n const memoizedValue = useMemo(() => value, [value]);\n\n return (\n <div className={`space-y-2 ${className}`}>\n {label && (\n <label htmlFor={id} className=\"block text-xs text-text-secondary\">\n {label}\n </label>\n )}\n\n <div className=\"overflow-hidden rounded-lg border border-border-default bg-surface-default\">\n <div className=\"flex items-center justify-between border-b border-border-default px-2 py-1.5\">\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => setActiveTab('write')}\n className={tabButtonClass('write')}\n aria-pressed={activeTab === 'write'}\n >\n Write\n </button>\n <button\n type=\"button\"\n onClick={() => setActiveTab('preview')}\n className={tabButtonClass('preview')}\n aria-pressed={activeTab === 'preview'}\n >\n Preview\n </button>\n </div>\n\n <div className=\"flex items-center gap-0.5\" aria-label=\"Markdown formatting\">\n <button\n type=\"button\"\n onClick={() => applyWrap(textareaRef, '**')}\n className={toolbarButtonClass}\n title=\"Bold\"\n aria-label=\"Bold\"\n >\n <Bold className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => applyWrap(textareaRef, '_')}\n className={toolbarButtonClass}\n title=\"Italic\"\n aria-label=\"Italic\"\n >\n <Italic className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => applyWrap(textareaRef, '[', '](url)')}\n className={toolbarButtonClass}\n title=\"Link\"\n aria-label=\"Link\"\n >\n <Link className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => applyWrap(textareaRef, '`')}\n className={toolbarButtonClass}\n title=\"Inline code\"\n aria-label=\"Inline code\"\n >\n <Code className=\"size-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => applyLinePrefix(textareaRef, '- ')}\n className={toolbarButtonClass}\n title=\"Bullet list\"\n aria-label=\"Bullet list\"\n >\n <List className=\"size-3.5\" />\n </button>\n </div>\n </div>\n\n {activeTab === 'write' ? (\n <textarea\n ref={textareaRef}\n id={id}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n placeholder={placeholder}\n rows={rows}\n className=\"w-full resize-y bg-surface-default px-3 py-2 text-sm text-text-primary placeholder:text-text-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n />\n ) : (\n <div className=\"min-h-[theme(spacing.32)] bg-surface-default px-3 py-2\">\n {value.trim() ? (\n <Markdown className=\"text-sm text-text-primary\">{memoizedValue}</Markdown>\n ) : (\n <p className=\"text-sm text-text-muted italic\">Nothing to preview.</p>\n )}\n </div>\n )}\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|