fix(articles): find .md by slug scan + lighter editor theme
Two fixes:
- _find_article_md() scans _ARTICLES_DIR for files whose frontmatter
slug matches, so padel-halle-bauen-de.md is found for slug
'padel-halle-bauen'. The previous exact-name lookup missed any file
where the filename ≠ slug (e.g. {slug}-{lang}.md naming convention).
- Editor pane: replace dark navy background with warm off-white (#FEFDFB)
and dark text so it reads like a document, not a code editor.
This commit is contained in:
@@ -2203,6 +2203,27 @@ _ARTICLES_DIR = Path(__file__).parent.parent.parent.parent.parent / "data" / "co
|
||||
_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:
|
||||
"""Upsert static .md articles from data/content/articles/ into the DB.
|
||||
|
||||
@@ -2626,11 +2647,12 @@ async def article_edit(article_id: int):
|
||||
|
||||
# Load markdown source if available (manual or generated)
|
||||
from ..content.routes import BUILD_DIR as CONTENT_BUILD_DIR
|
||||
md_path = _ARTICLES_DIR / f"{article['slug']}.md"
|
||||
if not md_path.exists():
|
||||
md_path = _find_article_md(article["slug"])
|
||||
if md_path is None:
|
||||
lang = article["language"] or "en"
|
||||
md_path = CONTENT_BUILD_DIR / lang / "md" / f"{article['slug']}.md"
|
||||
raw = md_path.read_text() if md_path.exists() else ""
|
||||
fallback = CONTENT_BUILD_DIR / lang / "md" / f"{article['slug']}.md"
|
||||
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
|
||||
m = _FRONTMATTER_RE.match(raw)
|
||||
body = raw[m.end():].lstrip("\n") if m else raw
|
||||
|
||||
@@ -156,8 +156,8 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.375rem 0.875rem;
|
||||
background: #1E293B;
|
||||
border-bottom: 1px solid #0F172A;
|
||||
background: #F8FAFC;
|
||||
border-bottom: 1px solid #E2E8F0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.ae-pane--preview .ae-pane__header {
|
||||
@@ -171,13 +171,11 @@
|
||||
letter-spacing: 0.09em;
|
||||
color: #94A3B8;
|
||||
}
|
||||
.ae-pane--editor .ae-pane__label { color: #475569; }
|
||||
.ae-pane__hint {
|
||||
font-size: 0.625rem;
|
||||
font-family: var(--font-mono);
|
||||
color: #475569;
|
||||
color: #94A3B8;
|
||||
}
|
||||
.ae-pane--preview .ae-pane__hint { color: #94A3B8; }
|
||||
|
||||
/* The markdown textarea */
|
||||
.ae-editor {
|
||||
@@ -185,16 +183,16 @@
|
||||
resize: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 1.125rem 1.25rem;
|
||||
padding: 1.5rem 2rem;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.75;
|
||||
background: #0F172A;
|
||||
color: #CBD5E1;
|
||||
caret-color: #3B82F6;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.8;
|
||||
background: #FEFDFB;
|
||||
color: #1E293B;
|
||||
caret-color: #1D4ED8;
|
||||
tab-size: 2;
|
||||
}
|
||||
.ae-editor::placeholder { color: #334155; }
|
||||
.ae-editor::placeholder { color: #CBD5E1; }
|
||||
.ae-editor:focus { outline: none; }
|
||||
|
||||
/* Preview pane */
|
||||
@@ -283,9 +281,15 @@
|
||||
color: #94A3B8;
|
||||
font-family: var(--font-mono);
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.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>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user