Spaces:
Running
Running
Create app.py
Browse files
app.py
ADDED
@@ -0,0 +1,429 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import subprocess
|
3 |
+
import tempfile
|
4 |
+
import base64
|
5 |
+
from pathlib import Path
|
6 |
+
import os
|
7 |
+
|
8 |
+
# Set page configuration
|
9 |
+
st.set_page_config(page_title="LaTeX Editor & Compiler", page_icon="📝", layout="wide")
|
10 |
+
|
11 |
+
# Function to convert LaTeX to PDF
|
12 |
+
def latex_to_pdf(latex_code):
|
13 |
+
with tempfile.TemporaryDirectory() as temp_dir:
|
14 |
+
temp_path = Path(temp_dir)
|
15 |
+
tex_file = temp_path / "document.tex"
|
16 |
+
pdf_file = temp_path / "document.pdf"
|
17 |
+
|
18 |
+
# Write LaTeX code to file
|
19 |
+
with open(tex_file, "w") as f:
|
20 |
+
f.write(latex_code)
|
21 |
+
|
22 |
+
try:
|
23 |
+
# Run pdflatex to compile the LaTeX file
|
24 |
+
process = subprocess.run(
|
25 |
+
["pdflatex", "-interaction=nonstopmode", "-output-directory", temp_dir, str(tex_file)],
|
26 |
+
capture_output=True,
|
27 |
+
text=True
|
28 |
+
)
|
29 |
+
|
30 |
+
# Check if PDF was created
|
31 |
+
if pdf_file.exists():
|
32 |
+
with open(pdf_file, "rb") as file:
|
33 |
+
pdf_data = file.read()
|
34 |
+
return pdf_data, process.stdout, process.stderr
|
35 |
+
else:
|
36 |
+
return None, process.stdout, process.stderr
|
37 |
+
except Exception as e:
|
38 |
+
return None, "", str(e)
|
39 |
+
|
40 |
+
# Function to display PDF
|
41 |
+
def display_pdf(pdf_data):
|
42 |
+
base64_pdf = base64.b64encode(pdf_data).decode('utf-8')
|
43 |
+
pdf_display = f"""
|
44 |
+
<iframe
|
45 |
+
src="data:application/pdf;base64,{base64_pdf}"
|
46 |
+
width="100%"
|
47 |
+
height="600"
|
48 |
+
style="border: none;"
|
49 |
+
></iframe>
|
50 |
+
"""
|
51 |
+
st.markdown(pdf_display, unsafe_allow_html=True)
|
52 |
+
|
53 |
+
# Function to create download link for PDF
|
54 |
+
def get_download_link(pdf_data, filename="document.pdf"):
|
55 |
+
b64_pdf = base64.b64encode(pdf_data).decode()
|
56 |
+
return f'<a href="data:application/pdf;base64,{b64_pdf}" download="{filename}" class="download-button">Download PDF</a>'
|
57 |
+
|
58 |
+
# LaTeX package reference
|
59 |
+
latex_packages = {
|
60 |
+
"Document": {
|
61 |
+
"\\usepackage{geometry}": "Page layout customization",
|
62 |
+
"\\usepackage{fancyhdr}": "Custom headers and footers",
|
63 |
+
"\\usepackage{titlesec}": "Title formatting",
|
64 |
+
"\\usepackage{hyperref}": "Hyperlinks and PDF metadata"
|
65 |
+
},
|
66 |
+
"Math": {
|
67 |
+
"\\usepackage{amsmath}": "Enhanced math formatting",
|
68 |
+
"\\usepackage{amssymb}": "Mathematical symbols",
|
69 |
+
"\\usepackage{mathtools}": "Extensions to amsmath",
|
70 |
+
"\\usepackage{physics}": "Physics notation"
|
71 |
+
},
|
72 |
+
"Graphics": {
|
73 |
+
"\\usepackage{graphicx}": "Include images",
|
74 |
+
"\\usepackage{tikz}": "Create vector graphics",
|
75 |
+
"\\usepackage{pgfplots}": "Create plots",
|
76 |
+
"\\usepackage{float}": "Better figure placement"
|
77 |
+
},
|
78 |
+
"Tables": {
|
79 |
+
"\\usepackage{tabularx}": "Flexible tables",
|
80 |
+
"\\usepackage{booktabs}": "Professional tables",
|
81 |
+
"\\usepackage{colortbl}": "Colored tables",
|
82 |
+
"\\usepackage{multirow}": "Multi-row cells"
|
83 |
+
},
|
84 |
+
"Content": {
|
85 |
+
"\\usepackage{listings}": "Code syntax highlighting",
|
86 |
+
"\\usepackage{minted}": "Advanced code highlighting",
|
87 |
+
"\\usepackage{biblatex}": "Bibliography management",
|
88 |
+
"\\usepackage{xcolor}": "Color support"
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
# LaTeX commands reference
|
93 |
+
latex_commands = {
|
94 |
+
"Document Structure": {
|
95 |
+
"\\documentclass{article}": "Specifies the type of document",
|
96 |
+
"\\begin{document}": "Starts the document content",
|
97 |
+
"\\end{document}": "Ends the document content",
|
98 |
+
"\\title{...}": "Sets the document title",
|
99 |
+
"\\author{...}": "Sets the document author",
|
100 |
+
"\\date{...}": "Sets the document date",
|
101 |
+
"\\maketitle": "Prints the title, author, and date"
|
102 |
+
},
|
103 |
+
"Sections": {
|
104 |
+
"\\section{...}": "Creates a section",
|
105 |
+
"\\subsection{...}": "Creates a subsection",
|
106 |
+
"\\subsubsection{...}": "Creates a subsubsection",
|
107 |
+
"\\paragraph{...}": "Creates a paragraph heading",
|
108 |
+
"\\tableofcontents": "Generates a table of contents"
|
109 |
+
},
|
110 |
+
"Text Formatting": {
|
111 |
+
"\\textbf{...}": "Bold text",
|
112 |
+
"\\textit{...}": "Italic text",
|
113 |
+
"\\underline{...}": "Underlined text",
|
114 |
+
"\\emph{...}": "Emphasized text",
|
115 |
+
"\\texttt{...}": "Typewriter text",
|
116 |
+
"\\textsc{...}": "Small caps text",
|
117 |
+
"\\textsf{...}": "Sans-serif text",
|
118 |
+
"\\color{red}{...}": "Colored text (requires xcolor)"
|
119 |
+
},
|
120 |
+
"Math": {
|
121 |
+
"$...$": "Inline math mode",
|
122 |
+
"$$...$$": "Display math mode",
|
123 |
+
"\\begin{equation}...\\end{equation}": "Numbered equation",
|
124 |
+
"\\begin{align}...\\end{align}": "Aligned equations",
|
125 |
+
"\\frac{num}{denom}": "Fraction",
|
126 |
+
"\\dfrac{num}{denom}": "Display fraction",
|
127 |
+
"\\sqrt{...}": "Square root",
|
128 |
+
"\\sqrt[n]{...}": "nth root",
|
129 |
+
"\\sum_{lower}^{upper}": "Summation",
|
130 |
+
"\\prod_{lower}^{upper}": "Product",
|
131 |
+
"\\int_{lower}^{upper}": "Integral",
|
132 |
+
"\\lim_{x \\to value}": "Limit",
|
133 |
+
"\\vec{...}": "Vector",
|
134 |
+
"\\overline{...}": "Overline",
|
135 |
+
"\\hat{...}": "Hat accent",
|
136 |
+
"\\partial": "Partial derivative"
|
137 |
+
},
|
138 |
+
"Lists": {
|
139 |
+
"\\begin{itemize}...\\end{itemize}": "Bulleted list",
|
140 |
+
"\\begin{enumerate}...\\end{enumerate}": "Numbered list",
|
141 |
+
"\\begin{description}...\\end{description}": "Description list",
|
142 |
+
"\\item": "List item",
|
143 |
+
"\\item[custom]": "Custom label item"
|
144 |
+
},
|
145 |
+
"Tables": {
|
146 |
+
"\\begin{table}...\\end{table}": "Table environment",
|
147 |
+
"\\begin{tabular}{cols}...\\end{tabular}": "Create a table",
|
148 |
+
"\\hline": "Horizontal line in table",
|
149 |
+
"\\cline{i-j}": "Partial horizontal line",
|
150 |
+
"cell1 & cell2 & cell3 \\\\": "Table row",
|
151 |
+
"\\multicolumn{n}{align}{content}": "Span multiple columns"
|
152 |
+
},
|
153 |
+
"Figures": {
|
154 |
+
"\\begin{figure}...\\end{figure}": "Figure environment",
|
155 |
+
"\\includegraphics[width=0.8\\textwidth]{filename}": "Include an image",
|
156 |
+
"\\caption{...}": "Add a caption to a figure or table",
|
157 |
+
"\\label{...}": "Add a label for cross-referencing",
|
158 |
+
"\\ref{...}": "Reference a labeled item"
|
159 |
+
},
|
160 |
+
"Citations": {
|
161 |
+
"\\cite{key}": "Citation",
|
162 |
+
"\\bibliography{file}": "Bibliography source",
|
163 |
+
"\\bibliographystyle{style}": "Bibliography style"
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
# Default LaTeX template
|
168 |
+
default_template = r"""\documentclass{article}
|
169 |
+
\usepackage[utf8]{inputenc}
|
170 |
+
\usepackage{amsmath}
|
171 |
+
\usepackage{amssymb}
|
172 |
+
\usepackage{graphicx}
|
173 |
+
\usepackage{hyperref}
|
174 |
+
|
175 |
+
\title{LaTeX Document}
|
176 |
+
\author{Your Name}
|
177 |
+
\date{\today}
|
178 |
+
|
179 |
+
\begin{document}
|
180 |
+
|
181 |
+
\maketitle
|
182 |
+
|
183 |
+
\section{Introduction}
|
184 |
+
Your introduction here. Insert some text to demonstrate LaTeX.
|
185 |
+
|
186 |
+
\section{Mathematical Expressions}
|
187 |
+
\subsection{Equations}
|
188 |
+
The famous Einstein's equation:
|
189 |
+
\begin{equation}
|
190 |
+
E = mc^2
|
191 |
+
\end{equation}
|
192 |
+
|
193 |
+
The quadratic formula:
|
194 |
+
\begin{equation}
|
195 |
+
x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
|
196 |
+
\end{equation}
|
197 |
+
|
198 |
+
\subsection{Calculus}
|
199 |
+
An integral example:
|
200 |
+
\begin{equation}
|
201 |
+
\int_{0}^{\pi} \sin(x) \, dx = 2
|
202 |
+
\end{equation}
|
203 |
+
|
204 |
+
\section{Lists and Items}
|
205 |
+
\subsection{Bullet Points}
|
206 |
+
\begin{itemize}
|
207 |
+
\item First item
|
208 |
+
\item Second item
|
209 |
+
\item Third item
|
210 |
+
\end{itemize}
|
211 |
+
|
212 |
+
\subsection{Numbered List}
|
213 |
+
\begin{enumerate}
|
214 |
+
\item First step
|
215 |
+
\item Second step
|
216 |
+
\item Third step
|
217 |
+
\end{enumerate}
|
218 |
+
|
219 |
+
\section{Tables}
|
220 |
+
\begin{table}[h]
|
221 |
+
\centering
|
222 |
+
\begin{tabular}{|c|c|c|}
|
223 |
+
\hline
|
224 |
+
Cell 1 & Cell 2 & Cell 3 \\
|
225 |
+
\hline
|
226 |
+
Data 1 & Data 2 & Data 3 \\
|
227 |
+
\hline
|
228 |
+
\end{tabular}
|
229 |
+
\caption{A simple table}
|
230 |
+
\label{tab:simple}
|
231 |
+
\end{table}
|
232 |
+
|
233 |
+
\section{Conclusion}
|
234 |
+
Your conclusion here.
|
235 |
+
|
236 |
+
\end{document}
|
237 |
+
"""
|
238 |
+
|
239 |
+
# Add custom CSS
|
240 |
+
st.markdown("""
|
241 |
+
<style>
|
242 |
+
.editor-container {
|
243 |
+
border: 1px solid #ccc;
|
244 |
+
border-radius: 5px;
|
245 |
+
padding: 10px;
|
246 |
+
background-color: #f8f9fa;
|
247 |
+
}
|
248 |
+
.download-button {
|
249 |
+
display: inline-block;
|
250 |
+
padding: 0.5em 1em;
|
251 |
+
background-color: #4CAF50;
|
252 |
+
color: white !important;
|
253 |
+
text-align: center;
|
254 |
+
text-decoration: none;
|
255 |
+
font-size: 16px;
|
256 |
+
border-radius: 4px;
|
257 |
+
transition: background-color 0.3s;
|
258 |
+
margin-top: 10px;
|
259 |
+
}
|
260 |
+
.download-button:hover {
|
261 |
+
background-color: #45a049;
|
262 |
+
}
|
263 |
+
.stTextArea textarea {
|
264 |
+
font-family: 'Courier New', Courier, monospace !important;
|
265 |
+
font-size: 14px !important;
|
266 |
+
line-height: 1.5 !important;
|
267 |
+
}
|
268 |
+
.latex-command {
|
269 |
+
background-color: #f1f1f1;
|
270 |
+
padding: 2px 4px;
|
271 |
+
border-radius: 3px;
|
272 |
+
font-family: monospace;
|
273 |
+
cursor: pointer;
|
274 |
+
}
|
275 |
+
.reference-tabs .stTabs {
|
276 |
+
background-color: #f5f5f5;
|
277 |
+
border-radius: 5px;
|
278 |
+
padding: 10px;
|
279 |
+
}
|
280 |
+
.stMarkdown h4 {
|
281 |
+
margin-top: 0.5rem !important;
|
282 |
+
margin-bottom: 0.5rem !important;
|
283 |
+
}
|
284 |
+
.command-category {
|
285 |
+
margin-bottom: 15px !important;
|
286 |
+
}
|
287 |
+
</style>
|
288 |
+
""", unsafe_allow_html=True)
|
289 |
+
|
290 |
+
# JavaScript for copying commands to editor
|
291 |
+
st.markdown("""
|
292 |
+
<script>
|
293 |
+
function copyToEditor(text) {
|
294 |
+
const textareas = document.getElementsByTagName('textarea');
|
295 |
+
if (textareas.length > 0) {
|
296 |
+
const editor = textareas[0];
|
297 |
+
const start = editor.selectionStart;
|
298 |
+
const end = editor.selectionEnd;
|
299 |
+
const value = editor.value;
|
300 |
+
editor.value = value.substring(0, start) + text + value.substring(end);
|
301 |
+
editor.selectionStart = editor.selectionEnd = start + text.length;
|
302 |
+
editor.focus();
|
303 |
+
}
|
304 |
+
}
|
305 |
+
</script>
|
306 |
+
""", unsafe_allow_html=True)
|
307 |
+
|
308 |
+
# Main application
|
309 |
+
def main():
|
310 |
+
st.title("LaTeX Editor & PDF Compiler")
|
311 |
+
|
312 |
+
# Create layout with sidebar
|
313 |
+
col1, col2 = st.columns([3, 2])
|
314 |
+
|
315 |
+
with col1:
|
316 |
+
st.subheader("LaTeX Editor")
|
317 |
+
|
318 |
+
# Initialize session state
|
319 |
+
if 'latex_code' not in st.session_state:
|
320 |
+
st.session_state.latex_code = default_template
|
321 |
+
|
322 |
+
# LaTeX editor
|
323 |
+
latex_code = st.text_area(
|
324 |
+
"Edit your LaTeX document:",
|
325 |
+
value=st.session_state.latex_code,
|
326 |
+
height=500,
|
327 |
+
key="latex_editor"
|
328 |
+
)
|
329 |
+
st.session_state.latex_code = latex_code
|
330 |
+
|
331 |
+
# Control buttons
|
332 |
+
col1_1, col1_2, col1_3 = st.columns(3)
|
333 |
+
|
334 |
+
with col1_1:
|
335 |
+
if st.button("Compile PDF", use_container_width=True):
|
336 |
+
st.session_state.compile_clicked = True
|
337 |
+
|
338 |
+
with col1_2:
|
339 |
+
if st.button("Load Template", use_container_width=True):
|
340 |
+
st.session_state.latex_code = default_template
|
341 |
+
st.rerun()
|
342 |
+
|
343 |
+
with col1_3:
|
344 |
+
if st.button("Clear Editor", use_container_width=True):
|
345 |
+
st.session_state.latex_code = ""
|
346 |
+
st.rerun()
|
347 |
+
|
348 |
+
with col2:
|
349 |
+
st.subheader("PDF Preview")
|
350 |
+
|
351 |
+
# PDF preview
|
352 |
+
if 'compile_clicked' in st.session_state and st.session_state.compile_clicked:
|
353 |
+
with st.spinner("Compiling LaTeX to PDF..."):
|
354 |
+
pdf_data, stdout, stderr = latex_to_pdf(latex_code)
|
355 |
+
|
356 |
+
if pdf_data:
|
357 |
+
st.session_state.pdf_data = pdf_data
|
358 |
+
display_pdf(pdf_data)
|
359 |
+
|
360 |
+
# Download button
|
361 |
+
st.markdown(get_download_link(pdf_data), unsafe_allow_html=True)
|
362 |
+
st.session_state.compile_clicked = False
|
363 |
+
else:
|
364 |
+
st.error("Compilation Error")
|
365 |
+
with st.expander("Error Details"):
|
366 |
+
st.text(stdout)
|
367 |
+
st.text(stderr)
|
368 |
+
st.session_state.compile_clicked = False
|
369 |
+
|
370 |
+
# Display previous PDF if available
|
371 |
+
elif 'pdf_data' in st.session_state and st.session_state.pdf_data:
|
372 |
+
display_pdf(st.session_state.pdf_data)
|
373 |
+
st.markdown(get_download_link(st.session_state.pdf_data), unsafe_allow_html=True)
|
374 |
+
else:
|
375 |
+
st.info("Compile your LaTeX document to see the PDF preview")
|
376 |
+
|
377 |
+
# LaTeX Reference Sidebar
|
378 |
+
st.sidebar.title("LaTeX Reference")
|
379 |
+
|
380 |
+
# Search functionality
|
381 |
+
search_query = st.sidebar.text_input("Search commands or packages", "")
|
382 |
+
|
383 |
+
if search_query:
|
384 |
+
st.sidebar.subheader("Search Results")
|
385 |
+
found = False
|
386 |
+
|
387 |
+
# Search commands
|
388 |
+
for category, commands in latex_commands.items():
|
389 |
+
filtered_commands = {cmd: desc for cmd, desc in commands.items()
|
390 |
+
if search_query.lower() in cmd.lower() or search_query.lower() in desc.lower()}
|
391 |
+
|
392 |
+
if filtered_commands:
|
393 |
+
found = True
|
394 |
+
with st.sidebar.expander(f"{category} ({len(filtered_commands)} results)"):
|
395 |
+
for cmd, desc in filtered_commands.items():
|
396 |
+
st.markdown(f"<div class='latex-command' onclick=\"copyToEditor('{cmd}')\">{cmd}</div> - {desc}", unsafe_allow_html=True)
|
397 |
+
|
398 |
+
# Search packages
|
399 |
+
for category, packages in latex_packages.items():
|
400 |
+
filtered_packages = {pkg: desc for pkg, desc in packages.items()
|
401 |
+
if search_query.lower() in pkg.lower() or search_query.lower() in desc.lower()}
|
402 |
+
|
403 |
+
if filtered_packages:
|
404 |
+
found = True
|
405 |
+
with st.sidebar.expander(f"Packages: {category} ({len(filtered_packages)} results)"):
|
406 |
+
for pkg, desc in filtered_packages.items():
|
407 |
+
st.markdown(f"<div class='latex-command' onclick=\"copyToEditor('{pkg}')\">{pkg}</div> - {desc}", unsafe_allow_html=True)
|
408 |
+
|
409 |
+
if not found:
|
410 |
+
st.sidebar.info("No matching commands or packages found")
|
411 |
+
|
412 |
+
else:
|
413 |
+
# Display full reference when not searching
|
414 |
+
tabs = st.sidebar.tabs(["Commands", "Packages"])
|
415 |
+
|
416 |
+
with tabs[0]:
|
417 |
+
for category, commands in latex_commands.items():
|
418 |
+
with st.expander(category):
|
419 |
+
for cmd, desc in commands.items():
|
420 |
+
st.markdown(f"<div class='latex-command' onclick=\"copyToEditor('{cmd}')\">{cmd}</div> - {desc}", unsafe_allow_html=True)
|
421 |
+
|
422 |
+
with tabs[1]:
|
423 |
+
for category, packages in latex_packages.items():
|
424 |
+
with st.expander(category):
|
425 |
+
for pkg, desc in packages.items():
|
426 |
+
st.markdown(f"<div class='latex-command' onclick=\"copyToEditor('{pkg}')\">{pkg}</div> - {desc}", unsafe_allow_html=True)
|
427 |
+
|
428 |
+
if __name__ == "__main__":
|
429 |
+
main()
|