feat: full Markdown support in service card comments (mistune)
This commit is contained in:
+7
-24
@@ -16,6 +16,7 @@ from typing import Optional
|
|||||||
|
|
||||||
import docker
|
import docker
|
||||||
import requests
|
import requests
|
||||||
|
import mistune
|
||||||
from fastapi import Depends, FastAPI, File, Form, HTTPException, Query, Request, UploadFile, status
|
from fastapi import Depends, FastAPI, File, Form, HTTPException, Query, Request, UploadFile, status
|
||||||
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
@@ -299,34 +300,16 @@ def normalize_web_target(url: str) -> str:
|
|||||||
return f"http://{raw}"
|
return f"http://{raw}"
|
||||||
|
|
||||||
|
|
||||||
|
_md = mistune.create_markdown(
|
||||||
|
escape=True,
|
||||||
|
plugins=["strikethrough", "table", "task_lists"],
|
||||||
|
)
|
||||||
|
|
||||||
def format_service_comment(raw_text: str) -> Markup:
|
def format_service_comment(raw_text: str) -> Markup:
|
||||||
raw = (raw_text or "").replace("\r\n", "\n").replace("\r", "\n").strip()
|
raw = (raw_text or "").replace("\r\n", "\n").replace("\r", "\n").strip()
|
||||||
if not raw:
|
if not raw:
|
||||||
return Markup("")
|
return Markup("")
|
||||||
escaped = str(escape(raw))
|
return Markup(_md(raw))
|
||||||
# Support pasted/plain markdown-like bold fragments.
|
|
||||||
escaped = re.sub(r"\*\*(.+?)\*\*", r"<strong>\1</strong>", escaped, flags=re.DOTALL)
|
|
||||||
# Allow a small safe subset of pasted HTML tags.
|
|
||||||
replacements = {
|
|
||||||
"<b>": "<b>",
|
|
||||||
"</b>": "</b>",
|
|
||||||
"<strong>": "<strong>",
|
|
||||||
"</strong>": "</strong>",
|
|
||||||
"<i>": "<i>",
|
|
||||||
"</i>": "</i>",
|
|
||||||
"<em>": "<em>",
|
|
||||||
"</em>": "</em>",
|
|
||||||
"<u>": "<u>",
|
|
||||||
"</u>": "</u>",
|
|
||||||
"<br>": "<br>",
|
|
||||||
"<br/>": "<br>",
|
|
||||||
"<br />": "<br>",
|
|
||||||
}
|
|
||||||
for src, dst in replacements.items():
|
|
||||||
escaped = escaped.replace(src, dst)
|
|
||||||
escaped = escaped.replace("\n", "<br>")
|
|
||||||
return Markup(escaped)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_rdp_target(target: str) -> dict:
|
def parse_rdp_target(target: str) -> dict:
|
||||||
raw = (target or "").strip()
|
raw = (target or "").strip()
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ jinja2==3.1.6
|
|||||||
passlib[argon2]==1.7.4
|
passlib[argon2]==1.7.4
|
||||||
docker==7.1.0
|
docker==7.1.0
|
||||||
itsdangerous==2.2.0
|
itsdangerous==2.2.0
|
||||||
|
mistune==3.1.3
|
||||||
|
|||||||
@@ -781,3 +781,34 @@ button {
|
|||||||
color: rgba(240, 248, 255, 0.95);
|
color: rgba(240, 248, 255, 0.95);
|
||||||
text-shadow: 0 2px 10px rgba(9, 44, 72, 0.45);
|
text-shadow: 0 2px 10px rgba(9, 44, 72, 0.45);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Markdown inside service card comments */
|
||||||
|
.tile-comment p { margin: 0 0 0.4em; }
|
||||||
|
.tile-comment p:last-child { margin-bottom: 0; }
|
||||||
|
.tile-comment ul, .tile-comment ol { margin: 0.3em 0 0.4em 1.2em; padding: 0; }
|
||||||
|
.tile-comment li { margin-bottom: 0.15em; }
|
||||||
|
.tile-comment h1,.tile-comment h2,.tile-comment h3,
|
||||||
|
.tile-comment h4,.tile-comment h5,.tile-comment h6 {
|
||||||
|
font-size: 0.85em; font-weight: 700; margin: 0.4em 0 0.2em;
|
||||||
|
}
|
||||||
|
.tile-comment code {
|
||||||
|
font-family: monospace; font-size: 0.88em;
|
||||||
|
background: rgba(0,0,0,.06); border-radius: 3px; padding: 0.1em 0.3em;
|
||||||
|
}
|
||||||
|
.tile-comment pre {
|
||||||
|
background: rgba(0,0,0,.06); border-radius: 4px;
|
||||||
|
padding: 0.4em 0.6em; overflow-x: auto; font-size: 0.82em;
|
||||||
|
}
|
||||||
|
.tile-comment pre code { background: none; padding: 0; }
|
||||||
|
.tile-comment blockquote {
|
||||||
|
border-left: 3px solid #c7d9e8; margin: 0.3em 0 0.3em 0;
|
||||||
|
padding-left: 0.6em; color: #5a7a90;
|
||||||
|
}
|
||||||
|
.tile-comment a { color: #1668a6; text-decoration: underline; }
|
||||||
|
.tile-comment table { border-collapse: collapse; font-size: 0.82em; margin: 0.3em 0; }
|
||||||
|
.tile-comment th, .tile-comment td {
|
||||||
|
border: 1px solid #c7d9e8; padding: 0.2em 0.5em;
|
||||||
|
}
|
||||||
|
.tile-comment th { background: #eaf2fb; font-weight: 700; }
|
||||||
|
.tile-comment del { text-decoration: line-through; color: #7a9aaf; }
|
||||||
|
.tile-comment input[type=checkbox] { margin-right: 0.3em; }
|
||||||
|
|||||||
Reference in New Issue
Block a user