Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -10,7 +10,6 @@ from PIL import Image
|
|
10 |
import fitz # PyMuPDF
|
11 |
import time
|
12 |
import re
|
13 |
-
import json
|
14 |
|
15 |
# Set page configuration
|
16 |
st.set_page_config(
|
@@ -25,7 +24,7 @@ def is_pdflatex_installed():
|
|
25 |
return shutil.which("pdflatex") is not None
|
26 |
|
27 |
# Function to convert LaTeX to PDF
|
28 |
-
def latex_to_pdf(latex_code
|
29 |
# Check if pdflatex is installed
|
30 |
if not is_pdflatex_installed():
|
31 |
st.error("pdflatex not found. Debug info:")
|
@@ -35,12 +34,9 @@ def latex_to_pdf(latex_code, output_dir=None):
|
|
35 |
return None, "", "Error: pdflatex is not installed or not in PATH."
|
36 |
|
37 |
with tempfile.TemporaryDirectory() as temp_dir:
|
38 |
-
if output_dir is None:
|
39 |
-
output_dir = temp_dir
|
40 |
-
|
41 |
temp_path = Path(temp_dir)
|
42 |
tex_file = temp_path / "document.tex"
|
43 |
-
pdf_file =
|
44 |
|
45 |
# Write LaTeX code to file
|
46 |
with open(tex_file, "w") as f:
|
@@ -49,7 +45,7 @@ def latex_to_pdf(latex_code, output_dir=None):
|
|
49 |
try:
|
50 |
# Run pdflatex to compile the LaTeX file
|
51 |
process = subprocess.run(
|
52 |
-
["pdflatex", "-interaction=nonstopmode", "-output-directory",
|
53 |
capture_output=True,
|
54 |
text=True
|
55 |
)
|
@@ -64,6 +60,11 @@ def latex_to_pdf(latex_code, output_dir=None):
|
|
64 |
except Exception as e:
|
65 |
return None, "", str(e)
|
66 |
|
|
|
|
|
|
|
|
|
|
|
67 |
# Convert PDF to image for preview
|
68 |
def render_pdf_preview(pdf_data):
|
69 |
if not pdf_data:
|
@@ -78,7 +79,7 @@ def render_pdf_preview(pdf_data):
|
|
78 |
|
79 |
# Render pages as images
|
80 |
images = []
|
81 |
-
for page_num in range(min(
|
82 |
page = pdf_document.load_page(page_num)
|
83 |
pix = page.get_pixmap(matrix=fitz.Matrix(2, 2)) # Zoom factor 2 for better resolution
|
84 |
img_data = pix.tobytes("png")
|
@@ -91,11 +92,6 @@ def render_pdf_preview(pdf_data):
|
|
91 |
st.error(f"Error rendering PDF preview: {str(e)}")
|
92 |
return None
|
93 |
|
94 |
-
# Function to create download link for PDF
|
95 |
-
def get_download_link(pdf_data, filename="document.pdf"):
|
96 |
-
b64_pdf = base64.b64encode(pdf_data).decode()
|
97 |
-
return f'<a href="data:application/pdf;base64,{b64_pdf}" download="{filename}" class="download-button">Download PDF</a>'
|
98 |
-
|
99 |
# Function to parse LaTeX errors
|
100 |
def parse_latex_errors(output):
|
101 |
errors = []
|
@@ -113,10 +109,20 @@ def parse_latex_errors(output):
|
|
113 |
|
114 |
return errors, warnings
|
115 |
|
116 |
-
# Function to extract document structure
|
117 |
def extract_document_structure(latex_code):
|
118 |
structure = []
|
119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
120 |
# Find sections, subsections, etc.
|
121 |
section_pattern = r'\\(section|subsection|subsubsection|chapter|part)\{([^}]+)\}'
|
122 |
matches = re.finditer(section_pattern, latex_code)
|
@@ -238,57 +244,6 @@ Your conclusion here.
|
|
238 |
\end{document}
|
239 |
"""
|
240 |
|
241 |
-
# Ace Editor component for syntax highlighting
|
242 |
-
def create_ace_editor():
|
243 |
-
ace_editor_html = """
|
244 |
-
<div id="editor" style="height: 600px; width: 100%; border-radius: 4px;"></div>
|
245 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.24.1/ace.js"></script>
|
246 |
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.24.1/ext-language_tools.js"></script>
|
247 |
-
<script>
|
248 |
-
// Create the editor
|
249 |
-
var editor = ace.edit("editor");
|
250 |
-
editor.setTheme("ace/theme/tomorrow_night_eighties");
|
251 |
-
editor.session.setMode("ace/mode/latex");
|
252 |
-
editor.setValue(JSON.parse('{latex_content}'));
|
253 |
-
editor.clearSelection();
|
254 |
-
|
255 |
-
// Enable advanced features
|
256 |
-
editor.setOptions({
|
257 |
-
enableBasicAutocompletion: true,
|
258 |
-
enableSnippets: true,
|
259 |
-
enableLiveAutocompletion: true,
|
260 |
-
showPrintMargin: false,
|
261 |
-
fontSize: 14,
|
262 |
-
fontFamily: "'Fira Code', 'Courier New', monospace",
|
263 |
-
scrollPastEnd: 0.5
|
264 |
-
});
|
265 |
-
|
266 |
-
// Function to update Streamlit with the content
|
267 |
-
function updateStreamlit() {
|
268 |
-
const content = editor.getValue();
|
269 |
-
if (window.Streamlit) {
|
270 |
-
window.Streamlit.setComponentValue(content);
|
271 |
-
}
|
272 |
-
}
|
273 |
-
|
274 |
-
// Add change event listener
|
275 |
-
editor.session.on('change', function() {
|
276 |
-
updateStreamlit();
|
277 |
-
});
|
278 |
-
|
279 |
-
// Initialize Streamlit component communication
|
280 |
-
function onStreamlitLoad() {
|
281 |
-
updateStreamlit();
|
282 |
-
}
|
283 |
-
|
284 |
-
if (window.Streamlit) {
|
285 |
-
window.Streamlit.setComponentReady();
|
286 |
-
window.Streamlit.onCustomComponentReady(onStreamlitLoad);
|
287 |
-
}
|
288 |
-
</script>
|
289 |
-
"""
|
290 |
-
return ace_editor_html
|
291 |
-
|
292 |
# Enhanced VSCode-like advanced styling
|
293 |
st.markdown("""
|
294 |
<style>
|
@@ -312,6 +267,18 @@ st.markdown("""
|
|
312 |
background-color: #1177bb;
|
313 |
}
|
314 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
315 |
/* VS Code-like editor container */
|
316 |
.editor-container {
|
317 |
background-color: #1e1e1e;
|
@@ -363,27 +330,33 @@ st.markdown("""
|
|
363 |
font-size: 12px;
|
364 |
}
|
365 |
|
366 |
-
/*
|
367 |
-
.
|
368 |
-
|
369 |
-
|
370 |
display: flex;
|
371 |
-
|
372 |
align-items: center;
|
373 |
-
padding-top: 10px;
|
374 |
}
|
375 |
|
376 |
-
.
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
cursor: pointer;
|
382 |
-
|
|
|
|
|
|
|
|
|
383 |
}
|
384 |
|
385 |
-
.
|
386 |
-
|
|
|
|
|
|
|
387 |
}
|
388 |
|
389 |
/* Terminal/console styling */
|
@@ -472,35 +445,6 @@ st.markdown("""
|
|
472 |
gap: 5px;
|
473 |
}
|
474 |
|
475 |
-
/* Toolbar */
|
476 |
-
.toolbar {
|
477 |
-
background-color: #2d2d2d;
|
478 |
-
padding: 5px;
|
479 |
-
display: flex;
|
480 |
-
gap: 5px;
|
481 |
-
align-items: center;
|
482 |
-
}
|
483 |
-
|
484 |
-
.toolbar-button {
|
485 |
-
background-color: transparent;
|
486 |
-
border: none;
|
487 |
-
color: #cccccc;
|
488 |
-
padding: 5px;
|
489 |
-
cursor: pointer;
|
490 |
-
border-radius: 2px;
|
491 |
-
}
|
492 |
-
|
493 |
-
.toolbar-button:hover {
|
494 |
-
background-color: #3c3c3c;
|
495 |
-
}
|
496 |
-
|
497 |
-
.toolbar-separator {
|
498 |
-
width: 1px;
|
499 |
-
height: 20px;
|
500 |
-
background-color: #555;
|
501 |
-
margin: 0 5px;
|
502 |
-
}
|
503 |
-
|
504 |
/* Messages */
|
505 |
.stInfo {
|
506 |
background-color: #063b49;
|
@@ -545,39 +489,7 @@ st.markdown("""
|
|
545 |
color: white;
|
546 |
}
|
547 |
|
548 |
-
/*
|
549 |
-
.file-explorer {
|
550 |
-
background-color: #252526;
|
551 |
-
border: 1px solid #2d2d2d;
|
552 |
-
border-radius: 4px;
|
553 |
-
padding: 0;
|
554 |
-
margin-top: 10px;
|
555 |
-
}
|
556 |
-
|
557 |
-
.file-header {
|
558 |
-
background-color: #2d2d2d;
|
559 |
-
padding: 5px 10px;
|
560 |
-
font-weight: bold;
|
561 |
-
font-size: 13px;
|
562 |
-
}
|
563 |
-
|
564 |
-
.file-item {
|
565 |
-
padding: 5px 10px;
|
566 |
-
display: flex;
|
567 |
-
align-items: center;
|
568 |
-
cursor: pointer;
|
569 |
-
}
|
570 |
-
|
571 |
-
.file-item:hover {
|
572 |
-
background-color: #2a2d2e;
|
573 |
-
}
|
574 |
-
|
575 |
-
.file-icon {
|
576 |
-
margin-right: 5px;
|
577 |
-
opacity: 0.7;
|
578 |
-
}
|
579 |
-
|
580 |
-
/* Enhanced styles for problems panel */
|
581 |
.problems-panel {
|
582 |
background-color: #252526;
|
583 |
border: 1px solid #2d2d2d;
|
@@ -644,81 +556,58 @@ st.markdown("""
|
|
644 |
</style>
|
645 |
""", unsafe_allow_html=True)
|
646 |
|
647 |
-
#
|
648 |
-
def
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
component = st.components.v1.html(editor_html, height=height, scrolling=False)
|
658 |
-
|
659 |
-
# Return the latest value
|
660 |
-
return component if component is not None else content
|
661 |
|
662 |
# Build a VS Code-like toolbar
|
663 |
def render_toolbar():
|
664 |
toolbar_html = """
|
665 |
<div class="toolbar">
|
666 |
-
<button class="toolbar-button" title="Bold"
|
667 |
<strong>B</strong>
|
668 |
</button>
|
669 |
-
<button class="toolbar-button" title="Italic"
|
670 |
<em>I</em>
|
671 |
</button>
|
672 |
-
<button class="toolbar-button" title="Math"
|
673 |
∑
|
674 |
</button>
|
675 |
<div class="toolbar-separator"></div>
|
676 |
-
<button class="toolbar-button" title="Section"
|
677 |
§
|
678 |
</button>
|
679 |
-
<button class="toolbar-button" title="Subsection"
|
680 |
§§
|
681 |
</button>
|
682 |
<div class="toolbar-separator"></div>
|
683 |
-
<button class="toolbar-button" title="Itemize"
|
684 |
•
|
685 |
</button>
|
686 |
-
<button class="toolbar-button" title="Enumerate"
|
687 |
1.
|
688 |
</button>
|
689 |
<div class="toolbar-separator"></div>
|
690 |
-
<button class="toolbar-button" title="Equation"
|
691 |
=
|
692 |
</button>
|
693 |
-
<button class="toolbar-button" title="Figure"
|
694 |
🖼
|
695 |
</button>
|
696 |
-
<button class="toolbar-button" title="Table"
|
697 |
⊞
|
698 |
</button>
|
699 |
</div>
|
700 |
-
|
701 |
-
<script>
|
702 |
-
function insertTextAtCursor(text) {
|
703 |
-
var editor = ace.edit("editor");
|
704 |
-
editor.insert(text);
|
705 |
-
editor.focus();
|
706 |
-
}
|
707 |
-
</script>
|
708 |
"""
|
709 |
st.markdown(toolbar_html, unsafe_allow_html=True)
|
710 |
|
711 |
-
# VS Code-style editor tabs
|
712 |
-
def render_editor_tabs(active_tab="document.tex"):
|
713 |
-
tab_html = f"""
|
714 |
-
<div class="tab-bar">
|
715 |
-
<div class="tab active">
|
716 |
-
<span class="tab-icon">📄</span> {active_tab}
|
717 |
-
</div>
|
718 |
-
</div>
|
719 |
-
"""
|
720 |
-
st.markdown(tab_html, unsafe_allow_html=True)
|
721 |
-
|
722 |
# VS Code-style status bar
|
723 |
def render_status_bar():
|
724 |
status_html = """
|
@@ -752,7 +641,7 @@ def render_document_outline(structure):
|
|
752 |
indent = " " * (level * 4)
|
753 |
|
754 |
st.markdown(
|
755 |
-
f'<div class="outline-item"
|
756 |
f'<span>{type_icon}</span>'
|
757 |
f'<span class="outline-item-text">{indent}{title}</span>'
|
758 |
f'</div>',
|
@@ -795,6 +684,13 @@ def render_problems(errors, warnings):
|
|
795 |
|
796 |
# Render document information panel
|
797 |
def render_document_info(latex_code):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
798 |
# Calculate basic document stats
|
799 |
word_count = len(re.findall(r'\b\w+\b', latex_code))
|
800 |
char_count = len(latex_code)
|
@@ -872,10 +768,15 @@ def main():
|
|
872 |
# Toolbar
|
873 |
render_toolbar()
|
874 |
|
875 |
-
#
|
876 |
-
latex_code =
|
877 |
-
|
878 |
-
st.session_state.latex_code
|
|
|
|
|
|
|
|
|
|
|
879 |
|
880 |
# Status bar
|
881 |
render_status_bar()
|
@@ -1014,8 +915,11 @@ def main():
|
|
1014 |
st.info("Click 'Compile' to generate PDF output")
|
1015 |
|
1016 |
with output_tabs[1]:
|
1017 |
-
# Document structure/outline view
|
1018 |
-
|
|
|
|
|
|
|
1019 |
render_document_outline(structure)
|
1020 |
|
1021 |
with output_tabs[2]:
|
|
|
10 |
import fitz # PyMuPDF
|
11 |
import time
|
12 |
import re
|
|
|
13 |
|
14 |
# Set page configuration
|
15 |
st.set_page_config(
|
|
|
24 |
return shutil.which("pdflatex") is not None
|
25 |
|
26 |
# Function to convert LaTeX to PDF
|
27 |
+
def latex_to_pdf(latex_code):
|
28 |
# Check if pdflatex is installed
|
29 |
if not is_pdflatex_installed():
|
30 |
st.error("pdflatex not found. Debug info:")
|
|
|
34 |
return None, "", "Error: pdflatex is not installed or not in PATH."
|
35 |
|
36 |
with tempfile.TemporaryDirectory() as temp_dir:
|
|
|
|
|
|
|
37 |
temp_path = Path(temp_dir)
|
38 |
tex_file = temp_path / "document.tex"
|
39 |
+
pdf_file = temp_path / "document.pdf"
|
40 |
|
41 |
# Write LaTeX code to file
|
42 |
with open(tex_file, "w") as f:
|
|
|
45 |
try:
|
46 |
# Run pdflatex to compile the LaTeX file
|
47 |
process = subprocess.run(
|
48 |
+
["pdflatex", "-interaction=nonstopmode", "-output-directory", temp_dir, str(tex_file)],
|
49 |
capture_output=True,
|
50 |
text=True
|
51 |
)
|
|
|
60 |
except Exception as e:
|
61 |
return None, "", str(e)
|
62 |
|
63 |
+
# Function to create download link for PDF
|
64 |
+
def get_download_link(pdf_data, filename="document.pdf"):
|
65 |
+
b64_pdf = base64.b64encode(pdf_data).decode()
|
66 |
+
return f'<a href="data:application/pdf;base64,{b64_pdf}" download="{filename}" class="download-button">Download PDF</a>'
|
67 |
+
|
68 |
# Convert PDF to image for preview
|
69 |
def render_pdf_preview(pdf_data):
|
70 |
if not pdf_data:
|
|
|
79 |
|
80 |
# Render pages as images
|
81 |
images = []
|
82 |
+
for page_num in range(min(3, len(pdf_document))): # Preview first 3 pages max
|
83 |
page = pdf_document.load_page(page_num)
|
84 |
pix = page.get_pixmap(matrix=fitz.Matrix(2, 2)) # Zoom factor 2 for better resolution
|
85 |
img_data = pix.tobytes("png")
|
|
|
92 |
st.error(f"Error rendering PDF preview: {str(e)}")
|
93 |
return None
|
94 |
|
|
|
|
|
|
|
|
|
|
|
95 |
# Function to parse LaTeX errors
|
96 |
def parse_latex_errors(output):
|
97 |
errors = []
|
|
|
109 |
|
110 |
return errors, warnings
|
111 |
|
112 |
+
# Function to extract document structure - fixed to handle non-string input
|
113 |
def extract_document_structure(latex_code):
|
114 |
structure = []
|
115 |
|
116 |
+
# Ensure latex_code is a string
|
117 |
+
if latex_code is None:
|
118 |
+
return structure
|
119 |
+
|
120 |
+
if not isinstance(latex_code, str):
|
121 |
+
try:
|
122 |
+
latex_code = str(latex_code)
|
123 |
+
except:
|
124 |
+
return structure
|
125 |
+
|
126 |
# Find sections, subsections, etc.
|
127 |
section_pattern = r'\\(section|subsection|subsubsection|chapter|part)\{([^}]+)\}'
|
128 |
matches = re.finditer(section_pattern, latex_code)
|
|
|
244 |
\end{document}
|
245 |
"""
|
246 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
247 |
# Enhanced VSCode-like advanced styling
|
248 |
st.markdown("""
|
249 |
<style>
|
|
|
267 |
background-color: #1177bb;
|
268 |
}
|
269 |
|
270 |
+
/* VS Code-like editor */
|
271 |
+
.stTextArea textarea {
|
272 |
+
font-family: 'Consolas', 'Monaco', 'Courier New', monospace !important;
|
273 |
+
font-size: 14px !important;
|
274 |
+
line-height: 1.5 !important;
|
275 |
+
background-color: #1e1e1e !important;
|
276 |
+
color: #d4d4d4 !important;
|
277 |
+
padding: 10px !important;
|
278 |
+
border-radius: 4px !important;
|
279 |
+
border: 1px solid #252526 !important;
|
280 |
+
}
|
281 |
+
|
282 |
/* VS Code-like editor container */
|
283 |
.editor-container {
|
284 |
background-color: #1e1e1e;
|
|
|
330 |
font-size: 12px;
|
331 |
}
|
332 |
|
333 |
+
/* Toolbar */
|
334 |
+
.toolbar {
|
335 |
+
background-color: #2d2d2d;
|
336 |
+
padding: 5px;
|
337 |
display: flex;
|
338 |
+
gap: 5px;
|
339 |
align-items: center;
|
|
|
340 |
}
|
341 |
|
342 |
+
.toolbar-button {
|
343 |
+
background-color: transparent;
|
344 |
+
border: none;
|
345 |
+
color: #cccccc;
|
346 |
+
padding: 5px;
|
347 |
cursor: pointer;
|
348 |
+
border-radius: 2px;
|
349 |
+
}
|
350 |
+
|
351 |
+
.toolbar-button:hover {
|
352 |
+
background-color: #3c3c3c;
|
353 |
}
|
354 |
|
355 |
+
.toolbar-separator {
|
356 |
+
width: 1px;
|
357 |
+
height: 20px;
|
358 |
+
background-color: #555;
|
359 |
+
margin: 0 5px;
|
360 |
}
|
361 |
|
362 |
/* Terminal/console styling */
|
|
|
445 |
gap: 5px;
|
446 |
}
|
447 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
448 |
/* Messages */
|
449 |
.stInfo {
|
450 |
background-color: #063b49;
|
|
|
489 |
color: white;
|
490 |
}
|
491 |
|
492 |
+
/* Problems panel */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
493 |
.problems-panel {
|
494 |
background-color: #252526;
|
495 |
border: 1px solid #2d2d2d;
|
|
|
556 |
</style>
|
557 |
""", unsafe_allow_html=True)
|
558 |
|
559 |
+
# VS Code-style editor tabs
|
560 |
+
def render_editor_tabs(active_tab="document.tex"):
|
561 |
+
tab_html = f"""
|
562 |
+
<div class="tab-bar">
|
563 |
+
<div class="tab active">
|
564 |
+
<span class="tab-icon">📄</span> {active_tab}
|
565 |
+
</div>
|
566 |
+
</div>
|
567 |
+
"""
|
568 |
+
st.markdown(tab_html, unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
569 |
|
570 |
# Build a VS Code-like toolbar
|
571 |
def render_toolbar():
|
572 |
toolbar_html = """
|
573 |
<div class="toolbar">
|
574 |
+
<button class="toolbar-button" title="Bold">
|
575 |
<strong>B</strong>
|
576 |
</button>
|
577 |
+
<button class="toolbar-button" title="Italic">
|
578 |
<em>I</em>
|
579 |
</button>
|
580 |
+
<button class="toolbar-button" title="Math">
|
581 |
∑
|
582 |
</button>
|
583 |
<div class="toolbar-separator"></div>
|
584 |
+
<button class="toolbar-button" title="Section">
|
585 |
§
|
586 |
</button>
|
587 |
+
<button class="toolbar-button" title="Subsection">
|
588 |
§§
|
589 |
</button>
|
590 |
<div class="toolbar-separator"></div>
|
591 |
+
<button class="toolbar-button" title="Itemize">
|
592 |
•
|
593 |
</button>
|
594 |
+
<button class="toolbar-button" title="Enumerate">
|
595 |
1.
|
596 |
</button>
|
597 |
<div class="toolbar-separator"></div>
|
598 |
+
<button class="toolbar-button" title="Equation">
|
599 |
=
|
600 |
</button>
|
601 |
+
<button class="toolbar-button" title="Figure">
|
602 |
🖼
|
603 |
</button>
|
604 |
+
<button class="toolbar-button" title="Table">
|
605 |
⊞
|
606 |
</button>
|
607 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
608 |
"""
|
609 |
st.markdown(toolbar_html, unsafe_allow_html=True)
|
610 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
611 |
# VS Code-style status bar
|
612 |
def render_status_bar():
|
613 |
status_html = """
|
|
|
641 |
indent = " " * (level * 4)
|
642 |
|
643 |
st.markdown(
|
644 |
+
f'<div class="outline-item">'
|
645 |
f'<span>{type_icon}</span>'
|
646 |
f'<span class="outline-item-text">{indent}{title}</span>'
|
647 |
f'</div>',
|
|
|
684 |
|
685 |
# Render document information panel
|
686 |
def render_document_info(latex_code):
|
687 |
+
# Ensure latex_code is a string
|
688 |
+
if not isinstance(latex_code, str):
|
689 |
+
try:
|
690 |
+
latex_code = str(latex_code)
|
691 |
+
except:
|
692 |
+
latex_code = ""
|
693 |
+
|
694 |
# Calculate basic document stats
|
695 |
word_count = len(re.findall(r'\b\w+\b', latex_code))
|
696 |
char_count = len(latex_code)
|
|
|
768 |
# Toolbar
|
769 |
render_toolbar()
|
770 |
|
771 |
+
# Simple text area with VS Code styling
|
772 |
+
latex_code = st.text_area(
|
773 |
+
"",
|
774 |
+
value=st.session_state.latex_code,
|
775 |
+
height=500,
|
776 |
+
key="latex_editor",
|
777 |
+
label_visibility="collapsed"
|
778 |
+
)
|
779 |
+
st.session_state.latex_code = latex_code
|
780 |
|
781 |
# Status bar
|
782 |
render_status_bar()
|
|
|
915 |
st.info("Click 'Compile' to generate PDF output")
|
916 |
|
917 |
with output_tabs[1]:
|
918 |
+
# Document structure/outline view (with type check)
|
919 |
+
if isinstance(st.session_state.latex_code, str):
|
920 |
+
structure = extract_document_structure(st.session_state.latex_code)
|
921 |
+
else:
|
922 |
+
structure = []
|
923 |
render_document_outline(structure)
|
924 |
|
925 |
with output_tabs[2]:
|