tetrons 2.3.91 → 2.3.92
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/index.cjs +197 -90
- package/dist/index.mjs +197 -90
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -16016,14 +16016,10 @@ function ActionGroup({ editor }) {
|
|
|
16016
16016
|
setDropdownOpen(false);
|
|
16017
16017
|
}
|
|
16018
16018
|
};
|
|
16019
|
-
if (dropdownOpen)
|
|
16019
|
+
if (dropdownOpen)
|
|
16020
16020
|
document.addEventListener("mousedown", handleClickOutside);
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
}
|
|
16024
|
-
return () => {
|
|
16025
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
16026
|
-
};
|
|
16021
|
+
else document.removeEventListener("mousedown", handleClickOutside);
|
|
16022
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
16027
16023
|
}, [dropdownOpen]);
|
|
16028
16024
|
const zoomIn = () => {
|
|
16029
16025
|
const element = document.querySelector(
|
|
@@ -16032,8 +16028,7 @@ function ActionGroup({ editor }) {
|
|
|
16032
16028
|
if (element) {
|
|
16033
16029
|
const style = element.style;
|
|
16034
16030
|
const currentZoom = parseFloat(style.zoom || "1");
|
|
16035
|
-
|
|
16036
|
-
style.zoom = next.toString();
|
|
16031
|
+
style.zoom = Math.min(currentZoom + 0.1, 2).toString();
|
|
16037
16032
|
}
|
|
16038
16033
|
};
|
|
16039
16034
|
const zoomOut = () => {
|
|
@@ -16043,28 +16038,24 @@ function ActionGroup({ editor }) {
|
|
|
16043
16038
|
if (element) {
|
|
16044
16039
|
const style = element.style;
|
|
16045
16040
|
const currentZoom = parseFloat(style.zoom || "1");
|
|
16046
|
-
|
|
16047
|
-
style.zoom = next.toString();
|
|
16041
|
+
style.zoom = Math.max(currentZoom - 0.1, 0.5).toString();
|
|
16048
16042
|
}
|
|
16049
16043
|
};
|
|
16050
16044
|
const handlePrint = () => {
|
|
16045
|
+
if (!editor) return;
|
|
16051
16046
|
const html = editor.getHTML();
|
|
16052
16047
|
const printWindow = window.open("", "_blank");
|
|
16053
16048
|
if (printWindow) {
|
|
16054
|
-
printWindow.document.write(
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
<title>Print</title>
|
|
16058
|
-
</head>
|
|
16059
|
-
<body>${html}</body>
|
|
16060
|
-
</html>
|
|
16061
|
-
`);
|
|
16049
|
+
printWindow.document.write(
|
|
16050
|
+
`<html><head><title>Print</title></head><body>${html}</body></html>`
|
|
16051
|
+
);
|
|
16062
16052
|
printWindow.document.close();
|
|
16063
16053
|
printWindow.focus();
|
|
16064
16054
|
printWindow.print();
|
|
16065
16055
|
}
|
|
16066
16056
|
};
|
|
16067
16057
|
const handleSave = async () => {
|
|
16058
|
+
if (!editor) return;
|
|
16068
16059
|
const content = editor.getJSON();
|
|
16069
16060
|
try {
|
|
16070
16061
|
const response = await fetch("/api/save", {
|
|
@@ -16074,14 +16065,14 @@ function ActionGroup({ editor }) {
|
|
|
16074
16065
|
});
|
|
16075
16066
|
if (!response.ok) throw new Error("Failed to save file");
|
|
16076
16067
|
const result = await response.json();
|
|
16077
|
-
|
|
16078
|
-
alert("Content saved successfully!");
|
|
16068
|
+
alert(result.message || "Content saved successfully!");
|
|
16079
16069
|
} catch (error) {
|
|
16080
|
-
console.error(
|
|
16070
|
+
console.error(error);
|
|
16081
16071
|
alert("Failed to save content.");
|
|
16082
16072
|
}
|
|
16083
16073
|
};
|
|
16084
16074
|
const handleDownloadPDF = async () => {
|
|
16075
|
+
if (!editor) return;
|
|
16085
16076
|
const html = editor.getHTML();
|
|
16086
16077
|
const container = document.createElement("div");
|
|
16087
16078
|
container.innerHTML = html;
|
|
@@ -16089,22 +16080,22 @@ function ActionGroup({ editor }) {
|
|
|
16089
16080
|
document.body.appendChild(container);
|
|
16090
16081
|
try {
|
|
16091
16082
|
const domToPdf = (await import("dom-to-pdf")).default;
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
overrideWidth: 800,
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
|
|
16098
|
-
|
|
16099
|
-
});
|
|
16083
|
+
domToPdf(
|
|
16084
|
+
container,
|
|
16085
|
+
{ filename: "document.pdf", overrideWidth: 800, overrideHeight: 1120 },
|
|
16086
|
+
() => {
|
|
16087
|
+
console.log("PDF downloaded!");
|
|
16088
|
+
}
|
|
16089
|
+
);
|
|
16100
16090
|
} catch (error) {
|
|
16101
|
-
console.error(
|
|
16091
|
+
console.error(error);
|
|
16102
16092
|
alert("Failed to download PDF.");
|
|
16103
16093
|
} finally {
|
|
16104
16094
|
document.body.removeChild(container);
|
|
16105
16095
|
}
|
|
16106
16096
|
};
|
|
16107
16097
|
const handleDownloadHTML = () => {
|
|
16098
|
+
if (!editor) return;
|
|
16108
16099
|
const html = editor.getHTML();
|
|
16109
16100
|
const blob = new Blob([html], { type: "text/html" });
|
|
16110
16101
|
const link = document.createElement("a");
|
|
@@ -16115,15 +16106,11 @@ function ActionGroup({ editor }) {
|
|
|
16115
16106
|
document.body.removeChild(link);
|
|
16116
16107
|
};
|
|
16117
16108
|
const handleDownloadDOCX = async () => {
|
|
16109
|
+
if (!editor) return;
|
|
16118
16110
|
const { Document: Document2, Packer, Paragraph: Paragraph2 } = await import("docx");
|
|
16119
16111
|
const text = editor.getText();
|
|
16120
16112
|
const doc3 = new Document2({
|
|
16121
|
-
sections: [
|
|
16122
|
-
{
|
|
16123
|
-
properties: {},
|
|
16124
|
-
children: [new Paragraph2(text)]
|
|
16125
|
-
}
|
|
16126
|
-
]
|
|
16113
|
+
sections: [{ properties: {}, children: [new Paragraph2(text)] }]
|
|
16127
16114
|
});
|
|
16128
16115
|
const blob = await Packer.toBlob(doc3);
|
|
16129
16116
|
const link = document.createElement("a");
|
|
@@ -16133,49 +16120,59 @@ function ActionGroup({ editor }) {
|
|
|
16133
16120
|
link.click();
|
|
16134
16121
|
document.body.removeChild(link);
|
|
16135
16122
|
};
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
type: "button",
|
|
16140
|
-
onClick: () => setDropdownOpen((open) => !open),
|
|
16141
|
-
"aria-haspopup": "menu",
|
|
16142
|
-
"aria-expanded": dropdownOpen ? "true" : "false",
|
|
16143
|
-
className: "export-button",
|
|
16144
|
-
title: "Export"
|
|
16145
|
-
},
|
|
16146
|
-
/* @__PURE__ */ import_react10.default.createElement(import_md.MdDownload, null),
|
|
16147
|
-
/* @__PURE__ */ import_react10.default.createElement("span", { className: "text-sm" })
|
|
16148
|
-
), dropdownOpen && /* @__PURE__ */ import_react10.default.createElement("div", { className: "export-dropdown" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
16149
|
-
"button",
|
|
16150
|
-
{
|
|
16151
|
-
type: "button",
|
|
16152
|
-
onClick: () => {
|
|
16153
|
-
setDropdownOpen(false);
|
|
16154
|
-
handleDownloadPDF();
|
|
16155
|
-
}
|
|
16156
|
-
},
|
|
16157
|
-
"Export as PDF"
|
|
16158
|
-
), /* @__PURE__ */ import_react10.default.createElement(
|
|
16159
|
-
"button",
|
|
16160
|
-
{
|
|
16161
|
-
type: "button",
|
|
16162
|
-
onClick: () => {
|
|
16163
|
-
setDropdownOpen(false);
|
|
16164
|
-
handleDownloadHTML();
|
|
16165
|
-
}
|
|
16166
|
-
},
|
|
16167
|
-
"Export as HTML"
|
|
16168
|
-
), /* @__PURE__ */ import_react10.default.createElement(
|
|
16169
|
-
"button",
|
|
16123
|
+
if (!editor) return null;
|
|
16124
|
+
return /* @__PURE__ */ import_react10.default.createElement(
|
|
16125
|
+
"div",
|
|
16170
16126
|
{
|
|
16171
|
-
|
|
16172
|
-
|
|
16173
|
-
|
|
16174
|
-
handleDownloadDOCX();
|
|
16175
|
-
}
|
|
16127
|
+
className: "action-group bg-white text-black dark:bg-gray-800 dark:text-white",
|
|
16128
|
+
role: "group",
|
|
16129
|
+
"aria-label": "Editor actions"
|
|
16176
16130
|
},
|
|
16177
|
-
"
|
|
16178
|
-
|
|
16131
|
+
/* @__PURE__ */ import_react10.default.createElement(ToolbarButton_default, { icon: import_md.MdZoomIn, onClick: zoomIn, title: "Zoom In" }),
|
|
16132
|
+
/* @__PURE__ */ import_react10.default.createElement(ToolbarButton_default, { icon: import_md.MdZoomOut, onClick: zoomOut, title: "Zoom Out" }),
|
|
16133
|
+
/* @__PURE__ */ import_react10.default.createElement(ToolbarButton_default, { icon: import_md.MdPrint, onClick: handlePrint, title: "Print" }),
|
|
16134
|
+
/* @__PURE__ */ import_react10.default.createElement(ToolbarButton_default, { icon: import_md.MdSave, onClick: handleSave, title: "Save" }),
|
|
16135
|
+
/* @__PURE__ */ import_react10.default.createElement("div", { className: "relative", ref: dropdownRef }, /* @__PURE__ */ import_react10.default.createElement(
|
|
16136
|
+
"button",
|
|
16137
|
+
{
|
|
16138
|
+
type: "button",
|
|
16139
|
+
onClick: () => setDropdownOpen((o) => !o),
|
|
16140
|
+
className: "export-button",
|
|
16141
|
+
title: "Export"
|
|
16142
|
+
},
|
|
16143
|
+
/* @__PURE__ */ import_react10.default.createElement(import_md.MdDownload, null)
|
|
16144
|
+
), dropdownOpen && /* @__PURE__ */ import_react10.default.createElement("div", { className: "export-dropdown" }, /* @__PURE__ */ import_react10.default.createElement(
|
|
16145
|
+
"button",
|
|
16146
|
+
{
|
|
16147
|
+
type: "button",
|
|
16148
|
+
onClick: () => {
|
|
16149
|
+
setDropdownOpen(false);
|
|
16150
|
+
handleDownloadPDF();
|
|
16151
|
+
}
|
|
16152
|
+
},
|
|
16153
|
+
"Export as PDF"
|
|
16154
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
16155
|
+
"button",
|
|
16156
|
+
{
|
|
16157
|
+
type: "button",
|
|
16158
|
+
onClick: () => {
|
|
16159
|
+
setDropdownOpen(false);
|
|
16160
|
+
handleDownloadHTML();
|
|
16161
|
+
}
|
|
16162
|
+
},
|
|
16163
|
+
"Export as HTML"
|
|
16164
|
+
), /* @__PURE__ */ import_react10.default.createElement(
|
|
16165
|
+
"button",
|
|
16166
|
+
{
|
|
16167
|
+
type: "button",
|
|
16168
|
+
onClick: () => {
|
|
16169
|
+
setDropdownOpen(false);
|
|
16170
|
+
handleDownloadDOCX();
|
|
16171
|
+
}
|
|
16172
|
+
},
|
|
16173
|
+
"Export as DOCX"
|
|
16174
|
+
)))
|
|
16175
|
+
);
|
|
16179
16176
|
}
|
|
16180
16177
|
|
|
16181
16178
|
// src/components/tetrons/toolbar/ClipboardGroup.tsx
|
|
@@ -16638,13 +16635,18 @@ function InsertGroup({ editor }) {
|
|
|
16638
16635
|
var import_react15 = __toESM(require("react"));
|
|
16639
16636
|
var import_md5 = require("react-icons/md");
|
|
16640
16637
|
function ListAlignGroup({ editor }) {
|
|
16641
|
-
|
|
16638
|
+
if (!editor) return null;
|
|
16639
|
+
const canToggleBullet = editor.can().toggleBulletList() || editor.isEmpty;
|
|
16640
|
+
const canToggleOrdered = editor.can().toggleOrderedList() || editor.isEmpty;
|
|
16641
|
+
const canSink = editor.can().sinkListItem("listItem");
|
|
16642
|
+
const canLift = editor.can().liftListItem("listItem");
|
|
16643
|
+
return /* @__PURE__ */ import_react15.default.createElement("div", { className: "list-align-group bg-white text-black dark:bg-gray-800 dark:text-white" }, /* @__PURE__ */ import_react15.default.createElement(
|
|
16642
16644
|
ToolbarButton_default,
|
|
16643
16645
|
{
|
|
16644
16646
|
icon: import_md5.MdFormatListBulleted,
|
|
16645
16647
|
title: "Bulleted List",
|
|
16646
16648
|
onClick: () => editor.chain().focus().toggleBulletList().run(),
|
|
16647
|
-
disabled: !
|
|
16649
|
+
disabled: !canToggleBullet
|
|
16648
16650
|
}
|
|
16649
16651
|
), /* @__PURE__ */ import_react15.default.createElement(
|
|
16650
16652
|
ToolbarButton_default,
|
|
@@ -16652,7 +16654,7 @@ function ListAlignGroup({ editor }) {
|
|
|
16652
16654
|
icon: import_md5.MdFormatListNumbered,
|
|
16653
16655
|
title: "Numbered List",
|
|
16654
16656
|
onClick: () => editor.chain().focus().toggleOrderedList().run(),
|
|
16655
|
-
disabled: !
|
|
16657
|
+
disabled: !canToggleOrdered
|
|
16656
16658
|
}
|
|
16657
16659
|
), /* @__PURE__ */ import_react15.default.createElement(
|
|
16658
16660
|
ToolbarButton_default,
|
|
@@ -16660,7 +16662,7 @@ function ListAlignGroup({ editor }) {
|
|
|
16660
16662
|
icon: import_md5.MdFormatIndentIncrease,
|
|
16661
16663
|
title: "Increase Indent",
|
|
16662
16664
|
onClick: () => editor.chain().focus().sinkListItem("listItem").run(),
|
|
16663
|
-
disabled: !
|
|
16665
|
+
disabled: !canSink
|
|
16664
16666
|
}
|
|
16665
16667
|
), /* @__PURE__ */ import_react15.default.createElement(
|
|
16666
16668
|
ToolbarButton_default,
|
|
@@ -16668,7 +16670,7 @@ function ListAlignGroup({ editor }) {
|
|
|
16668
16670
|
icon: import_md5.MdFormatIndentDecrease,
|
|
16669
16671
|
title: "Decrease Indent",
|
|
16670
16672
|
onClick: () => editor.chain().focus().liftListItem("listItem").run(),
|
|
16671
|
-
disabled: !
|
|
16673
|
+
disabled: !canLift
|
|
16672
16674
|
}
|
|
16673
16675
|
), /* @__PURE__ */ import_react15.default.createElement(
|
|
16674
16676
|
ToolbarButton_default,
|
|
@@ -16876,11 +16878,16 @@ function FileGroup({ editor }) {
|
|
|
16876
16878
|
var import_react18 = __toESM(require("react"));
|
|
16877
16879
|
var import_fa2 = require("react-icons/fa");
|
|
16878
16880
|
var import_loaders = require("@uiball/loaders");
|
|
16881
|
+
var import_framer_motion = require("framer-motion");
|
|
16879
16882
|
function AiGroup({ editor, enabledFeatures }) {
|
|
16880
16883
|
const [isRecording, setIsRecording] = (0, import_react18.useState)(false);
|
|
16881
16884
|
const [audioBlob, setAudioBlob] = (0, import_react18.useState)(null);
|
|
16882
16885
|
const [isTranscribing, setIsTranscribing] = (0, import_react18.useState)(false);
|
|
16883
16886
|
const [transcriptionError, setTranscriptionError] = (0, import_react18.useState)("");
|
|
16887
|
+
const [showPromptInput, setShowPromptInput] = (0, import_react18.useState)(false);
|
|
16888
|
+
const [prompt2, setPrompt] = (0, import_react18.useState)("");
|
|
16889
|
+
const [isLoadingAI, setIsLoadingAI] = (0, import_react18.useState)(false);
|
|
16890
|
+
const [aiError, setAiError] = (0, import_react18.useState)("");
|
|
16884
16891
|
const mediaRecorderRef = (0, import_react18.useRef)(null);
|
|
16885
16892
|
const chunksRef = (0, import_react18.useRef)([]);
|
|
16886
16893
|
const startRecording = async () => {
|
|
@@ -16927,6 +16934,34 @@ function AiGroup({ editor, enabledFeatures }) {
|
|
|
16927
16934
|
setIsTranscribing(false);
|
|
16928
16935
|
}
|
|
16929
16936
|
};
|
|
16937
|
+
const handleAiClick = () => {
|
|
16938
|
+
setShowPromptInput(true);
|
|
16939
|
+
setPrompt("");
|
|
16940
|
+
setAiError("");
|
|
16941
|
+
};
|
|
16942
|
+
const handlePromptSubmit = async () => {
|
|
16943
|
+
if (!prompt2.trim()) return;
|
|
16944
|
+
setIsLoadingAI(true);
|
|
16945
|
+
setAiError("");
|
|
16946
|
+
try {
|
|
16947
|
+
const res = await fetch("https://staging.tetrons.com/api/ai-action", {
|
|
16948
|
+
method: "POST",
|
|
16949
|
+
headers: { "Content-Type": "application/json" },
|
|
16950
|
+
body: JSON.stringify({ content: prompt2 })
|
|
16951
|
+
});
|
|
16952
|
+
const data = await res.json();
|
|
16953
|
+
if (!res.ok || !data.response) {
|
|
16954
|
+
throw new Error(data.error || "AI failed to generate content");
|
|
16955
|
+
}
|
|
16956
|
+
editor.commands.insertContent(data.response);
|
|
16957
|
+
setShowPromptInput(false);
|
|
16958
|
+
} catch (e) {
|
|
16959
|
+
console.error(e);
|
|
16960
|
+
setAiError("Failed to generate content. Try again.");
|
|
16961
|
+
} finally {
|
|
16962
|
+
setIsLoadingAI(false);
|
|
16963
|
+
}
|
|
16964
|
+
};
|
|
16930
16965
|
if (!enabledFeatures.includes("voice to text")) return null;
|
|
16931
16966
|
return /* @__PURE__ */ import_react18.default.createElement("div", { className: "group flex flex-col gap-2 items-start" }, /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex gap-2 items-center" }, !isRecording ? /* @__PURE__ */ import_react18.default.createElement(
|
|
16932
16967
|
"button",
|
|
@@ -16946,7 +16981,60 @@ function AiGroup({ editor, enabledFeatures }) {
|
|
|
16946
16981
|
title: "Stop Recording"
|
|
16947
16982
|
},
|
|
16948
16983
|
/* @__PURE__ */ import_react18.default.createElement(import_fa2.FaStop, { size: 18 })
|
|
16949
|
-
)
|
|
16984
|
+
), /* @__PURE__ */ import_react18.default.createElement(
|
|
16985
|
+
"button",
|
|
16986
|
+
{
|
|
16987
|
+
type: "button",
|
|
16988
|
+
onClick: handleAiClick,
|
|
16989
|
+
className: "ai-button",
|
|
16990
|
+
title: "AI Assist"
|
|
16991
|
+
},
|
|
16992
|
+
"AI"
|
|
16993
|
+
)), isRecording && /* @__PURE__ */ import_react18.default.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ import_react18.default.createElement(import_loaders.Waveform, { size: 30, lineWeight: 3.5, speed: 1, color: "#4F46E5" }), /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-sm mt-1 text-gray-600" }, "Recording...")), isTranscribing && /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-sm text-gray-500" }, "Transcribing..."), transcriptionError && /* @__PURE__ */ import_react18.default.createElement("p", { className: "text-sm text-red-600" }, transcriptionError), audioBlob && /* @__PURE__ */ import_react18.default.createElement("div", { className: "mt-2" }, /* @__PURE__ */ import_react18.default.createElement("audio", { controls: true, src: URL.createObjectURL(audioBlob) })), /* @__PURE__ */ import_react18.default.createElement(import_framer_motion.AnimatePresence, null, showPromptInput && /* @__PURE__ */ import_react18.default.createElement(
|
|
16994
|
+
import_framer_motion.motion.div,
|
|
16995
|
+
{
|
|
16996
|
+
className: "ai-modal-backdrop",
|
|
16997
|
+
initial: { opacity: 0 },
|
|
16998
|
+
animate: { opacity: 1 },
|
|
16999
|
+
exit: { opacity: 0 }
|
|
17000
|
+
},
|
|
17001
|
+
/* @__PURE__ */ import_react18.default.createElement(
|
|
17002
|
+
import_framer_motion.motion.div,
|
|
17003
|
+
{
|
|
17004
|
+
className: "ai-modal-content",
|
|
17005
|
+
initial: { scale: 0.9, opacity: 0 },
|
|
17006
|
+
animate: { scale: 1, opacity: 1 },
|
|
17007
|
+
exit: { scale: 0.9, opacity: 0 }
|
|
17008
|
+
},
|
|
17009
|
+
/* @__PURE__ */ import_react18.default.createElement("h2", { className: "ai-modal-title" }, "AI Prompt"),
|
|
17010
|
+
/* @__PURE__ */ import_react18.default.createElement(
|
|
17011
|
+
"textarea",
|
|
17012
|
+
{
|
|
17013
|
+
className: "ai-modal-textarea",
|
|
17014
|
+
value: prompt2,
|
|
17015
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
17016
|
+
placeholder: "Enter your prompt here..."
|
|
17017
|
+
}
|
|
17018
|
+
),
|
|
17019
|
+
aiError && /* @__PURE__ */ import_react18.default.createElement("p", { className: "ai-modal-error" }, aiError),
|
|
17020
|
+
/* @__PURE__ */ import_react18.default.createElement("div", { className: "ai-modal-actions" }, /* @__PURE__ */ import_react18.default.createElement(
|
|
17021
|
+
"button",
|
|
17022
|
+
{
|
|
17023
|
+
onClick: () => setShowPromptInput(false),
|
|
17024
|
+
className: "ai-cancel-btn"
|
|
17025
|
+
},
|
|
17026
|
+
"Cancel"
|
|
17027
|
+
), /* @__PURE__ */ import_react18.default.createElement(
|
|
17028
|
+
"button",
|
|
17029
|
+
{
|
|
17030
|
+
onClick: handlePromptSubmit,
|
|
17031
|
+
disabled: isLoadingAI,
|
|
17032
|
+
className: "ai-submit-btn"
|
|
17033
|
+
},
|
|
17034
|
+
isLoadingAI ? "Generating..." : "Submit"
|
|
17035
|
+
))
|
|
17036
|
+
)
|
|
17037
|
+
)));
|
|
16950
17038
|
}
|
|
16951
17039
|
|
|
16952
17040
|
// src/components/tetrons/toolbar/AddOnGroup.tsx
|
|
@@ -17039,9 +17127,8 @@ function TetronsToolbar({
|
|
|
17039
17127
|
}) {
|
|
17040
17128
|
const [autoSave, setAutoSave] = (0, import_react23.useState)(false);
|
|
17041
17129
|
(0, import_react23.useEffect)(() => {
|
|
17042
|
-
if (!editor) return;
|
|
17130
|
+
if (!editor || !autoSave) return;
|
|
17043
17131
|
const handleUpdate = () => {
|
|
17044
|
-
if (!autoSave) return;
|
|
17045
17132
|
const content = editor.getJSON();
|
|
17046
17133
|
fetch("/api/save", {
|
|
17047
17134
|
method: "POST",
|
|
@@ -17060,7 +17147,18 @@ function TetronsToolbar({
|
|
|
17060
17147
|
case "premium":
|
|
17061
17148
|
return addOns;
|
|
17062
17149
|
case "platinum":
|
|
17063
|
-
return [
|
|
17150
|
+
return [
|
|
17151
|
+
"math",
|
|
17152
|
+
"code",
|
|
17153
|
+
"ai",
|
|
17154
|
+
"voice to text",
|
|
17155
|
+
"undo",
|
|
17156
|
+
"redo",
|
|
17157
|
+
"resetFormatting",
|
|
17158
|
+
"preview",
|
|
17159
|
+
"codeBlock",
|
|
17160
|
+
"spell check"
|
|
17161
|
+
];
|
|
17064
17162
|
default:
|
|
17065
17163
|
return [];
|
|
17066
17164
|
}
|
|
@@ -17073,13 +17171,22 @@ function TetronsToolbar({
|
|
|
17073
17171
|
checked: autoSave,
|
|
17074
17172
|
onChange: (e) => setAutoSave(e.target.checked)
|
|
17075
17173
|
}
|
|
17076
|
-
), /* @__PURE__ */ import_react23.default.createElement("label", { htmlFor: "autoSave" }, "Auto Save")), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ import_react23.default.createElement(FileGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(ClipboardGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(FontStyleGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(ListAlignGroup, { editor }), ["premium", "platinum"].includes(version) && /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, /* @__PURE__ */ import_react23.default.createElement(InsertGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(ActionGroup, { editor })),
|
|
17174
|
+
), /* @__PURE__ */ import_react23.default.createElement("label", { htmlFor: "autoSave" }, "Auto Save")), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ import_react23.default.createElement(FileGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(ClipboardGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(FontStyleGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(ListAlignGroup, { editor }), ["premium", "platinum"].includes(version) && /* @__PURE__ */ import_react23.default.createElement(import_react23.default.Fragment, null, /* @__PURE__ */ import_react23.default.createElement(InsertGroup, { editor }), /* @__PURE__ */ import_react23.default.createElement(ActionGroup, { editor })), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ import_react23.default.createElement(
|
|
17077
17175
|
MiscGroup,
|
|
17078
17176
|
{
|
|
17079
17177
|
editor,
|
|
17080
|
-
enabledFeatures: effectiveAddOns
|
|
17178
|
+
enabledFeatures: effectiveAddOns.filter(
|
|
17179
|
+
(a) => [
|
|
17180
|
+
"undo",
|
|
17181
|
+
"redo",
|
|
17182
|
+
"resetFormatting",
|
|
17183
|
+
"preview",
|
|
17184
|
+
"codeBlock",
|
|
17185
|
+
"spell check"
|
|
17186
|
+
].includes(a)
|
|
17187
|
+
)
|
|
17081
17188
|
}
|
|
17082
|
-
),
|
|
17189
|
+
), effectiveAddOns.some((a) => ["ai", "voice to text"].includes(a)) && /* @__PURE__ */ import_react23.default.createElement(
|
|
17083
17190
|
AiGroup,
|
|
17084
17191
|
{
|
|
17085
17192
|
editor,
|
package/dist/index.mjs
CHANGED
|
@@ -15986,14 +15986,10 @@ function ActionGroup({ editor }) {
|
|
|
15986
15986
|
setDropdownOpen(false);
|
|
15987
15987
|
}
|
|
15988
15988
|
};
|
|
15989
|
-
if (dropdownOpen)
|
|
15989
|
+
if (dropdownOpen)
|
|
15990
15990
|
document.addEventListener("mousedown", handleClickOutside);
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
}
|
|
15994
|
-
return () => {
|
|
15995
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
15996
|
-
};
|
|
15991
|
+
else document.removeEventListener("mousedown", handleClickOutside);
|
|
15992
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
15997
15993
|
}, [dropdownOpen]);
|
|
15998
15994
|
const zoomIn = () => {
|
|
15999
15995
|
const element = document.querySelector(
|
|
@@ -16002,8 +15998,7 @@ function ActionGroup({ editor }) {
|
|
|
16002
15998
|
if (element) {
|
|
16003
15999
|
const style = element.style;
|
|
16004
16000
|
const currentZoom = parseFloat(style.zoom || "1");
|
|
16005
|
-
|
|
16006
|
-
style.zoom = next.toString();
|
|
16001
|
+
style.zoom = Math.min(currentZoom + 0.1, 2).toString();
|
|
16007
16002
|
}
|
|
16008
16003
|
};
|
|
16009
16004
|
const zoomOut = () => {
|
|
@@ -16013,28 +16008,24 @@ function ActionGroup({ editor }) {
|
|
|
16013
16008
|
if (element) {
|
|
16014
16009
|
const style = element.style;
|
|
16015
16010
|
const currentZoom = parseFloat(style.zoom || "1");
|
|
16016
|
-
|
|
16017
|
-
style.zoom = next.toString();
|
|
16011
|
+
style.zoom = Math.max(currentZoom - 0.1, 0.5).toString();
|
|
16018
16012
|
}
|
|
16019
16013
|
};
|
|
16020
16014
|
const handlePrint = () => {
|
|
16015
|
+
if (!editor) return;
|
|
16021
16016
|
const html = editor.getHTML();
|
|
16022
16017
|
const printWindow = window.open("", "_blank");
|
|
16023
16018
|
if (printWindow) {
|
|
16024
|
-
printWindow.document.write(
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
<title>Print</title>
|
|
16028
|
-
</head>
|
|
16029
|
-
<body>${html}</body>
|
|
16030
|
-
</html>
|
|
16031
|
-
`);
|
|
16019
|
+
printWindow.document.write(
|
|
16020
|
+
`<html><head><title>Print</title></head><body>${html}</body></html>`
|
|
16021
|
+
);
|
|
16032
16022
|
printWindow.document.close();
|
|
16033
16023
|
printWindow.focus();
|
|
16034
16024
|
printWindow.print();
|
|
16035
16025
|
}
|
|
16036
16026
|
};
|
|
16037
16027
|
const handleSave = async () => {
|
|
16028
|
+
if (!editor) return;
|
|
16038
16029
|
const content = editor.getJSON();
|
|
16039
16030
|
try {
|
|
16040
16031
|
const response = await fetch("/api/save", {
|
|
@@ -16044,14 +16035,14 @@ function ActionGroup({ editor }) {
|
|
|
16044
16035
|
});
|
|
16045
16036
|
if (!response.ok) throw new Error("Failed to save file");
|
|
16046
16037
|
const result = await response.json();
|
|
16047
|
-
|
|
16048
|
-
alert("Content saved successfully!");
|
|
16038
|
+
alert(result.message || "Content saved successfully!");
|
|
16049
16039
|
} catch (error) {
|
|
16050
|
-
console.error(
|
|
16040
|
+
console.error(error);
|
|
16051
16041
|
alert("Failed to save content.");
|
|
16052
16042
|
}
|
|
16053
16043
|
};
|
|
16054
16044
|
const handleDownloadPDF = async () => {
|
|
16045
|
+
if (!editor) return;
|
|
16055
16046
|
const html = editor.getHTML();
|
|
16056
16047
|
const container = document.createElement("div");
|
|
16057
16048
|
container.innerHTML = html;
|
|
@@ -16059,22 +16050,22 @@ function ActionGroup({ editor }) {
|
|
|
16059
16050
|
document.body.appendChild(container);
|
|
16060
16051
|
try {
|
|
16061
16052
|
const domToPdf = (await import("dom-to-pdf")).default;
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
overrideWidth: 800,
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
});
|
|
16053
|
+
domToPdf(
|
|
16054
|
+
container,
|
|
16055
|
+
{ filename: "document.pdf", overrideWidth: 800, overrideHeight: 1120 },
|
|
16056
|
+
() => {
|
|
16057
|
+
console.log("PDF downloaded!");
|
|
16058
|
+
}
|
|
16059
|
+
);
|
|
16070
16060
|
} catch (error) {
|
|
16071
|
-
console.error(
|
|
16061
|
+
console.error(error);
|
|
16072
16062
|
alert("Failed to download PDF.");
|
|
16073
16063
|
} finally {
|
|
16074
16064
|
document.body.removeChild(container);
|
|
16075
16065
|
}
|
|
16076
16066
|
};
|
|
16077
16067
|
const handleDownloadHTML = () => {
|
|
16068
|
+
if (!editor) return;
|
|
16078
16069
|
const html = editor.getHTML();
|
|
16079
16070
|
const blob = new Blob([html], { type: "text/html" });
|
|
16080
16071
|
const link = document.createElement("a");
|
|
@@ -16085,15 +16076,11 @@ function ActionGroup({ editor }) {
|
|
|
16085
16076
|
document.body.removeChild(link);
|
|
16086
16077
|
};
|
|
16087
16078
|
const handleDownloadDOCX = async () => {
|
|
16079
|
+
if (!editor) return;
|
|
16088
16080
|
const { Document: Document2, Packer, Paragraph: Paragraph2 } = await import("docx");
|
|
16089
16081
|
const text = editor.getText();
|
|
16090
16082
|
const doc3 = new Document2({
|
|
16091
|
-
sections: [
|
|
16092
|
-
{
|
|
16093
|
-
properties: {},
|
|
16094
|
-
children: [new Paragraph2(text)]
|
|
16095
|
-
}
|
|
16096
|
-
]
|
|
16083
|
+
sections: [{ properties: {}, children: [new Paragraph2(text)] }]
|
|
16097
16084
|
});
|
|
16098
16085
|
const blob = await Packer.toBlob(doc3);
|
|
16099
16086
|
const link = document.createElement("a");
|
|
@@ -16103,49 +16090,59 @@ function ActionGroup({ editor }) {
|
|
|
16103
16090
|
link.click();
|
|
16104
16091
|
document.body.removeChild(link);
|
|
16105
16092
|
};
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16109
|
-
type: "button",
|
|
16110
|
-
onClick: () => setDropdownOpen((open) => !open),
|
|
16111
|
-
"aria-haspopup": "menu",
|
|
16112
|
-
"aria-expanded": dropdownOpen ? "true" : "false",
|
|
16113
|
-
className: "export-button",
|
|
16114
|
-
title: "Export"
|
|
16115
|
-
},
|
|
16116
|
-
/* @__PURE__ */ React5.createElement(MdDownload, null),
|
|
16117
|
-
/* @__PURE__ */ React5.createElement("span", { className: "text-sm" })
|
|
16118
|
-
), dropdownOpen && /* @__PURE__ */ React5.createElement("div", { className: "export-dropdown" }, /* @__PURE__ */ React5.createElement(
|
|
16119
|
-
"button",
|
|
16120
|
-
{
|
|
16121
|
-
type: "button",
|
|
16122
|
-
onClick: () => {
|
|
16123
|
-
setDropdownOpen(false);
|
|
16124
|
-
handleDownloadPDF();
|
|
16125
|
-
}
|
|
16126
|
-
},
|
|
16127
|
-
"Export as PDF"
|
|
16128
|
-
), /* @__PURE__ */ React5.createElement(
|
|
16129
|
-
"button",
|
|
16130
|
-
{
|
|
16131
|
-
type: "button",
|
|
16132
|
-
onClick: () => {
|
|
16133
|
-
setDropdownOpen(false);
|
|
16134
|
-
handleDownloadHTML();
|
|
16135
|
-
}
|
|
16136
|
-
},
|
|
16137
|
-
"Export as HTML"
|
|
16138
|
-
), /* @__PURE__ */ React5.createElement(
|
|
16139
|
-
"button",
|
|
16093
|
+
if (!editor) return null;
|
|
16094
|
+
return /* @__PURE__ */ React5.createElement(
|
|
16095
|
+
"div",
|
|
16140
16096
|
{
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
handleDownloadDOCX();
|
|
16145
|
-
}
|
|
16097
|
+
className: "action-group bg-white text-black dark:bg-gray-800 dark:text-white",
|
|
16098
|
+
role: "group",
|
|
16099
|
+
"aria-label": "Editor actions"
|
|
16146
16100
|
},
|
|
16147
|
-
"
|
|
16148
|
-
|
|
16101
|
+
/* @__PURE__ */ React5.createElement(ToolbarButton_default, { icon: MdZoomIn, onClick: zoomIn, title: "Zoom In" }),
|
|
16102
|
+
/* @__PURE__ */ React5.createElement(ToolbarButton_default, { icon: MdZoomOut, onClick: zoomOut, title: "Zoom Out" }),
|
|
16103
|
+
/* @__PURE__ */ React5.createElement(ToolbarButton_default, { icon: MdPrint, onClick: handlePrint, title: "Print" }),
|
|
16104
|
+
/* @__PURE__ */ React5.createElement(ToolbarButton_default, { icon: MdSave, onClick: handleSave, title: "Save" }),
|
|
16105
|
+
/* @__PURE__ */ React5.createElement("div", { className: "relative", ref: dropdownRef }, /* @__PURE__ */ React5.createElement(
|
|
16106
|
+
"button",
|
|
16107
|
+
{
|
|
16108
|
+
type: "button",
|
|
16109
|
+
onClick: () => setDropdownOpen((o) => !o),
|
|
16110
|
+
className: "export-button",
|
|
16111
|
+
title: "Export"
|
|
16112
|
+
},
|
|
16113
|
+
/* @__PURE__ */ React5.createElement(MdDownload, null)
|
|
16114
|
+
), dropdownOpen && /* @__PURE__ */ React5.createElement("div", { className: "export-dropdown" }, /* @__PURE__ */ React5.createElement(
|
|
16115
|
+
"button",
|
|
16116
|
+
{
|
|
16117
|
+
type: "button",
|
|
16118
|
+
onClick: () => {
|
|
16119
|
+
setDropdownOpen(false);
|
|
16120
|
+
handleDownloadPDF();
|
|
16121
|
+
}
|
|
16122
|
+
},
|
|
16123
|
+
"Export as PDF"
|
|
16124
|
+
), /* @__PURE__ */ React5.createElement(
|
|
16125
|
+
"button",
|
|
16126
|
+
{
|
|
16127
|
+
type: "button",
|
|
16128
|
+
onClick: () => {
|
|
16129
|
+
setDropdownOpen(false);
|
|
16130
|
+
handleDownloadHTML();
|
|
16131
|
+
}
|
|
16132
|
+
},
|
|
16133
|
+
"Export as HTML"
|
|
16134
|
+
), /* @__PURE__ */ React5.createElement(
|
|
16135
|
+
"button",
|
|
16136
|
+
{
|
|
16137
|
+
type: "button",
|
|
16138
|
+
onClick: () => {
|
|
16139
|
+
setDropdownOpen(false);
|
|
16140
|
+
handleDownloadDOCX();
|
|
16141
|
+
}
|
|
16142
|
+
},
|
|
16143
|
+
"Export as DOCX"
|
|
16144
|
+
)))
|
|
16145
|
+
);
|
|
16149
16146
|
}
|
|
16150
16147
|
|
|
16151
16148
|
// src/components/tetrons/toolbar/ClipboardGroup.tsx
|
|
@@ -16640,13 +16637,18 @@ import {
|
|
|
16640
16637
|
MdFormatAlignJustify
|
|
16641
16638
|
} from "react-icons/md";
|
|
16642
16639
|
function ListAlignGroup({ editor }) {
|
|
16643
|
-
|
|
16640
|
+
if (!editor) return null;
|
|
16641
|
+
const canToggleBullet = editor.can().toggleBulletList() || editor.isEmpty;
|
|
16642
|
+
const canToggleOrdered = editor.can().toggleOrderedList() || editor.isEmpty;
|
|
16643
|
+
const canSink = editor.can().sinkListItem("listItem");
|
|
16644
|
+
const canLift = editor.can().liftListItem("listItem");
|
|
16645
|
+
return /* @__PURE__ */ React9.createElement("div", { className: "list-align-group bg-white text-black dark:bg-gray-800 dark:text-white" }, /* @__PURE__ */ React9.createElement(
|
|
16644
16646
|
ToolbarButton_default,
|
|
16645
16647
|
{
|
|
16646
16648
|
icon: MdFormatListBulleted,
|
|
16647
16649
|
title: "Bulleted List",
|
|
16648
16650
|
onClick: () => editor.chain().focus().toggleBulletList().run(),
|
|
16649
|
-
disabled: !
|
|
16651
|
+
disabled: !canToggleBullet
|
|
16650
16652
|
}
|
|
16651
16653
|
), /* @__PURE__ */ React9.createElement(
|
|
16652
16654
|
ToolbarButton_default,
|
|
@@ -16654,7 +16656,7 @@ function ListAlignGroup({ editor }) {
|
|
|
16654
16656
|
icon: MdFormatListNumbered,
|
|
16655
16657
|
title: "Numbered List",
|
|
16656
16658
|
onClick: () => editor.chain().focus().toggleOrderedList().run(),
|
|
16657
|
-
disabled: !
|
|
16659
|
+
disabled: !canToggleOrdered
|
|
16658
16660
|
}
|
|
16659
16661
|
), /* @__PURE__ */ React9.createElement(
|
|
16660
16662
|
ToolbarButton_default,
|
|
@@ -16662,7 +16664,7 @@ function ListAlignGroup({ editor }) {
|
|
|
16662
16664
|
icon: MdFormatIndentIncrease,
|
|
16663
16665
|
title: "Increase Indent",
|
|
16664
16666
|
onClick: () => editor.chain().focus().sinkListItem("listItem").run(),
|
|
16665
|
-
disabled: !
|
|
16667
|
+
disabled: !canSink
|
|
16666
16668
|
}
|
|
16667
16669
|
), /* @__PURE__ */ React9.createElement(
|
|
16668
16670
|
ToolbarButton_default,
|
|
@@ -16670,7 +16672,7 @@ function ListAlignGroup({ editor }) {
|
|
|
16670
16672
|
icon: MdFormatIndentDecrease,
|
|
16671
16673
|
title: "Decrease Indent",
|
|
16672
16674
|
onClick: () => editor.chain().focus().liftListItem("listItem").run(),
|
|
16673
|
-
disabled: !
|
|
16675
|
+
disabled: !canLift
|
|
16674
16676
|
}
|
|
16675
16677
|
), /* @__PURE__ */ React9.createElement(
|
|
16676
16678
|
ToolbarButton_default,
|
|
@@ -16885,11 +16887,16 @@ function FileGroup({ editor }) {
|
|
|
16885
16887
|
import React12, { useState as useState7, useRef as useRef6 } from "react";
|
|
16886
16888
|
import { FaMicrophone, FaStop } from "react-icons/fa";
|
|
16887
16889
|
import { Waveform } from "@uiball/loaders";
|
|
16890
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
16888
16891
|
function AiGroup({ editor, enabledFeatures }) {
|
|
16889
16892
|
const [isRecording, setIsRecording] = useState7(false);
|
|
16890
16893
|
const [audioBlob, setAudioBlob] = useState7(null);
|
|
16891
16894
|
const [isTranscribing, setIsTranscribing] = useState7(false);
|
|
16892
16895
|
const [transcriptionError, setTranscriptionError] = useState7("");
|
|
16896
|
+
const [showPromptInput, setShowPromptInput] = useState7(false);
|
|
16897
|
+
const [prompt2, setPrompt] = useState7("");
|
|
16898
|
+
const [isLoadingAI, setIsLoadingAI] = useState7(false);
|
|
16899
|
+
const [aiError, setAiError] = useState7("");
|
|
16893
16900
|
const mediaRecorderRef = useRef6(null);
|
|
16894
16901
|
const chunksRef = useRef6([]);
|
|
16895
16902
|
const startRecording = async () => {
|
|
@@ -16936,6 +16943,34 @@ function AiGroup({ editor, enabledFeatures }) {
|
|
|
16936
16943
|
setIsTranscribing(false);
|
|
16937
16944
|
}
|
|
16938
16945
|
};
|
|
16946
|
+
const handleAiClick = () => {
|
|
16947
|
+
setShowPromptInput(true);
|
|
16948
|
+
setPrompt("");
|
|
16949
|
+
setAiError("");
|
|
16950
|
+
};
|
|
16951
|
+
const handlePromptSubmit = async () => {
|
|
16952
|
+
if (!prompt2.trim()) return;
|
|
16953
|
+
setIsLoadingAI(true);
|
|
16954
|
+
setAiError("");
|
|
16955
|
+
try {
|
|
16956
|
+
const res = await fetch("https://staging.tetrons.com/api/ai-action", {
|
|
16957
|
+
method: "POST",
|
|
16958
|
+
headers: { "Content-Type": "application/json" },
|
|
16959
|
+
body: JSON.stringify({ content: prompt2 })
|
|
16960
|
+
});
|
|
16961
|
+
const data = await res.json();
|
|
16962
|
+
if (!res.ok || !data.response) {
|
|
16963
|
+
throw new Error(data.error || "AI failed to generate content");
|
|
16964
|
+
}
|
|
16965
|
+
editor.commands.insertContent(data.response);
|
|
16966
|
+
setShowPromptInput(false);
|
|
16967
|
+
} catch (e) {
|
|
16968
|
+
console.error(e);
|
|
16969
|
+
setAiError("Failed to generate content. Try again.");
|
|
16970
|
+
} finally {
|
|
16971
|
+
setIsLoadingAI(false);
|
|
16972
|
+
}
|
|
16973
|
+
};
|
|
16939
16974
|
if (!enabledFeatures.includes("voice to text")) return null;
|
|
16940
16975
|
return /* @__PURE__ */ React12.createElement("div", { className: "group flex flex-col gap-2 items-start" }, /* @__PURE__ */ React12.createElement("div", { className: "flex gap-2 items-center" }, !isRecording ? /* @__PURE__ */ React12.createElement(
|
|
16941
16976
|
"button",
|
|
@@ -16955,7 +16990,60 @@ function AiGroup({ editor, enabledFeatures }) {
|
|
|
16955
16990
|
title: "Stop Recording"
|
|
16956
16991
|
},
|
|
16957
16992
|
/* @__PURE__ */ React12.createElement(FaStop, { size: 18 })
|
|
16958
|
-
)
|
|
16993
|
+
), /* @__PURE__ */ React12.createElement(
|
|
16994
|
+
"button",
|
|
16995
|
+
{
|
|
16996
|
+
type: "button",
|
|
16997
|
+
onClick: handleAiClick,
|
|
16998
|
+
className: "ai-button",
|
|
16999
|
+
title: "AI Assist"
|
|
17000
|
+
},
|
|
17001
|
+
"AI"
|
|
17002
|
+
)), isRecording && /* @__PURE__ */ React12.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React12.createElement(Waveform, { size: 30, lineWeight: 3.5, speed: 1, color: "#4F46E5" }), /* @__PURE__ */ React12.createElement("p", { className: "text-sm mt-1 text-gray-600" }, "Recording...")), isTranscribing && /* @__PURE__ */ React12.createElement("p", { className: "text-sm text-gray-500" }, "Transcribing..."), transcriptionError && /* @__PURE__ */ React12.createElement("p", { className: "text-sm text-red-600" }, transcriptionError), audioBlob && /* @__PURE__ */ React12.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React12.createElement("audio", { controls: true, src: URL.createObjectURL(audioBlob) })), /* @__PURE__ */ React12.createElement(AnimatePresence, null, showPromptInput && /* @__PURE__ */ React12.createElement(
|
|
17003
|
+
motion.div,
|
|
17004
|
+
{
|
|
17005
|
+
className: "ai-modal-backdrop",
|
|
17006
|
+
initial: { opacity: 0 },
|
|
17007
|
+
animate: { opacity: 1 },
|
|
17008
|
+
exit: { opacity: 0 }
|
|
17009
|
+
},
|
|
17010
|
+
/* @__PURE__ */ React12.createElement(
|
|
17011
|
+
motion.div,
|
|
17012
|
+
{
|
|
17013
|
+
className: "ai-modal-content",
|
|
17014
|
+
initial: { scale: 0.9, opacity: 0 },
|
|
17015
|
+
animate: { scale: 1, opacity: 1 },
|
|
17016
|
+
exit: { scale: 0.9, opacity: 0 }
|
|
17017
|
+
},
|
|
17018
|
+
/* @__PURE__ */ React12.createElement("h2", { className: "ai-modal-title" }, "AI Prompt"),
|
|
17019
|
+
/* @__PURE__ */ React12.createElement(
|
|
17020
|
+
"textarea",
|
|
17021
|
+
{
|
|
17022
|
+
className: "ai-modal-textarea",
|
|
17023
|
+
value: prompt2,
|
|
17024
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
17025
|
+
placeholder: "Enter your prompt here..."
|
|
17026
|
+
}
|
|
17027
|
+
),
|
|
17028
|
+
aiError && /* @__PURE__ */ React12.createElement("p", { className: "ai-modal-error" }, aiError),
|
|
17029
|
+
/* @__PURE__ */ React12.createElement("div", { className: "ai-modal-actions" }, /* @__PURE__ */ React12.createElement(
|
|
17030
|
+
"button",
|
|
17031
|
+
{
|
|
17032
|
+
onClick: () => setShowPromptInput(false),
|
|
17033
|
+
className: "ai-cancel-btn"
|
|
17034
|
+
},
|
|
17035
|
+
"Cancel"
|
|
17036
|
+
), /* @__PURE__ */ React12.createElement(
|
|
17037
|
+
"button",
|
|
17038
|
+
{
|
|
17039
|
+
onClick: handlePromptSubmit,
|
|
17040
|
+
disabled: isLoadingAI,
|
|
17041
|
+
className: "ai-submit-btn"
|
|
17042
|
+
},
|
|
17043
|
+
isLoadingAI ? "Generating..." : "Submit"
|
|
17044
|
+
))
|
|
17045
|
+
)
|
|
17046
|
+
)));
|
|
16959
17047
|
}
|
|
16960
17048
|
|
|
16961
17049
|
// src/components/tetrons/toolbar/AddOnGroup.tsx
|
|
@@ -17048,9 +17136,8 @@ function TetronsToolbar({
|
|
|
17048
17136
|
}) {
|
|
17049
17137
|
const [autoSave, setAutoSave] = useState10(false);
|
|
17050
17138
|
useEffect8(() => {
|
|
17051
|
-
if (!editor) return;
|
|
17139
|
+
if (!editor || !autoSave) return;
|
|
17052
17140
|
const handleUpdate = () => {
|
|
17053
|
-
if (!autoSave) return;
|
|
17054
17141
|
const content = editor.getJSON();
|
|
17055
17142
|
fetch("/api/save", {
|
|
17056
17143
|
method: "POST",
|
|
@@ -17069,7 +17156,18 @@ function TetronsToolbar({
|
|
|
17069
17156
|
case "premium":
|
|
17070
17157
|
return addOns;
|
|
17071
17158
|
case "platinum":
|
|
17072
|
-
return [
|
|
17159
|
+
return [
|
|
17160
|
+
"math",
|
|
17161
|
+
"code",
|
|
17162
|
+
"ai",
|
|
17163
|
+
"voice to text",
|
|
17164
|
+
"undo",
|
|
17165
|
+
"redo",
|
|
17166
|
+
"resetFormatting",
|
|
17167
|
+
"preview",
|
|
17168
|
+
"codeBlock",
|
|
17169
|
+
"spell check"
|
|
17170
|
+
];
|
|
17073
17171
|
default:
|
|
17074
17172
|
return [];
|
|
17075
17173
|
}
|
|
@@ -17082,13 +17180,22 @@ function TetronsToolbar({
|
|
|
17082
17180
|
checked: autoSave,
|
|
17083
17181
|
onChange: (e) => setAutoSave(e.target.checked)
|
|
17084
17182
|
}
|
|
17085
|
-
), /* @__PURE__ */ React16.createElement("label", { htmlFor: "autoSave" }, "Auto Save")), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ React16.createElement(FileGroup, { editor }), /* @__PURE__ */ React16.createElement(ClipboardGroup, { editor }), /* @__PURE__ */ React16.createElement(FontStyleGroup, { editor }), /* @__PURE__ */ React16.createElement(ListAlignGroup, { editor }), ["premium", "platinum"].includes(version) && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(InsertGroup, { editor }), /* @__PURE__ */ React16.createElement(ActionGroup, { editor })),
|
|
17183
|
+
), /* @__PURE__ */ React16.createElement("label", { htmlFor: "autoSave" }, "Auto Save")), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ React16.createElement(FileGroup, { editor }), /* @__PURE__ */ React16.createElement(ClipboardGroup, { editor }), /* @__PURE__ */ React16.createElement(FontStyleGroup, { editor }), /* @__PURE__ */ React16.createElement(ListAlignGroup, { editor }), ["premium", "platinum"].includes(version) && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(InsertGroup, { editor }), /* @__PURE__ */ React16.createElement(ActionGroup, { editor })), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ React16.createElement(
|
|
17086
17184
|
MiscGroup,
|
|
17087
17185
|
{
|
|
17088
17186
|
editor,
|
|
17089
|
-
enabledFeatures: effectiveAddOns
|
|
17187
|
+
enabledFeatures: effectiveAddOns.filter(
|
|
17188
|
+
(a) => [
|
|
17189
|
+
"undo",
|
|
17190
|
+
"redo",
|
|
17191
|
+
"resetFormatting",
|
|
17192
|
+
"preview",
|
|
17193
|
+
"codeBlock",
|
|
17194
|
+
"spell check"
|
|
17195
|
+
].includes(a)
|
|
17196
|
+
)
|
|
17090
17197
|
}
|
|
17091
|
-
),
|
|
17198
|
+
), effectiveAddOns.some((a) => ["ai", "voice to text"].includes(a)) && /* @__PURE__ */ React16.createElement(
|
|
17092
17199
|
AiGroup,
|
|
17093
17200
|
{
|
|
17094
17201
|
editor,
|