tetrons 2.3.97 → 2.3.98

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.mjs CHANGED
@@ -13,7 +13,7 @@ var MathModal_exports = {};
13
13
  __export(MathModal_exports, {
14
14
  default: () => MathModal
15
15
  });
16
- import React13, { useEffect as useEffect7 } from "react";
16
+ import React16, { useEffect as useEffect7 } from "react";
17
17
  import katex2 from "katex";
18
18
  import "katex/dist/katex.min.css";
19
19
  function MathModal({
@@ -33,7 +33,7 @@ function MathModal({
33
33
  return () => window.removeEventListener("keydown", onEsc);
34
34
  }, [isOpen, onClose]);
35
35
  if (!isOpen) return null;
36
- return /* @__PURE__ */ React13.createElement("div", { className: "ai-modal-backdrop" }, /* @__PURE__ */ React13.createElement("div", { className: "ai-modal-content" }, /* @__PURE__ */ React13.createElement("div", { className: "ai-modal-title" }, "Insert LaTeX Equation"), /* @__PURE__ */ React13.createElement(
36
+ return /* @__PURE__ */ React16.createElement("div", { className: "ai-modal-backdrop" }, /* @__PURE__ */ React16.createElement("div", { className: "ai-modal-content" }, /* @__PURE__ */ React16.createElement("div", { className: "ai-modal-title" }, "Insert LaTeX Equation"), /* @__PURE__ */ React16.createElement(
37
37
  "textarea",
38
38
  {
39
39
  className: "ai-modal-textarea",
@@ -41,7 +41,7 @@ function MathModal({
41
41
  value,
42
42
  onChange: (e) => setValue(e.target.value)
43
43
  }
44
- ), /* @__PURE__ */ React13.createElement("div", { className: "ai-modal-preview" }, /* @__PURE__ */ React13.createElement("strong", null, "Preview:"), /* @__PURE__ */ React13.createElement("div", { className: "ai-modal-preview-output" }, /* @__PURE__ */ React13.createElement("span", { dangerouslySetInnerHTML: { __html: renderLatex(value) } }))), /* @__PURE__ */ React13.createElement("div", { className: "ai-modal-actions" }, /* @__PURE__ */ React13.createElement("button", { type: "button", className: "ai-cancel-btn", onClick: onClose }, "Cancel"), /* @__PURE__ */ React13.createElement(
44
+ ), /* @__PURE__ */ React16.createElement("div", { className: "ai-modal-preview" }, /* @__PURE__ */ React16.createElement("strong", null, "Preview:"), /* @__PURE__ */ React16.createElement("div", { className: "ai-modal-preview-output" }, /* @__PURE__ */ React16.createElement("span", { dangerouslySetInnerHTML: { __html: renderLatex(value) } }))), /* @__PURE__ */ React16.createElement("div", { className: "ai-modal-actions" }, /* @__PURE__ */ React16.createElement("button", { type: "button", className: "ai-cancel-btn", onClick: onClose }, "Cancel"), /* @__PURE__ */ React16.createElement(
45
45
  "button",
46
46
  {
47
47
  className: "ai-submit-btn",
@@ -72,7 +72,7 @@ var CodeEditorModal_exports = {};
72
72
  __export(CodeEditorModal_exports, {
73
73
  default: () => CodeEditorModal_default
74
74
  });
75
- import React14, { useState as useState8 } from "react";
75
+ import React17, { useState as useState11 } from "react";
76
76
  import Editor from "@monaco-editor/react";
77
77
  var CodeEditorModal, CodeEditorModal_default;
78
78
  var init_CodeEditorModal = __esm({
@@ -85,10 +85,10 @@ var init_CodeEditorModal = __esm({
85
85
  onSubmitCode,
86
86
  onSubmitCodeWithOutput
87
87
  }) => {
88
- const [language, setLanguage] = useState8("javascript");
89
- const [code, setCode] = useState8("// Write your code here");
90
- const [output, setOutput] = useState8("");
91
- const [loading, setLoading] = useState8(false);
88
+ const [language, setLanguage] = useState11("javascript");
89
+ const [code, setCode] = useState11("// Write your code here");
90
+ const [output, setOutput] = useState11("");
91
+ const [loading, setLoading] = useState11(false);
92
92
  const runCode = async () => {
93
93
  setLoading(true);
94
94
  try {
@@ -124,19 +124,19 @@ ${data.stderr}
124
124
  onClose();
125
125
  };
126
126
  if (!isOpen) return null;
127
- return /* @__PURE__ */ React14.createElement("div", { className: "code-modal-overlay" }, /* @__PURE__ */ React14.createElement("div", { className: "code-modal-content" }, /* @__PURE__ */ React14.createElement("div", { className: "code-modal-header" }, /* @__PURE__ */ React14.createElement("h2", null, "Run Code"), /* @__PURE__ */ React14.createElement("button", { onClick: onClose, className: "code-close-btn" }, "\xD7")), /* @__PURE__ */ React14.createElement("div", { className: "code-modal-controls" }, /* @__PURE__ */ React14.createElement("label", { htmlFor: "language" }, "Language:"), /* @__PURE__ */ React14.createElement(
127
+ return /* @__PURE__ */ React17.createElement("div", { className: "code-modal-overlay" }, /* @__PURE__ */ React17.createElement("div", { className: "code-modal-content" }, /* @__PURE__ */ React17.createElement("div", { className: "code-modal-header" }, /* @__PURE__ */ React17.createElement("h2", null, "Run Code"), /* @__PURE__ */ React17.createElement("button", { onClick: onClose, className: "code-close-btn" }, "\xD7")), /* @__PURE__ */ React17.createElement("div", { className: "code-modal-controls" }, /* @__PURE__ */ React17.createElement("label", { htmlFor: "language" }, "Language:"), /* @__PURE__ */ React17.createElement(
128
128
  "select",
129
129
  {
130
130
  id: "language",
131
131
  value: language,
132
132
  onChange: (e) => setLanguage(e.target.value)
133
133
  },
134
- /* @__PURE__ */ React14.createElement("option", { value: "javascript" }, "JavaScript"),
135
- /* @__PURE__ */ React14.createElement("option", { value: "python" }, "Python"),
136
- /* @__PURE__ */ React14.createElement("option", { value: "cpp" }, "C++"),
137
- /* @__PURE__ */ React14.createElement("option", { value: "java" }, "Java"),
138
- /* @__PURE__ */ React14.createElement("option", { value: "typescript" }, "TypeScript")
139
- ), /* @__PURE__ */ React14.createElement("button", { className: "run-code", onClick: runCode, disabled: loading }, loading ? "Running..." : "Run")), /* @__PURE__ */ React14.createElement(
134
+ /* @__PURE__ */ React17.createElement("option", { value: "javascript" }, "JavaScript"),
135
+ /* @__PURE__ */ React17.createElement("option", { value: "python" }, "Python"),
136
+ /* @__PURE__ */ React17.createElement("option", { value: "cpp" }, "C++"),
137
+ /* @__PURE__ */ React17.createElement("option", { value: "java" }, "Java"),
138
+ /* @__PURE__ */ React17.createElement("option", { value: "typescript" }, "TypeScript")
139
+ ), /* @__PURE__ */ React17.createElement("button", { className: "run-code", onClick: runCode, disabled: loading }, loading ? "Running..." : "Run")), /* @__PURE__ */ React17.createElement(
140
140
  Editor,
141
141
  {
142
142
  height: "50vh",
@@ -145,7 +145,7 @@ ${data.stderr}
145
145
  value: code,
146
146
  onChange: (v) => setCode(v ?? "")
147
147
  }
148
- ), /* @__PURE__ */ React14.createElement("div", { className: "code-output" }, /* @__PURE__ */ React14.createElement("strong", null, "Output:"), /* @__PURE__ */ React14.createElement("pre", null, output.trim() === "" ? "\u2190 Click Run to see output here" : output)), /* @__PURE__ */ React14.createElement("div", { className: "code-submit-buttons-container" }, /* @__PURE__ */ React14.createElement(
148
+ ), /* @__PURE__ */ React17.createElement("div", { className: "code-output" }, /* @__PURE__ */ React17.createElement("strong", null, "Output:"), /* @__PURE__ */ React17.createElement("pre", null, output.trim() === "" ? "\u2190 Click Run to see output here" : output)), /* @__PURE__ */ React17.createElement("div", { className: "code-submit-buttons-container" }, /* @__PURE__ */ React17.createElement(
149
149
  "button",
150
150
  {
151
151
  className: "code-submit-buttons",
@@ -153,7 +153,7 @@ ${data.stderr}
153
153
  disabled: loading || !code
154
154
  },
155
155
  "Submit Code Snippet Only"
156
- ), /* @__PURE__ */ React14.createElement(
156
+ ), /* @__PURE__ */ React17.createElement(
157
157
  "button",
158
158
  {
159
159
  className: "code-submit-buttons",
@@ -224,7 +224,7 @@ var MathInline = Node.create({
224
224
  });
225
225
 
226
226
  // src/components/tetrons/EditorContent.tsx
227
- import React17, { useEffect as useEffect9, useRef as useRef7, useState as useState11 } from "react";
227
+ import React20, { useEffect as useEffect9, useRef as useRef7, useState as useState14 } from "react";
228
228
  import { useEditor, EditorContent as TiptapEditorContent } from "@tiptap/react";
229
229
 
230
230
  // src/utils/licenseTracker.ts
@@ -15942,7 +15942,7 @@ function TableContextMenu({ editor }) {
15942
15942
  }
15943
15943
 
15944
15944
  // src/components/tetrons/toolbar/TetronsToolbar.tsx
15945
- import React16, { useEffect as useEffect8, useState as useState10 } from "react";
15945
+ import React19, { useEffect as useEffect8, useState as useState13 } from "react";
15946
15946
 
15947
15947
  // src/components/tetrons/toolbar/ActionGroup.tsx
15948
15948
  import React5, { useEffect as useEffect5, useRef as useRef3, useState as useState4 } from "react";
@@ -16884,18 +16884,251 @@ function FileGroup({ editor }) {
16884
16884
  }
16885
16885
 
16886
16886
  // src/components/tetrons/toolbar/AIGroup.tsx
16887
- import React12, { useState as useState7, useRef as useRef6 } from "react";
16888
- import { FaMicrophone, FaStop } from "react-icons/fa";
16887
+ import React15, { useState as useState10, useRef as useRef6 } from "react";
16888
+ import { FaMicrophone as FaMicrophone3, FaStop, FaLanguage } from "react-icons/fa";
16889
16889
  import { Waveform } from "@uiball/loaders";
16890
+
16891
+ // src/components/tetrons/toolbar/Tabs.tsx
16892
+ import { useState as useState9 } from "react";
16893
+
16894
+ // src/components/tetrons/toolbar/Converter.tsx
16895
+ import React12, { useState as useState7 } from "react";
16896
+
16897
+ // src/utils/languages.ts
16898
+ var indianLanguages = [
16899
+ "Assamese",
16900
+ "Bengali",
16901
+ "Bodo",
16902
+ "Dogri",
16903
+ "Gujarati",
16904
+ "Hindi",
16905
+ "Kannada",
16906
+ "Kashmiri",
16907
+ "Konkani",
16908
+ "Maithili",
16909
+ "Malayalam",
16910
+ "Manipuri",
16911
+ "Marathi",
16912
+ "Nepali",
16913
+ "Odia",
16914
+ "Punjabi",
16915
+ "Sanskrit",
16916
+ "Santali",
16917
+ "Sindhi",
16918
+ "Tamil",
16919
+ "Telugu",
16920
+ "Urdu",
16921
+ "English"
16922
+ ];
16923
+
16924
+ // src/components/tetrons/toolbar/Converter.tsx
16925
+ import { FaMicrophone } from "react-icons/fa";
16926
+ function Converter({
16927
+ onResult
16928
+ }) {
16929
+ const [sourceLang, setSourceLang] = useState7("Hindi");
16930
+ const [targetLang, setTargetLang] = useState7("Bengali");
16931
+ const [text, setText] = useState7("");
16932
+ const [result, setResult] = useState7("");
16933
+ const handleConvert = async () => {
16934
+ const res = await fetch("https://tetrons.com/api/translate", {
16935
+ method: "POST",
16936
+ headers: { "Content-Type": "application/json" },
16937
+ body: JSON.stringify({ text, sourceLang, targetLang, mode: "convert" })
16938
+ });
16939
+ const data = await res.json();
16940
+ setResult(data.result);
16941
+ if (data.result && onResult) {
16942
+ onResult(data.result);
16943
+ }
16944
+ };
16945
+ const handleSpeakOutput = async () => {
16946
+ if (!result) return;
16947
+ const res = await fetch("https://tetrons.com/api/speak", {
16948
+ method: "POST",
16949
+ headers: { "Content-Type": "application/json" },
16950
+ body: JSON.stringify({ text: result, lang: targetLang })
16951
+ });
16952
+ const blob = await res.blob();
16953
+ const url = URL.createObjectURL(blob);
16954
+ const audio = new Audio(url);
16955
+ audio.play();
16956
+ };
16957
+ return /* @__PURE__ */ React12.createElement("div", { className: "container" }, /* @__PURE__ */ React12.createElement("div", { className: "field" }, /* @__PURE__ */ React12.createElement("label", { htmlFor: "sourceLang", className: "label" }, "Source Language:"), /* @__PURE__ */ React12.createElement(
16958
+ "select",
16959
+ {
16960
+ id: "sourceLang",
16961
+ value: sourceLang,
16962
+ onChange: (e) => setSourceLang(e.target.value),
16963
+ className: "select"
16964
+ },
16965
+ indianLanguages.map((lang) => /* @__PURE__ */ React12.createElement("option", { key: lang }, lang))
16966
+ )), /* @__PURE__ */ React12.createElement("div", { className: "field" }, /* @__PURE__ */ React12.createElement("label", { htmlFor: "targetLang", className: "label" }, "Target Language:"), /* @__PURE__ */ React12.createElement(
16967
+ "select",
16968
+ {
16969
+ id: "targetLang",
16970
+ value: targetLang,
16971
+ onChange: (e) => setTargetLang(e.target.value),
16972
+ className: "select"
16973
+ },
16974
+ indianLanguages.map((lang) => /* @__PURE__ */ React12.createElement("option", { key: lang }, lang))
16975
+ )), /* @__PURE__ */ React12.createElement("div", { className: "field" }, /* @__PURE__ */ React12.createElement("label", { htmlFor: "inputText", className: "label" }, "Enter Text:"), /* @__PURE__ */ React12.createElement(
16976
+ "textarea",
16977
+ {
16978
+ id: "inputText",
16979
+ placeholder: "Enter text...",
16980
+ value: text,
16981
+ onChange: (e) => setText(e.target.value),
16982
+ className: "textarea"
16983
+ }
16984
+ )), /* @__PURE__ */ React12.createElement("button", { type: "button", onClick: handleConvert, className: "button" }, "Convert"), /* @__PURE__ */ React12.createElement("div", { className: "outputWrapper" }, /* @__PURE__ */ React12.createElement("div", { className: "output" }, result), result && /* @__PURE__ */ React12.createElement(
16985
+ "button",
16986
+ {
16987
+ type: "button",
16988
+ onClick: handleSpeakOutput,
16989
+ className: "iconButton",
16990
+ "aria-label": "Play conversion",
16991
+ title: "Play conversion"
16992
+ },
16993
+ /* @__PURE__ */ React12.createElement(FaMicrophone, null)
16994
+ )));
16995
+ }
16996
+
16997
+ // src/components/tetrons/toolbar/Translator.tsx
16998
+ import React13, { useState as useState8 } from "react";
16999
+ import { FaMicrophone as FaMicrophone2, FaVolumeUp } from "react-icons/fa";
17000
+ function Translator({
17001
+ onResult
17002
+ }) {
17003
+ const [sourceLang, setSourceLang] = useState8("Hindi");
17004
+ const [targetLang, setTargetLang] = useState8("English");
17005
+ const [text, setText] = useState8("");
17006
+ const [result, setResult] = useState8("");
17007
+ const [listening, setListening] = useState8(false);
17008
+ const handleTranslate = async () => {
17009
+ const res = await fetch("https://tetrons.com/api/translate", {
17010
+ method: "POST",
17011
+ headers: { "Content-Type": "application/json" },
17012
+ body: JSON.stringify({ text, sourceLang, targetLang, mode: "translate" })
17013
+ });
17014
+ const data = await res.json();
17015
+ setResult(data.result);
17016
+ if (data.result && onResult) {
17017
+ onResult(data.result);
17018
+ }
17019
+ };
17020
+ const handleMicInput = () => {
17021
+ const SpeechRecognitionClass = window.SpeechRecognition || window.webkitSpeechRecognition;
17022
+ if (!SpeechRecognitionClass) {
17023
+ alert("Speech recognition is not supported in this browser.");
17024
+ return;
17025
+ }
17026
+ const recognition = new SpeechRecognitionClass();
17027
+ recognition.lang = sourceLang === "English" ? "en-IN" : "hi-IN";
17028
+ recognition.interimResults = false;
17029
+ recognition.onstart = () => setListening(true);
17030
+ recognition.onend = () => setListening(false);
17031
+ recognition.onresult = (event) => {
17032
+ const transcript = event.results[0][0].transcript;
17033
+ setText((prev) => prev ? prev + " " + transcript : transcript);
17034
+ };
17035
+ recognition.start();
17036
+ };
17037
+ const handleSpeakOutput = async () => {
17038
+ if (!result) return;
17039
+ const res = await fetch("/api/speak", {
17040
+ method: "POST",
17041
+ headers: { "Content-Type": "application/json" },
17042
+ body: JSON.stringify({ text: result, lang: targetLang })
17043
+ });
17044
+ const blob = await res.blob();
17045
+ const url = URL.createObjectURL(blob);
17046
+ const audio = new Audio(url);
17047
+ audio.play();
17048
+ };
17049
+ return /* @__PURE__ */ React13.createElement("div", { className: "container" }, /* @__PURE__ */ React13.createElement("div", { className: "field" }, /* @__PURE__ */ React13.createElement("label", { htmlFor: "sourceLang", className: "label" }, "Source Language:"), /* @__PURE__ */ React13.createElement(
17050
+ "select",
17051
+ {
17052
+ id: "sourceLang",
17053
+ value: sourceLang,
17054
+ onChange: (e) => setSourceLang(e.target.value),
17055
+ className: "select"
17056
+ },
17057
+ indianLanguages.map((lang) => /* @__PURE__ */ React13.createElement("option", { key: lang }, lang))
17058
+ )), /* @__PURE__ */ React13.createElement("div", { className: "field" }, /* @__PURE__ */ React13.createElement("label", { htmlFor: "targetLang", className: "label" }, "Target Language:"), /* @__PURE__ */ React13.createElement(
17059
+ "select",
17060
+ {
17061
+ id: "targetLang",
17062
+ value: targetLang,
17063
+ onChange: (e) => setTargetLang(e.target.value),
17064
+ className: "select"
17065
+ },
17066
+ indianLanguages.map((lang) => /* @__PURE__ */ React13.createElement("option", { key: lang }, lang))
17067
+ )), /* @__PURE__ */ React13.createElement("div", { className: "field" }, /* @__PURE__ */ React13.createElement("label", { htmlFor: "inputText", className: "label" }, "Enter Text:"), /* @__PURE__ */ React13.createElement("div", { className: "textareaWrapper" }, /* @__PURE__ */ React13.createElement(
17068
+ "textarea",
17069
+ {
17070
+ id: "inputText",
17071
+ placeholder: "Enter text...",
17072
+ value: text,
17073
+ onChange: (e) => setText(e.target.value),
17074
+ className: "textarea"
17075
+ }
17076
+ ), /* @__PURE__ */ React13.createElement(
17077
+ "button",
17078
+ {
17079
+ type: "button",
17080
+ onClick: handleMicInput,
17081
+ className: "iconButton",
17082
+ title: listening ? "Listening..." : "Start voice input"
17083
+ },
17084
+ /* @__PURE__ */ React13.createElement(FaMicrophone2, { color: listening ? "red" : "black" })
17085
+ ))), /* @__PURE__ */ React13.createElement("button", { type: "button", onClick: handleTranslate, className: "button" }, "Translate"), /* @__PURE__ */ React13.createElement("div", { className: "outputWrapper" }, /* @__PURE__ */ React13.createElement("div", { className: "output" }, result), result && /* @__PURE__ */ React13.createElement(
17086
+ "button",
17087
+ {
17088
+ type: "button",
17089
+ onClick: handleSpeakOutput,
17090
+ className: "iconButton",
17091
+ "aria-label": "Play translation",
17092
+ title: "Play translation"
17093
+ },
17094
+ /* @__PURE__ */ React13.createElement(FaVolumeUp, null)
17095
+ )));
17096
+ }
17097
+
17098
+ // src/components/tetrons/toolbar/Tabs.tsx
17099
+ import * as React14 from "react";
17100
+ function Tabs({ onResult }) {
17101
+ const [activeTab, setActiveTab] = useState9("convert");
17102
+ return /* @__PURE__ */ React14.createElement("div", null, /* @__PURE__ */ React14.createElement("div", { className: "tabHeader" }, /* @__PURE__ */ React14.createElement(
17103
+ "button",
17104
+ {
17105
+ type: "button",
17106
+ className: `$"tabButton" ${activeTab === "convert" ? "active" : ""}`,
17107
+ onClick: () => setActiveTab("convert")
17108
+ },
17109
+ "Convert"
17110
+ ), /* @__PURE__ */ React14.createElement(
17111
+ "button",
17112
+ {
17113
+ type: "button",
17114
+ className: `$"tabButton" ${activeTab === "translate" ? "active" : ""}`,
17115
+ onClick: () => setActiveTab("translate")
17116
+ },
17117
+ "Translate"
17118
+ )), /* @__PURE__ */ React14.createElement("div", { className: "tabContent" }, activeTab === "convert" ? /* @__PURE__ */ React14.createElement(Converter, { onResult }) : /* @__PURE__ */ React14.createElement(Translator, { onResult })));
17119
+ }
17120
+
17121
+ // src/components/tetrons/toolbar/AIGroup.tsx
16890
17122
  function AiGroup({ editor, enabledFeatures }) {
16891
- const [isRecording, setIsRecording] = useState7(false);
16892
- const [audioBlob, setAudioBlob] = useState7(null);
16893
- const [isTranscribing, setIsTranscribing] = useState7(false);
16894
- const [transcriptionError, setTranscriptionError] = useState7("");
16895
- const [showPromptInput, setShowPromptInput] = useState7(false);
16896
- const [prompt2, setPrompt] = useState7("");
16897
- const [isLoadingAI, setIsLoadingAI] = useState7(false);
16898
- const [aiError, setAiError] = useState7("");
17123
+ const [isRecording, setIsRecording] = useState10(false);
17124
+ const [audioBlob, setAudioBlob] = useState10(null);
17125
+ const [isTranscribing, setIsTranscribing] = useState10(false);
17126
+ const [transcriptionError, setTranscriptionError] = useState10("");
17127
+ const [showPromptInput, setShowPromptInput] = useState10(false);
17128
+ const [prompt2, setPrompt] = useState10("");
17129
+ const [isLoadingAI, setIsLoadingAI] = useState10(false);
17130
+ const [aiError, setAiError] = useState10("");
17131
+ const [showLangModal, setShowLangModal] = useState10(false);
16899
17132
  const mediaRecorderRef = useRef6(null);
16900
17133
  const chunksRef = useRef6([]);
16901
17134
  const startRecording = async () => {
@@ -16970,7 +17203,16 @@ function AiGroup({ editor, enabledFeatures }) {
16970
17203
  setIsLoadingAI(false);
16971
17204
  }
16972
17205
  };
16973
- return /* @__PURE__ */ React12.createElement("div", { className: "group flex flex-col gap-2 items-start" }, /* @__PURE__ */ React12.createElement("div", { className: "flex gap-2 items-center" }, enabledFeatures.includes("voice to text") && /* @__PURE__ */ React12.createElement(React12.Fragment, null, !isRecording ? /* @__PURE__ */ React12.createElement(
17206
+ const handleLangClick = () => {
17207
+ setShowLangModal(true);
17208
+ };
17209
+ const handleLangResult = (output) => {
17210
+ if (output) {
17211
+ editor.commands.insertContent(output);
17212
+ setShowLangModal(false);
17213
+ }
17214
+ };
17215
+ return /* @__PURE__ */ React15.createElement("div", { className: "group flex flex-col gap-2 items-start" }, /* @__PURE__ */ React15.createElement("div", { className: "flex gap-2 items-center" }, enabledFeatures.includes("voice to text") && /* @__PURE__ */ React15.createElement(React15.Fragment, null, !isRecording ? /* @__PURE__ */ React15.createElement(
16974
17216
  "button",
16975
17217
  {
16976
17218
  type: "button",
@@ -16978,8 +17220,8 @@ function AiGroup({ editor, enabledFeatures }) {
16978
17220
  className: "icon-btn",
16979
17221
  title: "Start Voice Input"
16980
17222
  },
16981
- /* @__PURE__ */ React12.createElement(FaMicrophone, { size: 18 })
16982
- ) : /* @__PURE__ */ React12.createElement(
17223
+ /* @__PURE__ */ React15.createElement(FaMicrophone3, { size: 18 })
17224
+ ) : /* @__PURE__ */ React15.createElement(
16983
17225
  "button",
16984
17226
  {
16985
17227
  type: "button",
@@ -16987,8 +17229,8 @@ function AiGroup({ editor, enabledFeatures }) {
16987
17229
  className: "icon-btn stop-btn",
16988
17230
  title: "Stop Recording"
16989
17231
  },
16990
- /* @__PURE__ */ React12.createElement(FaStop, { size: 18 })
16991
- )), enabledFeatures.includes("ai") && /* @__PURE__ */ React12.createElement(
17232
+ /* @__PURE__ */ React15.createElement(FaStop, { size: 18 })
17233
+ )), enabledFeatures.includes("ai") && /* @__PURE__ */ React15.createElement(
16992
17234
  "button",
16993
17235
  {
16994
17236
  type: "button",
@@ -16997,7 +17239,16 @@ function AiGroup({ editor, enabledFeatures }) {
16997
17239
  title: "AI Assist"
16998
17240
  },
16999
17241
  "AI"
17000
- )), 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) })), showPromptInput && /* @__PURE__ */ React12.createElement("div", { className: "ai-modal-backdrop" }, /* @__PURE__ */ React12.createElement("div", { className: "ai-modal-content" }, /* @__PURE__ */ React12.createElement("h2", { className: "ai-modal-title" }, "AI Prompt"), /* @__PURE__ */ React12.createElement(
17242
+ ), enabledFeatures.includes("language") && /* @__PURE__ */ React15.createElement(
17243
+ "button",
17244
+ {
17245
+ type: "button",
17246
+ onClick: handleLangClick,
17247
+ className: "lang-button ml-2",
17248
+ title: "Convert/Translate"
17249
+ },
17250
+ /* @__PURE__ */ React15.createElement(FaLanguage, { size: 18 })
17251
+ )), isRecording && /* @__PURE__ */ React15.createElement("div", { className: "flex flex-col items-center" }, /* @__PURE__ */ React15.createElement(Waveform, { size: 30, lineWeight: 3.5, speed: 1, color: "#4F46E5" }), /* @__PURE__ */ React15.createElement("p", { className: "text-sm mt-1 text-gray-600" }, "Recording...")), isTranscribing && /* @__PURE__ */ React15.createElement("p", { className: "text-sm text-gray-500" }, "Transcribing..."), transcriptionError && /* @__PURE__ */ React15.createElement("p", { className: "text-sm text-red-600" }, transcriptionError), audioBlob && /* @__PURE__ */ React15.createElement("div", { className: "mt-2" }, /* @__PURE__ */ React15.createElement("audio", { controls: true, src: URL.createObjectURL(audioBlob) })), showPromptInput && /* @__PURE__ */ React15.createElement("div", { className: "ai-modal-backdrop" }, /* @__PURE__ */ React15.createElement("div", { className: "ai-modal-content" }, /* @__PURE__ */ React15.createElement("h2", { className: "ai-modal-title" }, "AI Prompt"), /* @__PURE__ */ React15.createElement(
17001
17252
  "textarea",
17002
17253
  {
17003
17254
  className: "ai-modal-textarea",
@@ -17005,7 +17256,7 @@ function AiGroup({ editor, enabledFeatures }) {
17005
17256
  onChange: (e) => setPrompt(e.target.value),
17006
17257
  placeholder: "Enter your prompt here..."
17007
17258
  }
17008
- ), aiError && /* @__PURE__ */ React12.createElement("p", { className: "ai-modal-error" }, aiError), /* @__PURE__ */ React12.createElement("div", { className: "ai-modal-actions" }, /* @__PURE__ */ React12.createElement(
17259
+ ), aiError && /* @__PURE__ */ React15.createElement("p", { className: "ai-modal-error" }, aiError), /* @__PURE__ */ React15.createElement("div", { className: "ai-modal-actions" }, /* @__PURE__ */ React15.createElement(
17009
17260
  "button",
17010
17261
  {
17011
17262
  type: "button",
@@ -17013,7 +17264,7 @@ function AiGroup({ editor, enabledFeatures }) {
17013
17264
  className: "ai-cancel-btn"
17014
17265
  },
17015
17266
  "Cancel"
17016
- ), /* @__PURE__ */ React12.createElement(
17267
+ ), /* @__PURE__ */ React15.createElement(
17017
17268
  "button",
17018
17269
  {
17019
17270
  type: "button",
@@ -17022,11 +17273,19 @@ function AiGroup({ editor, enabledFeatures }) {
17022
17273
  className: "ai-submit-btn"
17023
17274
  },
17024
17275
  isLoadingAI ? "Generating..." : "Submit"
17276
+ )))), showLangModal && /* @__PURE__ */ React15.createElement("div", { className: "ai-modal-backdrop" }, /* @__PURE__ */ React15.createElement("div", { className: "ai-modal-content" }, /* @__PURE__ */ React15.createElement("h2", { className: "ai-modal-title" }, "Convert / Translate"), /* @__PURE__ */ React15.createElement(Tabs, { onResult: handleLangResult }), /* @__PURE__ */ React15.createElement("div", { className: "ai-modal-actions mt-2" }, /* @__PURE__ */ React15.createElement(
17277
+ "button",
17278
+ {
17279
+ type: "button",
17280
+ onClick: () => setShowLangModal(false),
17281
+ className: "ai-cancel-btn"
17282
+ },
17283
+ "Close"
17025
17284
  )))));
17026
17285
  }
17027
17286
 
17028
17287
  // src/components/tetrons/toolbar/AddOnGroup.tsx
17029
- import React15, { useState as useState9 } from "react";
17288
+ import React18, { useState as useState12 } from "react";
17030
17289
  import { SquareRadical, MessageSquareCode } from "lucide-react";
17031
17290
  import dynamic from "next/dynamic";
17032
17291
  import "katex/dist/katex.min.css";
@@ -17035,9 +17294,9 @@ var CodeEditorModal2 = dynamic(() => Promise.resolve().then(() => (init_CodeEdit
17035
17294
  ssr: false
17036
17295
  });
17037
17296
  var AddOnGroup = ({ editor, addOns }) => {
17038
- const [isMathModalOpen, setMathModalOpen] = useState9(false);
17039
- const [latexValue, setLatexValue] = useState9("");
17040
- const [isCodeModalOpen, setCodeModalOpen] = useState9(false);
17297
+ const [isMathModalOpen, setMathModalOpen] = useState12(false);
17298
+ const [latexValue, setLatexValue] = useState12("");
17299
+ const [isCodeModalOpen, setCodeModalOpen] = useState12(false);
17041
17300
  if (!editor) return null;
17042
17301
  const insertCodeBlock = () => setCodeModalOpen(true);
17043
17302
  const handleMathInsert = (latex) => {
@@ -17068,7 +17327,7 @@ var AddOnGroup = ({ editor, addOns }) => {
17068
17327
  }).run();
17069
17328
  setCodeModalOpen(false);
17070
17329
  };
17071
- return /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement("div", { className: "group flex gap-2 items-center" }, addOns.includes("code") && /* @__PURE__ */ React15.createElement(
17330
+ return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement("div", { className: "group flex gap-2 items-center" }, addOns.includes("code") && /* @__PURE__ */ React18.createElement(
17072
17331
  "button",
17073
17332
  {
17074
17333
  type: "button",
@@ -17076,8 +17335,8 @@ var AddOnGroup = ({ editor, addOns }) => {
17076
17335
  className: "addon-btn",
17077
17336
  title: "Open Code Editor"
17078
17337
  },
17079
- /* @__PURE__ */ React15.createElement(MessageSquareCode, { size: 18 })
17080
- ), addOns.includes("math") && /* @__PURE__ */ React15.createElement(
17338
+ /* @__PURE__ */ React18.createElement(MessageSquareCode, { size: 18 })
17339
+ ), addOns.includes("math") && /* @__PURE__ */ React18.createElement(
17081
17340
  "button",
17082
17341
  {
17083
17342
  type: "button",
@@ -17085,8 +17344,8 @@ var AddOnGroup = ({ editor, addOns }) => {
17085
17344
  className: "addon-btn",
17086
17345
  title: "Insert Math Equation"
17087
17346
  },
17088
- /* @__PURE__ */ React15.createElement(SquareRadical, { size: 18 })
17089
- )), addOns.includes("math") && /* @__PURE__ */ React15.createElement(
17347
+ /* @__PURE__ */ React18.createElement(SquareRadical, { size: 18 })
17348
+ )), addOns.includes("math") && /* @__PURE__ */ React18.createElement(
17090
17349
  MathModal2,
17091
17350
  {
17092
17351
  isOpen: isMathModalOpen,
@@ -17095,7 +17354,7 @@ var AddOnGroup = ({ editor, addOns }) => {
17095
17354
  value: latexValue,
17096
17355
  setValue: setLatexValue
17097
17356
  }
17098
- ), addOns.includes("code") && /* @__PURE__ */ React15.createElement(
17357
+ ), addOns.includes("code") && /* @__PURE__ */ React18.createElement(
17099
17358
  CodeEditorModal2,
17100
17359
  {
17101
17360
  isOpen: isCodeModalOpen,
@@ -17113,7 +17372,7 @@ function TetronsToolbar({
17113
17372
  version,
17114
17373
  addOns = []
17115
17374
  }) {
17116
- const [autoSave, setAutoSave] = useState10(false);
17375
+ const [autoSave, setAutoSave] = useState13(false);
17117
17376
  useEffect8(() => {
17118
17377
  if (!editor || !autoSave) return;
17119
17378
  const handleUpdate = () => {
@@ -17151,7 +17410,7 @@ function TetronsToolbar({
17151
17410
  return [];
17152
17411
  }
17153
17412
  })();
17154
- return /* @__PURE__ */ React16.createElement("div", { className: "tetrons-toolbar" }, version !== "free" && /* @__PURE__ */ React16.createElement("div", { className: "group" }, /* @__PURE__ */ React16.createElement(
17413
+ return /* @__PURE__ */ React19.createElement("div", { className: "tetrons-toolbar" }, version !== "free" && /* @__PURE__ */ React19.createElement("div", { className: "group" }, /* @__PURE__ */ React19.createElement(
17155
17414
  "input",
17156
17415
  {
17157
17416
  type: "checkbox",
@@ -17159,7 +17418,7 @@ function TetronsToolbar({
17159
17418
  checked: autoSave,
17160
17419
  onChange: (e) => setAutoSave(e.target.checked)
17161
17420
  }
17162
- ), /* @__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(
17421
+ ), /* @__PURE__ */ React19.createElement("label", { htmlFor: "autoSave" }, "Auto Save")), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ React19.createElement(FileGroup, { editor }), /* @__PURE__ */ React19.createElement(ClipboardGroup, { editor }), /* @__PURE__ */ React19.createElement(FontStyleGroup, { editor }), /* @__PURE__ */ React19.createElement(ListAlignGroup, { editor }), ["premium", "platinum"].includes(version) && /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(InsertGroup, { editor }), /* @__PURE__ */ React19.createElement(ActionGroup, { editor })), ["pro", "premium", "platinum"].includes(version) && /* @__PURE__ */ React19.createElement(
17163
17422
  MiscGroup,
17164
17423
  {
17165
17424
  editor,
@@ -17174,18 +17433,18 @@ function TetronsToolbar({
17174
17433
  ].includes(a)
17175
17434
  )
17176
17435
  }
17177
- ), (version === "platinum" || effectiveAddOns.includes("ai") || effectiveAddOns.includes("voice to text")) && /* @__PURE__ */ React16.createElement(
17436
+ ), (version === "platinum" || effectiveAddOns.includes("ai") || effectiveAddOns.includes("voice to text")) && /* @__PURE__ */ React19.createElement(
17178
17437
  AiGroup,
17179
17438
  {
17180
17439
  editor,
17181
17440
  enabledFeatures: [
17182
- ...version === "platinum" ? ["ai"] : [],
17441
+ ...version === "platinum" ? ["ai", "language"] : [],
17183
17442
  ...effectiveAddOns.filter(
17184
- (a) => ["ai", "voice to text"].includes(a)
17443
+ (a) => ["ai", "voice to text", "language"].includes(a)
17185
17444
  )
17186
17445
  ]
17187
17446
  }
17188
- ), effectiveAddOns.some((a) => a === "math" || a === "code") && /* @__PURE__ */ React16.createElement(
17447
+ ), effectiveAddOns.some((a) => a === "math" || a === "code") && /* @__PURE__ */ React19.createElement(
17189
17448
  AddOnGroup_default,
17190
17449
  {
17191
17450
  editor,
@@ -17200,14 +17459,14 @@ lowlight.register("js", javascript);
17200
17459
  lowlight.register("ts", typescript);
17201
17460
  function EditorContent({ apiKey }) {
17202
17461
  const typo = useTypo();
17203
- const [isValid, setIsValid] = useState11(null);
17204
- const [error, setError] = useState11(null);
17205
- const [versions, setVersions] = useState11([]);
17206
- const [userVersion, setUserVersion] = useState11(null);
17207
- const [currentVersionIndex, setCurrentVersionIndex] = useState11(
17462
+ const [isValid, setIsValid] = useState14(null);
17463
+ const [error, setError] = useState14(null);
17464
+ const [versions, setVersions] = useState14([]);
17465
+ const [userVersion, setUserVersion] = useState14(null);
17466
+ const [currentVersionIndex, setCurrentVersionIndex] = useState14(
17208
17467
  null
17209
17468
  );
17210
- const [addOns, setAddOns] = useState11([]);
17469
+ const [addOns, setAddOns] = useState14([]);
17211
17470
  const wrapperRef = useRef7(null);
17212
17471
  const API_BASE_URL = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_TETRONS_API_URL ? process.env.NEXT_PUBLIC_TETRONS_API_URL : "https://staging.tetrons.com";
17213
17472
  useEffect9(() => {
@@ -17318,15 +17577,15 @@ function EditorContent({ apiKey }) {
17318
17577
  }
17319
17578
  };
17320
17579
  if (isValid === false) {
17321
- return /* @__PURE__ */ React17.createElement("div", { className: "editor-error" }, "\u26A0\uFE0F ", error);
17580
+ return /* @__PURE__ */ React20.createElement("div", { className: "editor-error" }, "\u26A0\uFE0F ", error);
17322
17581
  }
17323
17582
  if (isValid === null) {
17324
- return /* @__PURE__ */ React17.createElement("div", { className: "editor-loading" }, "\u{1F50D} Validating license...");
17583
+ return /* @__PURE__ */ React20.createElement("div", { className: "editor-loading" }, "\u{1F50D} Validating license...");
17325
17584
  }
17326
17585
  if (!typo) {
17327
- return /* @__PURE__ */ React17.createElement("div", { className: "editor-loading" }, "\u{1F4D6} Loading dictionary...");
17586
+ return /* @__PURE__ */ React20.createElement("div", { className: "editor-loading" }, "\u{1F4D6} Loading dictionary...");
17328
17587
  }
17329
- return /* @__PURE__ */ React17.createElement("div", { className: "editor-container" }, userVersion !== "free" && /* @__PURE__ */ React17.createElement("div", { className: "editor-toolbar" }, /* @__PURE__ */ React17.createElement(
17588
+ return /* @__PURE__ */ React20.createElement("div", { className: "editor-container" }, userVersion !== "free" && /* @__PURE__ */ React20.createElement("div", { className: "editor-toolbar" }, /* @__PURE__ */ React20.createElement(
17330
17589
  "button",
17331
17590
  {
17332
17591
  type: "button",
@@ -17335,7 +17594,7 @@ function EditorContent({ apiKey }) {
17335
17594
  className: "editor-save-btn"
17336
17595
  },
17337
17596
  "Save Version"
17338
- ), /* @__PURE__ */ React17.createElement("div", { className: "editor-versions-wrapper" }, versions.length === 0 ? /* @__PURE__ */ React17.createElement("span", { className: "editor-no-versions" }, "No saved versions") : versions.map((_, idx) => /* @__PURE__ */ React17.createElement(
17597
+ ), /* @__PURE__ */ React20.createElement("div", { className: "editor-versions-wrapper" }, versions.length === 0 ? /* @__PURE__ */ React20.createElement("span", { className: "editor-no-versions" }, "No saved versions") : versions.map((_, idx) => /* @__PURE__ */ React20.createElement(
17339
17598
  "button",
17340
17599
  {
17341
17600
  key: idx,
@@ -17345,14 +17604,14 @@ function EditorContent({ apiKey }) {
17345
17604
  title: `Restore Version ${idx + 1}`
17346
17605
  },
17347
17606
  `V${idx + 1}`
17348
- )))), editor && userVersion && /* @__PURE__ */ React17.createElement(TetronsToolbar, { editor, version: userVersion, addOns }), /* @__PURE__ */ React17.createElement(
17607
+ )))), editor && userVersion && /* @__PURE__ */ React20.createElement(TetronsToolbar, { editor, version: userVersion, addOns }), /* @__PURE__ */ React20.createElement(
17349
17608
  "div",
17350
17609
  {
17351
17610
  ref: wrapperRef,
17352
17611
  className: "editor-content-wrapper",
17353
17612
  onClick: handleEditorClick
17354
17613
  },
17355
- editor ? /* @__PURE__ */ React17.createElement(React17.Fragment, null, /* @__PURE__ */ React17.createElement(TiptapEditorContent, { editor }), /* @__PURE__ */ React17.createElement(TableContextMenu, { editor })) : /* @__PURE__ */ React17.createElement("div", { className: "editor-loading" }, "Loading editor...")
17614
+ editor ? /* @__PURE__ */ React20.createElement(React20.Fragment, null, /* @__PURE__ */ React20.createElement(TiptapEditorContent, { editor }), /* @__PURE__ */ React20.createElement(TableContextMenu, { editor })) : /* @__PURE__ */ React20.createElement("div", { className: "editor-loading" }, "Loading editor...")
17356
17615
  ));
17357
17616
  }
17358
17617