Refine TalkOrigins POC navigation and resources

This commit is contained in:
welsberr 2026-04-28 19:05:36 +00:00
parent 81a7745760
commit 66378d938f
8 changed files with 183 additions and 59 deletions

View File

@ -2,7 +2,7 @@
"lang": "en", "lang": "en",
"title": "TalkOrigins Archive: Modernized Preview", "title": "TalkOrigins Archive: Modernized Preview",
"site_title": "TalkOrigins Archive", "site_title": "TalkOrigins Archive",
"description": "A SciSiteForge proof-of-concept for the www2.talkorigins.org modernization line.", "description": "A SciSiteForge proof-of-concept for poc1.talkorigins.org and the TalkOrigins Archive modernization line.",
"license": "CC BY-SA 4.0", "license": "CC BY-SA 4.0",
"github_url": "https://git.cns.fyi/welsberr/talkorigins-modern", "github_url": "https://git.cns.fyi/welsberr/talkorigins-modern",
"contact_email": "feedback@talkorigins.org", "contact_email": "feedback@talkorigins.org",
@ -35,52 +35,59 @@
] ]
}, },
"navigation": [ "navigation": [
{ "label": "Home", "href": "/" }, { "label": "Start Here", "href": "#start" },
{ "label": "Support", "href": "/foundation/2026-update/" }, { "label": "Key Resources", "href": "#resources" },
{ "label": "Search", "href": "/search/" } { "label": "Search", "href": "https://www.talkorigins.org/search/" },
{ "label": "Roadmap", "href": "#roadmap" },
{ "label": "Support", "href": "#roadmap" }
], ],
"hero": { "hero": {
"kicker": "Archive Preview", "kicker": "Archive Preview",
"title": "A cleaner, more readable TalkOrigins Archive that still feels like the Archive.", "title": "A clearer front door for the TalkOrigins Archive.",
"lede": "Modernization is already underway: stable Archive articles, dynamic sister-site commentary, corpus-aware search, and claim-centered notebooks can coexist without collapsing into a single CMS.", "lede": "The modernization work keeps the Archive's stable reference role while making it easier for a first-time reader to find explanations, claims, search tools, and sister Foundation resources.",
"actions": [ "actions": [
{ "label": "Open the preview", "href": "/#overview", "primary": true }, { "label": "Start with the overview", "href": "#start", "primary": true },
{ "label": "View support update", "href": "/foundation/2026-update/", "primary": false } { "label": "See the roadmap", "href": "#roadmap", "primary": false }
] ]
}, },
"content": { "content": {
"feature_cards": [ "feature_cards": [
{ {
"title": "Stable Archive, Modern Access", "title": "New to the topic?",
"body": "The preview keeps the Archive's durable explanatory role while making the reading surface responsive, easier to scan, and easier to route through search.", "body": "Start with readable explanations that separate the scientific issues from the rhetoric around them.",
"href": "/", "href": "https://www.talkorigins.org/faqs/faq-misconceptions.html",
"meta": "modernization" "meta": "Archive guide",
"link_label": "Read a sample FAQ"
}, },
{ {
"title": "Foundation Search", "title": "Looking for a specific claim?",
"body": "Search can select among TalkOrigins, TalkDesign, Panda's Thumb, Panda's Thumb MT, and the Index to Creationist Claims as separate corpora.", "body": "The Index to Creationist Claims gives readers a direct path from a familiar claim to a response and references.",
"href": "/search/", "href": "https://www.talkorigins.org/indexcc/",
"meta": "workbench" "meta": "Claim index",
"link_label": "Open the Index"
}, },
{ {
"title": "Support Update", "title": "Searching across Foundation sites?",
"body": "The public update explains that modernization is already underway and that the stable Archive/dynamic commentary split is intentional.", "body": "Foundation search keeps TalkOrigins, TalkDesign, Panda's Thumb, Panda's Thumb MT, and the claim index as distinct selectable corpora.",
"href": "/foundation/2026-update/", "href": "https://www.talkorigins.org/search/",
"meta": "public proof" "meta": "Search",
"link_label": "Search the sites"
} }
], ],
"section_cards": [ "section_cards": [
{ {
"title": "Featured FAQ: Misconceptions", "title": "Featured FAQ: Misconceptions",
"body": "A representative long-form Archive article demonstrates how legacy explanatory material can be presented in the modern theme.", "body": "A representative long-form Archive article demonstrates how legacy explanatory material can be presented in the modern theme.",
"href": "/faqs/faq-misconceptions/", "href": "https://www.talkorigins.org/faqs/faq-misconceptions.html",
"meta": "Archive article" "meta": "Archive article",
"link_label": "Read the FAQ"
}, },
{ {
"title": "Featured Claim: CA100", "title": "Featured Claim: CA100",
"body": "A representative Index to Creationist Claims entry shows the claim-centered path into evidence and rebuttal material.", "body": "A representative Index to Creationist Claims entry shows the claim-centered path into evidence and rebuttal material.",
"href": "/indexcc/CA100/", "href": "https://www.talkorigins.org/indexcc/CA/CA100.html",
"meta": "Index claim" "meta": "Index claim",
"link_label": "Read the claim entry"
} }
], ],
"bibliography_entries": [ "bibliography_entries": [
@ -107,18 +114,18 @@
"notebooks": [ "notebooks": [
{ {
"id": "evidence-and-claims", "id": "evidence-and-claims",
"title": "Evidence and Claims Notebook", "title": "Evidence and Claims Reading Path",
"summary": "A reusable study module that can connect stable Archive articles, Index to Creationist Claims entries, guided concepts, and bibliography updates.", "summary": "A guided path can connect stable Archive articles, Index to Creationist Claims entries, search results, and bibliography updates without hiding where each source came from.",
"audience": "self-learners, instructors, and board-reviewed site editors", "audience": "interested lay readers, instructors, and site editors",
"goals": [ "goals": [
"Move from a claim to the relevant evidence and archive context", "Move from a claim to the relevant evidence and archive context",
"Keep stable source material separate from dynamic commentary", "Keep stable source material separate from dynamic commentary",
"Expose provenance, citations, and review status as first-class study material" "Show provenance, citations, and review status as part of the reading experience"
], ],
"apps": [ "apps": [
{ {
"title": "Public search", "title": "Public search",
"href": "/search/", "href": "https://www.talkorigins.org/search/",
"description": "Search across Foundation corpora and the Index to Creationist Claims" "description": "Search across Foundation corpora and the Index to Creationist Claims"
} }
], ],
@ -126,5 +133,27 @@
"max_items": 8 "max_items": 8
} }
], ],
"roadmap": [
{
"title": "Replace the preview placeholders with real Archive pages",
"status": "Next",
"body": "Use the modernization theme on selected high-value FAQs and claim pages so readers can evaluate actual content, not just a shell."
},
{
"title": "Promote corpus-aware Foundation search",
"status": "Next",
"body": "Make search visible from each Foundation-associated domain with Index and local-domain corpora selected by default."
},
{
"title": "Connect support messaging to visible modernization work",
"status": "Planned",
"body": "Use the proof-of-concept site to show that the Archive is being actively maintained while preserving the stable Archive and dynamic commentary split."
},
{
"title": "Add guided reading paths",
"status": "Planned",
"body": "Generalize the notebook pattern into reader-friendly paths that help users move from questions, claims, and classroom needs to reliable Archive material."
}
],
"content_sources": {} "content_sources": {}
} }

View File

@ -17,6 +17,7 @@ class ContentCard:
meta: str = "" meta: str = ""
kind: str = "feature" kind: str = "feature"
source: str = "" source: str = ""
link_label: str = "Read More"
@dataclass(slots=True) @dataclass(slots=True)
@ -42,6 +43,7 @@ def cards_from_config(items: list[dict[str, Any]], *, default_kind: str) -> list
meta=str(item.get("meta") or item.get("kind") or default_kind), meta=str(item.get("meta") or item.get("kind") or default_kind),
kind=str(item.get("kind") or default_kind), kind=str(item.get("kind") or default_kind),
source=str(item.get("source") or item.get("id") or title.lower().replace(" ", "-")), source=str(item.get("source") or item.get("id") or title.lower().replace(" ", "-")),
link_label=str(item.get("link_label") or item.get("label") or "Read More"),
) )
) )
return cards return cards

View File

@ -69,6 +69,8 @@ def _language_options_html(languages: list[dict[str, str]], current_lang: str) -
for item in languages for item in languages
if item.get("coverage", True) or item.get("code") == current_lang if item.get("coverage", True) or item.get("code") == current_lang
] ]
if len(visible_languages) <= 1:
return ""
return "\n".join( return "\n".join(
f'<option value="{html_escape(item["code"])}" {"selected" if item["code"] == current_lang else ""}>{html_escape(item["name"])}</option>' f'<option value="{html_escape(item["code"])}" {"selected" if item["code"] == current_lang else ""}>{html_escape(item["name"])}</option>'
for item in visible_languages for item in visible_languages
@ -85,6 +87,41 @@ def _language_policy_html(language_policy: dict[str, Any]) -> str:
return f'<p class="language-policy-note">Planned languages: {planned_names}</p>' return f'<p class="language-policy-note">Planned languages: {planned_names}</p>'
def _roadmap_html(roadmap: list[dict[str, Any]], language_policy: dict[str, Any]) -> str:
items = []
for item in roadmap:
if not isinstance(item, dict):
continue
title = html_escape(item.get("title", "Roadmap item"))
body = html_escape(item.get("body", ""))
status = html_escape(item.get("status", "Planned"))
items.append(f'<li><strong>{title}</strong> <span class="meta">{status}</span><p>{body}</p></li>')
planned_languages = language_policy.get("planned_languages", [])
planned_names = ", ".join(
html_escape(item.get("name", item.get("code", "")))
for item in planned_languages
if isinstance(item, dict) and (item.get("name") or item.get("code"))
)
if planned_names:
items.append(
'<li><strong>Multilingual access</strong> <span class="meta">Planned</span>'
f'<p>Language options will appear only when reviewed coverage exists. Target languages under consideration: {planned_names}.</p></li>'
)
if not items:
return ""
return '<ul class="roadmap-list">' + "\n".join(items) + "</ul>"
def _language_selector_html(language_options: str) -> str:
if not language_options:
return ""
return (
'<select id="lang-switch" aria-label="Language" onchange="switchLanguage(this.value)">'
f"{language_options}"
"</select>"
)
def _hero_actions_html(actions: list[dict[str, Any]]) -> str: def _hero_actions_html(actions: list[dict[str, Any]]) -> str:
if not actions: if not actions:
return "" return ""
@ -120,7 +157,7 @@ def _render_cards(cards: list, template_path: str | Path, lang: str) -> str:
"section_excerpt": html_escape(card.body), "section_excerpt": html_escape(card.body),
"section_path": html_escape(card.source or card.title.lower().replace(" ", "-")), "section_path": html_escape(card.source or card.title.lower().replace(" ", "-")),
"href": html_escape(card.href), "href": html_escape(card.href),
"link_label": "Open", "link_label": html_escape(card.link_label),
}, },
) )
) )
@ -175,6 +212,7 @@ def build_site(config_file: str | Path, output_dir: str | Path) -> dict[str, Any
"page_class": html_escape(theme.page_class), "page_class": html_escape(theme.page_class),
"navigation_html": _navigation_html(config.get("navigation", [])), "navigation_html": _navigation_html(config.get("navigation", [])),
"language_options": _language_options_html(languages, config.get("lang", "en")), "language_options": _language_options_html(languages, config.get("lang", "en")),
"language_selector_html": _language_selector_html(_language_options_html(languages, config.get("lang", "en"))),
"language_policy_html": _language_policy_html(language_policy), "language_policy_html": _language_policy_html(language_policy),
"hero_kicker": html_escape(hero.get("kicker", theme.display_name)), "hero_kicker": html_escape(hero.get("kicker", theme.display_name)),
"hero_title": html_escape(hero.get("title", config.get("title", ""))), "hero_title": html_escape(hero.get("title", config.get("title", ""))),
@ -188,6 +226,7 @@ def build_site(config_file: str | Path, output_dir: str | Path) -> dict[str, Any
for card in site_content.bibliography_entries for card in site_content.bibliography_entries
), ),
"notebook_html": render_notebooks(notebooks, site_content), "notebook_html": render_notebooks(notebooks, site_content),
"roadmap_html": _roadmap_html(config.get("roadmap", []), language_policy),
} }
page_context.update( page_context.update(
{ {

View File

@ -1,5 +1,5 @@
<article class="card feature-card"> <article class="card feature-card">
<h3>{{ app_title }}</h3> <h3>{{ app_title }}</h3>
<p>{{ app_description }}</p> <p>{{ app_description }}</p>
<a href="/{{ lang }}/apps/{{ app_slug }}/" class="btn button-link">Launch App</a> <a href="{{ href }}" class="btn button-link">{{ link_label }}</a>
</article> </article>

View File

@ -2,6 +2,6 @@
<h3>{{ section_title }}</h3> <h3>{{ section_title }}</h3>
<p class="meta">{{ section_meta }}</p> <p class="meta">{{ section_meta }}</p>
<p class="excerpt">{{ section_excerpt }}</p> <p class="excerpt">{{ section_excerpt }}</p>
<button class="expand-btn btn button-link" data-src="/{{ lang }}/notebook/{{ section_path }}">Show</button> <a href="{{ href }}" class="btn button-link">{{ link_label }}</a>
<div class="content"></div> <div class="content"></div>
</div> </div>

View File

@ -109,6 +109,7 @@ class SciSiteForgeTests(unittest.TestCase):
"body": "Corpus-aware search entry point.", "body": "Corpus-aware search entry point.",
"href": "/search/", "href": "/search/",
"meta": "workbench", "meta": "workbench",
"link_label": "Search",
} }
], ],
default_kind="feature", default_kind="feature",
@ -118,6 +119,7 @@ class SciSiteForgeTests(unittest.TestCase):
self.assertEqual(cards[0].kind, "feature") self.assertEqual(cards[0].kind, "feature")
self.assertEqual(cards[0].href, "/search/") self.assertEqual(cards[0].href, "/search/")
self.assertEqual(cards[0].meta, "workbench") self.assertEqual(cards[0].meta, "workbench")
self.assertEqual(cards[0].link_label, "Search")
def test_build_site_renders_selected_theme_and_content(self) -> None: def test_build_site_renders_selected_theme_and_content(self) -> None:
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
@ -236,10 +238,11 @@ class SciSiteForgeTests(unittest.TestCase):
build.build_site(config_path, out_dir) build.build_site(config_path, out_dir)
html = (out_dir / "index.html").read_text(encoding="utf-8") html = (out_dir / "index.html").read_text(encoding="utf-8")
self.assertIn('<option value="en" selected>English</option>', html) self.assertNotIn('<select id="lang-switch"', html)
self.assertNotIn('value="es"', html) self.assertNotIn('value="es"', html)
self.assertNotIn('value="fr"', html) self.assertNotIn('value="fr"', html)
self.assertIn("Planned languages: Español, Français", html) self.assertIn("Multilingual access", html)
self.assertIn("Target languages under consideration: Español, Français", html)
def test_notebook_pattern_groups_goals_apps_and_source_cards(self) -> None: def test_notebook_pattern_groups_goals_apps_and_source_cards(self) -> None:
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory

View File

@ -27,10 +27,7 @@
</div> </div>
<nav class="top-nav" aria-label="Primary navigation"> <nav class="top-nav" aria-label="Primary navigation">
{{ navigation_html }} {{ navigation_html }}
<select id="lang-switch" onchange="switchLanguage(this.value)"> {{ language_selector_html }}
{{ language_options }}
</select>
{{ language_policy_html }}
</nav> </nav>
</header> </header>
@ -46,27 +43,27 @@
</div> </div>
</div> </div>
<div class="continuity-note hero-note"> <div class="continuity-note hero-note">
<p class="eyebrow">Framework</p> <p class="eyebrow">What This Is</p>
<h2>Modular, static, and reviewable</h2> <h2>A preview of a working modernization path</h2>
<p>This theme is intended to prove the modernization line without giving up the archive posture.</p> <p>The Archive remains a stable reference library. The redesign makes that library easier to read, search, and connect to sister Foundation resources.</p>
<ul class="link-list compact-list"> <ul class="link-list compact-list">
<li>Responsive reading</li> <li>Stable explanatory articles</li>
<li>Reusable content blocks</li> <li>Claim-centered entry points</li>
<li>Search and bibliography ready</li> <li>Search across Foundation corpora</li>
</ul> </ul>
</div> </div>
</div> </div>
</section> </section>
<section class="content-panel"> <section id="start" class="content-panel lead-panel">
<h2>Feature cards</h2> <h2>Start Here</h2>
<div class="feature-grid"> <div class="feature-grid">
{{ feature_cards_html }} {{ feature_cards_html }}
</div> </div>
</section> </section>
<section class="content-panel"> <section id="resources" class="content-panel resources-panel">
<h2>Notebook and app content</h2> <h2>Key Resources</h2>
{{ notebook_html }} {{ notebook_html }}
<div class="section-grid"> <div class="section-grid">
{{ section_cards_html }} {{ section_cards_html }}
@ -74,12 +71,17 @@
</div> </div>
</section> </section>
<section class="content-panel"> <section id="references" class="content-panel">
<h2>Bibliography</h2> <h2>Reference Context</h2>
<ul class="archive-list bibliography-list"> <ul class="archive-list bibliography-list">
{{ bibliography_html }} {{ bibliography_html }}
</ul> </ul>
</section> </section>
<section id="roadmap" class="content-panel roadmap-panel">
<h2>Roadmap</h2>
{{ roadmap_html }}
</section>
</main> </main>
<footer class="site-footer"> <footer class="site-footer">

View File

@ -12,7 +12,8 @@
--gold: #b18d33; --gold: #b18d33;
--gold-soft: #f3e4b3; --gold-soft: #f3e4b3;
--brick-soft: #efe1dc; --brick-soft: #efe1dc;
--shadow: 0 22px 55px rgba(20, 33, 53, 0.1); --shadow: 0 18px 42px rgba(20, 33, 53, 0.09);
--card-shadow: 0 8px 20px rgba(20, 33, 53, 0.06);
--max-width: 1180px; --max-width: 1180px;
--article-width: 760px; --article-width: 760px;
} }
@ -71,15 +72,21 @@ a:hover {
.article-body, .article-body,
.side-card, .side-card,
.site-footer, .site-footer,
.continuity-note, .continuity-note {
.feature-card,
.section-card {
background: var(--panel); background: var(--panel);
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 22px; border-radius: 22px;
box-shadow: var(--shadow); box-shadow: var(--shadow);
} }
.feature-card,
.section-card {
background: rgba(255, 255, 255, 0.58);
border: 1px solid var(--line);
border-radius: 10px;
box-shadow: var(--card-shadow);
}
.site-header, .site-header,
.site-footer, .site-footer,
.hero-panel, .hero-panel,
@ -165,10 +172,12 @@ a:hover {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 10px; gap: 10px;
align-items: center;
} }
.top-nav a, .top-nav a,
.button-link { .button-link,
.top-nav select {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -181,11 +190,16 @@ a:hover {
} }
.top-nav a, .top-nav a,
.button-link.button-link-secondary { .button-link.button-link-secondary,
.top-nav select {
background: rgba(255, 255, 255, 0.82); background: rgba(255, 255, 255, 0.82);
color: var(--ink); color: var(--ink);
} }
.top-nav select {
font: 600 0.95rem/1.2 "Helvetica Neue", Arial, sans-serif;
}
.button-link, .button-link,
.top-nav a:first-child { .top-nav a:first-child {
background: linear-gradient(180deg, var(--blue), var(--blue-deep)); background: linear-gradient(180deg, var(--blue), var(--blue-deep));
@ -292,6 +306,12 @@ a:hover {
border-top: 5px solid rgba(177, 141, 51, 0.45); border-top: 5px solid rgba(177, 141, 51, 0.45);
} }
.resources-panel {
background:
linear-gradient(180deg, rgba(255, 255, 255, 0.98), rgba(244, 248, 252, 0.96));
border-top: 5px solid rgba(33, 79, 148, 0.34);
}
.preview-panel { .preview-panel {
background: background:
linear-gradient(180deg, rgba(244, 248, 252, 0.92), rgba(255, 255, 255, 0.96)); linear-gradient(180deg, rgba(244, 248, 252, 0.92), rgba(255, 255, 255, 0.96));
@ -335,6 +355,15 @@ a:hover {
opacity: 0.85; opacity: 0.85;
} }
.feature-card .button-link,
.section-card .button-link {
min-height: 38px;
margin-top: 0.45rem;
padding: 0.55rem 0.78rem;
border-radius: 8px;
font-size: 0.88rem;
}
.lead-panel .feature-card:nth-child(4n + 1), .lead-panel .feature-card:nth-child(4n + 1),
.direction-panel .feature-card:nth-child(3n + 1), .direction-panel .feature-card:nth-child(3n + 1),
.section-card:nth-child(4n + 1) { .section-card:nth-child(4n + 1) {
@ -525,11 +554,13 @@ a:hover {
} }
.notebook-panel { .notebook-panel {
border: 1px solid var(--line); border: 1px solid rgba(22, 54, 89, 0.14);
border-radius: 8px; border-left: 5px solid var(--blue);
border-radius: 12px;
padding: 1.25rem; padding: 1.25rem;
margin: 1rem 0 1.5rem; margin: 1rem 0 1.5rem;
background: rgba(255, 255, 255, 0.84); background:
linear-gradient(180deg, rgba(244, 248, 252, 0.9), rgba(255, 255, 255, 0.86));
} }
.notebook-panel h2, .notebook-panel h2,
@ -556,6 +587,24 @@ a:hover {
margin-top: 0.5rem; margin-top: 0.5rem;
} }
.roadmap-list,
.bibliography-list {
margin: 0;
padding-left: 1.2rem;
}
.roadmap-list li + li,
.bibliography-list li + li {
margin-top: 0.9rem;
}
.roadmap-list p {
max-width: 72ch;
margin: 0.35rem 0 0;
color: var(--muted);
line-height: 1.6;
}
a:focus-visible, a:focus-visible,
button:focus-visible { button:focus-visible {
outline: 3px solid #e5b748; outline: 3px solid #e5b748;