merge: fix article .md lookup + lighter editor
This commit is contained in:
@@ -2121,6 +2121,27 @@ _ARTICLES_DIR = Path(__file__).parent.parent.parent.parent.parent / "data" / "co
|
|||||||
_FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
|
_FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_article_md(slug: str) -> Path | None:
|
||||||
|
"""Return the Path of the .md file whose frontmatter slug matches, or None.
|
||||||
|
|
||||||
|
Tries the exact name first ({slug}.md), then scans _ARTICLES_DIR for any
|
||||||
|
file whose YAML frontmatter contains 'slug: <slug>'. This handles the
|
||||||
|
common pattern where files are named {slug}-{lang}.md but the frontmatter
|
||||||
|
slug omits the language suffix.
|
||||||
|
"""
|
||||||
|
if not _ARTICLES_DIR.is_dir():
|
||||||
|
return None
|
||||||
|
exact = _ARTICLES_DIR / f"{slug}.md"
|
||||||
|
if exact.exists():
|
||||||
|
return exact
|
||||||
|
for path in _ARTICLES_DIR.glob("*.md"):
|
||||||
|
raw = path.read_text(encoding="utf-8")
|
||||||
|
m = _FRONTMATTER_RE.match(raw)
|
||||||
|
if m and f"slug: {slug}" in m.group(1):
|
||||||
|
return path
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _sync_static_articles() -> None:
|
async def _sync_static_articles() -> None:
|
||||||
"""Upsert static .md articles from data/content/articles/ into the DB.
|
"""Upsert static .md articles from data/content/articles/ into the DB.
|
||||||
|
|
||||||
@@ -2544,11 +2565,12 @@ async def article_edit(article_id: int):
|
|||||||
|
|
||||||
# Load markdown source if available (manual or generated)
|
# Load markdown source if available (manual or generated)
|
||||||
from ..content.routes import BUILD_DIR as CONTENT_BUILD_DIR
|
from ..content.routes import BUILD_DIR as CONTENT_BUILD_DIR
|
||||||
md_path = _ARTICLES_DIR / f"{article['slug']}.md"
|
md_path = _find_article_md(article["slug"])
|
||||||
if not md_path.exists():
|
if md_path is None:
|
||||||
lang = article["language"] or "en"
|
lang = article["language"] or "en"
|
||||||
md_path = CONTENT_BUILD_DIR / lang / "md" / f"{article['slug']}.md"
|
fallback = CONTENT_BUILD_DIR / lang / "md" / f"{article['slug']}.md"
|
||||||
raw = md_path.read_text() if md_path.exists() else ""
|
md_path = fallback if fallback.exists() else None
|
||||||
|
raw = md_path.read_text() if md_path else ""
|
||||||
# Strip YAML frontmatter so only the prose body appears in the editor
|
# Strip YAML frontmatter so only the prose body appears in the editor
|
||||||
m = _FRONTMATTER_RE.match(raw)
|
m = _FRONTMATTER_RE.match(raw)
|
||||||
body = raw[m.end():].lstrip("\n") if m else raw
|
body = raw[m.end():].lstrip("\n") if m else raw
|
||||||
|
|||||||
@@ -156,8 +156,8 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 0.375rem 0.875rem;
|
padding: 0.375rem 0.875rem;
|
||||||
background: #1E293B;
|
background: #F8FAFC;
|
||||||
border-bottom: 1px solid #0F172A;
|
border-bottom: 1px solid #E2E8F0;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.ae-pane--preview .ae-pane__header {
|
.ae-pane--preview .ae-pane__header {
|
||||||
@@ -171,13 +171,11 @@
|
|||||||
letter-spacing: 0.09em;
|
letter-spacing: 0.09em;
|
||||||
color: #94A3B8;
|
color: #94A3B8;
|
||||||
}
|
}
|
||||||
.ae-pane--editor .ae-pane__label { color: #475569; }
|
|
||||||
.ae-pane__hint {
|
.ae-pane__hint {
|
||||||
font-size: 0.625rem;
|
font-size: 0.625rem;
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
color: #475569;
|
color: #94A3B8;
|
||||||
}
|
}
|
||||||
.ae-pane--preview .ae-pane__hint { color: #94A3B8; }
|
|
||||||
|
|
||||||
/* The markdown textarea */
|
/* The markdown textarea */
|
||||||
.ae-editor {
|
.ae-editor {
|
||||||
@@ -185,16 +183,16 @@
|
|||||||
resize: none;
|
resize: none;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
padding: 1.125rem 1.25rem;
|
padding: 1.5rem 2rem;
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
font-size: 0.8125rem;
|
font-size: 0.875rem;
|
||||||
line-height: 1.75;
|
line-height: 1.8;
|
||||||
background: #0F172A;
|
background: #FEFDFB;
|
||||||
color: #CBD5E1;
|
color: #1E293B;
|
||||||
caret-color: #3B82F6;
|
caret-color: #1D4ED8;
|
||||||
tab-size: 2;
|
tab-size: 2;
|
||||||
}
|
}
|
||||||
.ae-editor::placeholder { color: #334155; }
|
.ae-editor::placeholder { color: #CBD5E1; }
|
||||||
.ae-editor:focus { outline: none; }
|
.ae-editor:focus { outline: none; }
|
||||||
|
|
||||||
/* Preview pane */
|
/* Preview pane */
|
||||||
@@ -283,9 +281,15 @@
|
|||||||
color: #94A3B8;
|
color: #94A3B8;
|
||||||
font-family: var(--font-mono);
|
font-family: var(--font-mono);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.15s;
|
transition: opacity 0.2s;
|
||||||
}
|
}
|
||||||
.ae-loading.htmx-request { opacity: 1; }
|
.ae-loading.htmx-request { opacity: 1; }
|
||||||
|
|
||||||
|
/* Responsive: stack on narrow screens */
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.ae-split { grid-template-columns: 1fr; }
|
||||||
|
.ae-pane--preview { display: none; }
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user