Compare commits

...

2 Commits

Author SHA1 Message Date
Deeman
94d92328b8 merge: fix article .md lookup + lighter editor
All checks were successful
CI / test (push) Successful in 51s
CI / tag (push) Successful in 3s
2026-03-02 11:47:13 +01:00
Deeman
100e200c3b 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.
2026-03-02 11:43:26 +01:00
2 changed files with 43 additions and 17 deletions

View File

@@ -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)
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.
@@ -2544,11 +2565,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

View File

@@ -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 %}