Markdown line support, better CSS, refactoring
This commit is contained in:
parent
912cb749c5
commit
f4d4b423cc
151
app.py
151
app.py
@ -40,7 +40,7 @@ HTML_FORM = '''
|
|||||||
}
|
}
|
||||||
.form-card {
|
.form-card {
|
||||||
background: #22282c;
|
background: #22282c;
|
||||||
padding: 2em 2.4em 1em 2em;
|
padding: 2em 2em 1em 2em;
|
||||||
border-radius: 1.5em;
|
border-radius: 1.5em;
|
||||||
box-shadow: 0 0 12px 0 #000a;
|
box-shadow: 0 0 12px 0 #000a;
|
||||||
min-width: 410px;
|
min-width: 410px;
|
||||||
@ -54,12 +54,14 @@ HTML_FORM = '''
|
|||||||
.markdown-ref {
|
.markdown-ref {
|
||||||
background: #22282c;
|
background: #22282c;
|
||||||
border-radius: 1.2em;
|
border-radius: 1.2em;
|
||||||
box-shadow: 0 0 8px #0008;
|
box-shadow: 0 0 12px 0 #000a;
|
||||||
padding: 1.3em 1.2em 1.1em 1.6em;
|
padding: 2em 2em 1.5em 2em;
|
||||||
color: #b6c8e0;
|
color: #b6c8e0;
|
||||||
font-size: 1.08em;
|
font-size: 1.08em;
|
||||||
max-width: 410px;
|
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 410px;
|
||||||
}
|
}
|
||||||
.markdown-ref h4 {
|
.markdown-ref h4 {
|
||||||
margin: 0 0 0.4em 0;
|
margin: 0 0 0.4em 0;
|
||||||
@ -102,10 +104,10 @@ HTML_FORM = '''
|
|||||||
.buttons {
|
.buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
align-items: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
button[type=submit] {
|
button[type=submit] {
|
||||||
background: linear-gradient(90deg, #8ee3c1, #35a7ff 85%);
|
background: linear-gradient(90deg, #8ee3c1, #35a7ff);
|
||||||
color: #222;
|
color: #222;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 1.12em;
|
font-size: 1.12em;
|
||||||
@ -122,6 +124,12 @@ HTML_FORM = '''
|
|||||||
filter: brightness(1.12);
|
filter: brightness(1.12);
|
||||||
box-shadow: 0 4px 18px #2229;
|
box-shadow: 0 4px 18px #2229;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button[type=submit][name=print] {
|
||||||
|
background: linear-gradient(90deg, #ffeb3b, #ff9100);
|
||||||
|
color:#181c1f;
|
||||||
|
}
|
||||||
|
|
||||||
.preview-card {
|
.preview-card {
|
||||||
background: #23282d;
|
background: #23282d;
|
||||||
padding: 2em 1.4em 1em 1.4em;
|
padding: 2em 1.4em 1em 1.4em;
|
||||||
@ -137,7 +145,6 @@ HTML_FORM = '''
|
|||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 0.6em;
|
|
||||||
box-shadow: 0 0 8px 1px #111a;
|
box-shadow: 0 0 8px 1px #111a;
|
||||||
}
|
}
|
||||||
.status-msg {
|
.status-msg {
|
||||||
@ -158,8 +165,92 @@ HTML_FORM = '''
|
|||||||
border-left: 4px solid #ff6384;
|
border-left: 4px solid #ff6384;
|
||||||
box-shadow: 0 0 8px #22000690;
|
box-shadow: 0 0 8px #22000690;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.centered-flex {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
height: auto;
|
||||||
|
gap: 1.6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-card,
|
||||||
|
.preview-card,
|
||||||
|
.markdown-ref {
|
||||||
|
min-width: auto;
|
||||||
|
max-width: 90vw;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0.8em 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-frame {
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px 15px;
|
||||||
|
margin-top: 1em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-frame::before,
|
||||||
|
.print-frame::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 101%;
|
||||||
|
height: 10px;
|
||||||
|
background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZlcnNpb249IjEuMSIgdmlld0JveD0iMCAwIDQuMjMzMyA0LjIzMzMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIHN0cm9rZS1saW5lY2FwPSJzcXVhcmUiIHN0cm9rZS1vcGFjaXR5PSIuOTc2NDciPgo8cmVjdCB4PSItNS41NTExZS0xNyIgd2lkdGg9IjQuMjMzMyIgaGVpZ2h0PSI0LjIzMzMiIGZpbGw9IiMyMjI4MmMiIHN0cm9rZS13aWR0aD0iLjE5MjI2Ii8+CjxwYXRoIHRyYW5zZm9ybT0ibWF0cml4KC4wMzYxMzUgMCAwIC4wNDE3MjUgMS4xNTY4IDEuMTI4OSkiIGQ9Im04NS4xNDEgNzQuNDAzLTExNy4xNS0xZS02IDU4LjU3Ny0xMDEuNDZ6IiBmaWxsPSIjZmZmIiBzdHJva2Utd2lkdGg9Ii4yNjQ1OCIvPgo8L2c+Cjwvc3ZnPgo=') repeat-x left;
|
||||||
|
background-size: 10px 384px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-frame::before {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-frame::after {
|
||||||
|
bottom: 0;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.print-frame img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="centered-flex">
|
<div class="centered-flex">
|
||||||
|
<div class="form-card">
|
||||||
|
<center>
|
||||||
|
<h2 style="margin-top:0.2em;">😺 CatNote 🖨️</h2>
|
||||||
|
</center>
|
||||||
|
<form method=post enctype=multipart/form-data>
|
||||||
|
<textarea name=md placeholder="Ingrese Markdown aquí...">{{ default_md }}</textarea><br>
|
||||||
|
<div class="buttons">
|
||||||
|
<button type=submit name="generate">📷 Generar</button>
|
||||||
|
<button type=submit name="print">🖨️ Imprimir</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{% if printed %}
|
||||||
|
<div class="status-msg">✅ Enviado a impresora</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if error %}
|
||||||
|
<div class="status-msg status-err">⚠️ {{ error }}</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="preview-card">
|
||||||
|
{% if img %}
|
||||||
|
<h3 style="margin-top:0.1em;margin-bottom:0.6em;">Vista previa</h3>
|
||||||
|
<div class="print-frame">
|
||||||
|
<img src="data:image/png;base64,{{ img }}">
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p style="opacity:.6;">Su vista previa aparecerá aquí</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="markdown-ref">
|
<div class="markdown-ref">
|
||||||
<h4>Referencia rápida de Markdown</h4>
|
<h4>Referencia rápida de Markdown</h4>
|
||||||
<ul>
|
<ul>
|
||||||
@ -174,35 +265,12 @@ HTML_FORM = '''
|
|||||||
<li><b>Salto de línea:</b> Deje una línea vacía</li>
|
<li><b>Salto de línea:</b> Deje una línea vacía</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-card">
|
|
||||||
<h2 style="margin-top:0.2em;">CatNotepad</h2>
|
|
||||||
<form method=post enctype=multipart/form-data>
|
|
||||||
<textarea name=md placeholder="Ingrese Markdown aquí...">{{ default_md }}</textarea><br>
|
|
||||||
<div class="buttons">
|
|
||||||
<button type=submit name="generate">📷 Generar</button>
|
|
||||||
<button type=submit name="print" style="background:linear-gradient(90deg,#ffeb3b 55%,#ff9100 95%);color:#181c1f;">🖨️ Imprimir</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% if printed %}
|
|
||||||
<div class="status-msg">✅ Enviado a impresora</div>
|
|
||||||
{% endif %}
|
|
||||||
{% if error %}
|
|
||||||
<div class="status-msg status-err">⚠️ {{ error }}</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="preview-card">
|
|
||||||
{% if img %}
|
|
||||||
<h3 style="margin-top:0.1em;margin-bottom:0.6em;">Vista previa</h3>
|
|
||||||
<img src="data:image/png;base64,{{ img }}">
|
|
||||||
{% else %}
|
|
||||||
<p style="opacity:.6;">Su vista previa aparecerá aquí</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def parse_line(line):
|
def parse_line(line):
|
||||||
header_level = 0
|
if re.match(r'^\s*---\s*$', line):
|
||||||
|
return ('hr', [])
|
||||||
header_match = re.match(r"^(#{1,3}) +(.*)", line)
|
header_match = re.match(r"^(#{1,3}) +(.*)", line)
|
||||||
if header_match:
|
if header_match:
|
||||||
header_level = len(header_match.group(1))
|
header_level = len(header_match.group(1))
|
||||||
@ -307,7 +375,9 @@ def render(md):
|
|||||||
lines_out.append(('blank', []))
|
lines_out.append(('blank', []))
|
||||||
continue
|
continue
|
||||||
tag = parse_line(src_line)
|
tag = parse_line(src_line)
|
||||||
if tag[0] == 'header':
|
if tag[0] == 'hr':
|
||||||
|
lines_out.append(('hr',))
|
||||||
|
elif tag[0] == 'header':
|
||||||
header_level = tag[1]
|
header_level = tag[1]
|
||||||
segments = tag[2]
|
segments = tag[2]
|
||||||
if header_level == 1:
|
if header_level == 1:
|
||||||
@ -346,13 +416,23 @@ def render(md):
|
|||||||
segments = tag[1]
|
segments = tag[1]
|
||||||
for wrapped in wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH):
|
for wrapped in wrap_segments(segments, font, font_bold, font_italic, font_bolditalic, IMAGE_WIDTH):
|
||||||
lines_out.append(('text', wrapped, font, FONT_SIZE))
|
lines_out.append(('text', wrapped, font, FONT_SIZE))
|
||||||
height = sum(item[3] if item[0] in ('header','text','bullet','ordered') else FONT_SIZE for item in lines_out) + 10
|
|
||||||
|
height = sum(
|
||||||
|
item[3] if item[0] in ('header', 'text', 'bullet', 'ordered') else
|
||||||
|
10 if item[0] == 'hr' else
|
||||||
|
FONT_SIZE
|
||||||
|
for item in lines_out
|
||||||
|
) + 10
|
||||||
|
|
||||||
image = Image.new("L", (IMAGE_WIDTH, height), 255)
|
image = Image.new("L", (IMAGE_WIDTH, height), 255)
|
||||||
draw = ImageDraw.Draw(image)
|
draw = ImageDraw.Draw(image)
|
||||||
y = 0
|
y = 0
|
||||||
for item in lines_out:
|
for item in lines_out:
|
||||||
if item[0] == 'blank':
|
if item[0] == 'blank':
|
||||||
y += FONT_SIZE
|
y += FONT_SIZE
|
||||||
|
elif item[0] == 'hr':
|
||||||
|
draw.line((0, y + 5, IMAGE_WIDTH, y + 5), fill=0, width=2)
|
||||||
|
y += 10
|
||||||
elif item[0] == 'header':
|
elif item[0] == 'header':
|
||||||
segments, fnt, sz = item[1], item[2], item[3]
|
segments, fnt, sz = item[1], item[2], item[3]
|
||||||
x = 0
|
x = 0
|
||||||
@ -396,7 +476,6 @@ def render(md):
|
|||||||
y += sz
|
y += sz
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=["GET", "POST"])
|
@app.route("/", methods=["GET", "POST"])
|
||||||
def index():
|
def index():
|
||||||
img_data = None
|
img_data = None
|
||||||
@ -436,4 +515,4 @@ def index():
|
|||||||
printed=printed, error=error)
|
printed=printed, error=error)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(host="0.0.0.0")
|
app.run(host="0.0.0.0", debug=True)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user