Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -108,45 +108,60 @@ def parse_endpoint():
|
|
| 108 |
def build_full_html(markdown_text, styles, include_fontawesome):
|
| 109 |
wrapper_id = "#output-wrapper"
|
| 110 |
font_family = styles.get('font_family', "'Arial', sans-serif")
|
| 111 |
-
google_font_name = font_family.split(',')[0].strip("'\"")
|
| 112 |
-
google_font_link = ""
|
| 113 |
-
if " " in google_font_name and google_font_name not in ["Times New Roman", "Courier New"]:
|
| 114 |
-
google_font_link = f'<link href="https://fonts.googleapis.com/css2?family={google_font_name.replace(" ", "+")}:wght@400;700&display=swap" rel="stylesheet">'
|
| 115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
highlight_theme = styles.get('highlight_theme', 'default')
|
| 117 |
pygments_css = ""
|
| 118 |
if highlight_theme != 'none':
|
| 119 |
formatter = HtmlFormatter(style=highlight_theme, cssclass="codehilite")
|
| 120 |
pygments_css = formatter.get_style_defs(f' {wrapper_id}')
|
| 121 |
-
|
| 122 |
scoped_css = f"""
|
|
|
|
| 123 |
{wrapper_id} {{
|
| 124 |
-
font-family: {font_family};
|
| 125 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
}}
|
| 127 |
-
{
|
| 128 |
-
|
| 129 |
-
{
|
| 130 |
-
{wrapper_id} img {{ max-width: 100%; height: auto; }}
|
| 131 |
-
{wrapper_id} pre {{ padding: {styles.get('code_padding', '15')}px; border-radius: 5px; white-space: pre-wrap; word-wrap: break-word; }}
|
| 132 |
-
{wrapper_id} h1, {wrapper_id} h2, {wrapper_id} h3 {{ border-bottom: 1px solid #eee; padding-bottom: 5px; margin-top: 1.5em; }}
|
| 133 |
-
{wrapper_id} :not(pre) > code {{ font-family: 'Courier New', monospace; background-color: #eef; padding: .2em .4em; border-radius: 3px; }}
|
| 134 |
-
{pygments_css} {styles.get('custom_css', '')}
|
| 135 |
"""
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
-
|
| 138 |
-
html_content = markdown.markdown(markdown_text, extensions=md_extensions, extension_configs={'codehilite': {'css_class': 'codehilite'}})
|
| 139 |
-
final_html_body = f'<div id="output-wrapper">{html_content}</div>'
|
| 140 |
-
|
| 141 |
-
fontawesome_link = '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">' if include_fontawesome else ""
|
| 142 |
-
|
| 143 |
-
full_html = f"""<!DOCTYPE html>
|
| 144 |
-
<html><head><meta charset="UTF-8">{google_font_link}{fontawesome_link}<style>
|
| 145 |
-
#ouput-wrapper {{ background-color: {styles.get('background_color', '#fff')}; padding: 25px; display: inline-block;}}
|
| 146 |
-
{scoped_css}
|
| 147 |
-
</style></head><body>{final_html_body}</body></html>"""
|
| 148 |
|
| 149 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
@app.route('/convert', methods=['POST'])
|
| 152 |
def convert_endpoint():
|
|
@@ -157,7 +172,7 @@ def convert_endpoint():
|
|
| 157 |
styles=data.get('styles', {}),
|
| 158 |
include_fontawesome=data.get('include_fontawesome', False)
|
| 159 |
)
|
| 160 |
-
options = {"quiet": "", 'encoding': "UTF-8"}
|
| 161 |
|
| 162 |
if data.get('download', False):
|
| 163 |
download_type = data.get('download_type', 'png')
|
|
@@ -214,8 +229,62 @@ def index():
|
|
| 214 |
<form id="main-form" onsubmit="return false;">
|
| 215 |
<fieldset><legend>1. Load Content</legend><div id="info-box" class="info"></div><textarea id="markdown-text-input" name="markdown_text" rows="8"></textarea><div style="margin-top: 10px; display: flex; align-items: center; gap: 10px;"><label for="markdown-file-input">Or upload a file:</label><input type="file" id="markdown-file-input" name="markdown_file" accept=".md,.txt,text/markdown"></div><div style="margin-top: 15px;"><button type="button" id="load-btn" class="action-btn">Load & Analyze</button></div></fieldset>
|
| 216 |
<fieldset id="components-fieldset" style="display:none;"><legend>2. Select Components</legend><div class="selection-controls"><button type="button" onclick="toggleAllComponents(true)">Select All</button><button type="button" onclick="toggleAllComponents(false)">Deselect All</button></div><div id="components-container" class="component-grid"></div></fieldset>
|
| 217 |
-
|
| 218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
</form>
|
| 220 |
<div id="error-box" class="error"></div>
|
| 221 |
<div id="preview-section" style="display:none;">
|
|
|
|
| 108 |
def build_full_html(markdown_text, styles, include_fontawesome):
|
| 109 |
wrapper_id = "#output-wrapper"
|
| 110 |
font_family = styles.get('font_family', "'Arial', sans-serif")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
+
# Extract clean font name for Google Fonts API
|
| 113 |
+
google_font_name = font_family.split(',')[0].strip("'\"")
|
| 114 |
+
google_font_link = f'<link href="https://fonts.googleapis.com/css2?family={google_font_name.replace(" ", "+")}:wght@400;700&display=swap" rel="stylesheet">'
|
| 115 |
+
|
| 116 |
highlight_theme = styles.get('highlight_theme', 'default')
|
| 117 |
pygments_css = ""
|
| 118 |
if highlight_theme != 'none':
|
| 119 |
formatter = HtmlFormatter(style=highlight_theme, cssclass="codehilite")
|
| 120 |
pygments_css = formatter.get_style_defs(f' {wrapper_id}')
|
| 121 |
+
|
| 122 |
scoped_css = f"""
|
| 123 |
+
body {{ background-color: {styles.get('background_color', '#ffffff')}; margin: 0; padding: 0; }}
|
| 124 |
{wrapper_id} {{
|
| 125 |
+
font-family: {font_family};
|
| 126 |
+
font-size: {styles.get('font_size', '16')}px;
|
| 127 |
+
line-height: {styles.get('line_height', '1.6')};
|
| 128 |
+
color: {styles.get('text_color', '#333')};
|
| 129 |
+
background-color: {styles.get('background_color', '#fff')};
|
| 130 |
+
padding: {styles.get('page_padding', '40')}px;
|
| 131 |
+
max-width: 100%;
|
| 132 |
+
}}
|
| 133 |
+
{wrapper_id} h1, {wrapper_id} h2, {wrapper_id} h3 {{
|
| 134 |
+
margin-top: 1.2em;
|
| 135 |
+
margin-bottom: 0.6em;
|
| 136 |
+
font-weight: 700;
|
| 137 |
+
}}
|
| 138 |
+
{wrapper_id} pre {{
|
| 139 |
+
padding: {styles.get('code_padding', '15')}px;
|
| 140 |
+
border-radius: 8px;
|
| 141 |
+
overflow-x: auto;
|
| 142 |
}}
|
| 143 |
+
{pygments_css}
|
| 144 |
+
/* User Custom CSS Injection */
|
| 145 |
+
{styles.get('custom_css', '')}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
"""
|
| 147 |
+
|
| 148 |
+
md_extensions = ['fenced_code', 'tables', 'codehilite', 'nl2br']
|
| 149 |
+
html_body = markdown.markdown(markdown_text, extensions=md_extensions)
|
| 150 |
|
| 151 |
+
fontawesome = '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">' if include_fontawesome else ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
|
| 153 |
+
return f"""<!DOCTYPE html>
|
| 154 |
+
<html>
|
| 155 |
+
<head>
|
| 156 |
+
<meta charset="UTF-8">
|
| 157 |
+
{google_font_link}
|
| 158 |
+
{fontawesome}
|
| 159 |
+
<style>{scoped_css}</style>
|
| 160 |
+
</head>
|
| 161 |
+
<body>
|
| 162 |
+
<div id="output-wrapper">{html_body}</div>
|
| 163 |
+
</body>
|
| 164 |
+
</html>"""
|
| 165 |
|
| 166 |
@app.route('/convert', methods=['POST'])
|
| 167 |
def convert_endpoint():
|
|
|
|
| 172 |
styles=data.get('styles', {}),
|
| 173 |
include_fontawesome=data.get('include_fontawesome', False)
|
| 174 |
)
|
| 175 |
+
options = {"quiet": "", 'encoding': "UTF-8", "width": 1200, "disable-smart-width":""}
|
| 176 |
|
| 177 |
if data.get('download', False):
|
| 178 |
download_type = data.get('download_type', 'png')
|
|
|
|
| 229 |
<form id="main-form" onsubmit="return false;">
|
| 230 |
<fieldset><legend>1. Load Content</legend><div id="info-box" class="info"></div><textarea id="markdown-text-input" name="markdown_text" rows="8"></textarea><div style="margin-top: 10px; display: flex; align-items: center; gap: 10px;"><label for="markdown-file-input">Or upload a file:</label><input type="file" id="markdown-file-input" name="markdown_file" accept=".md,.txt,text/markdown"></div><div style="margin-top: 15px;"><button type="button" id="load-btn" class="action-btn">Load & Analyze</button></div></fieldset>
|
| 231 |
<fieldset id="components-fieldset" style="display:none;"><legend>2. Select Components</legend><div class="selection-controls"><button type="button" onclick="toggleAllComponents(true)">Select All</button><button type="button" onclick="toggleAllComponents(false)">Deselect All</button></div><div id="components-container" class="component-grid"></div></fieldset>
|
| 232 |
+
<fieldset>
|
| 233 |
+
<legend>3. Visual & Layout Controls</legend>
|
| 234 |
+
<div class="style-grid">
|
| 235 |
+
<div>
|
| 236 |
+
<label>Font Family</label>
|
| 237 |
+
<select id="font_family">
|
| 238 |
+
<option value="'Inter', sans-serif">Inter (Modern)</option>
|
| 239 |
+
<option value="'Playfair Display', serif">Playfair (Elegant)</option>
|
| 240 |
+
<option value="'Fira Code', monospace">Fira Code (Dev)</option>
|
| 241 |
+
<option value="'Roboto', sans-serif">Roboto (Clean)</option>
|
| 242 |
+
<option value="'Lora', serif">Lora (Classic)</option>
|
| 243 |
+
</select>
|
| 244 |
+
</div>
|
| 245 |
+
<div>
|
| 246 |
+
<label>Font Size (px)</label>
|
| 247 |
+
<input type="number" id="font_size" value="16">
|
| 248 |
+
</div>
|
| 249 |
+
<div>
|
| 250 |
+
<label>Line Height</label>
|
| 251 |
+
<input type="number" id="line_height" value="1.6" step="0.1">
|
| 252 |
+
</div>
|
| 253 |
+
|
| 254 |
+
<div>
|
| 255 |
+
<label>Text Color</label>
|
| 256 |
+
<input type="color" id="text_color" value="#333333">
|
| 257 |
+
</div>
|
| 258 |
+
<div>
|
| 259 |
+
<label>Background</label>
|
| 260 |
+
<input type="color" id="background_color" value="#ffffff">
|
| 261 |
+
</div>
|
| 262 |
+
<div>
|
| 263 |
+
<label>Highlight Theme</label>
|
| 264 |
+
<select id="highlight_theme">
|
| 265 |
+
<option value="monokai">Monokai</option>
|
| 266 |
+
<option value="github-light">GitHub Light</option>
|
| 267 |
+
<option value="dracula">Dracula</option>
|
| 268 |
+
</select>
|
| 269 |
+
</div>
|
| 270 |
+
|
| 271 |
+
<div>
|
| 272 |
+
<label>Page Padding (px)</label>
|
| 273 |
+
<input type="number" id="page_padding" value="40">
|
| 274 |
+
</div>
|
| 275 |
+
<div>
|
| 276 |
+
<label>Code Padding (px)</label>
|
| 277 |
+
<input type="number" id="code_padding" value="15">
|
| 278 |
+
</div>
|
| 279 |
+
</div>
|
| 280 |
+
|
| 281 |
+
<div style="margin-top:15px;">
|
| 282 |
+
<label><b>Custom CSS Overrides:</b></label>
|
| 283 |
+
<textarea id="custom_css" rows="4" placeholder="#output-wrapper h1 { color: red; }"></textarea>
|
| 284 |
+
</div>
|
| 285 |
+
</fieldset>
|
| 286 |
+
|
| 287 |
+
<div class="main-actions"><button type="button" id="generate-btn" class="generate-btn">Generate Preview</button></div>
|
| 288 |
</form>
|
| 289 |
<div id="error-box" class="error"></div>
|
| 290 |
<div id="preview-section" style="display:none;">
|