{% raw %} # Consistency rules These are hard, structural rules, not suggestions. They are derived from the **posts / feed page**, the reference implementation and the most structurally and visually correct page in the application. Other pages are refactored to match it; new pages follow these rules from the start. The header, breadcrumb, content root, and footer are *shared infrastructure*. A page supplies its content and its stylesheet; it never rebuilds the frame. ## The reference skeleton This is the posts page reduced to its structure. A content page looks like this and nothing else: ```html {% extends "base.html" %} {% block extra_head %} <link rel="stylesheet" href="{{ static_url('/static/css/feed.css') }}"> {% endblock %} {% block content %} <h1 class="sr-only">Feed</h1> <div class="feed-layout"> {# exactly one layout container #} <aside class="sidebar-card"> ... </aside> <div class="feed-main"> ... </div> <aside class="feed-right"> ... </aside> </div> {% endblock %} ``` The header, breadcrumb, `
` wrapper, and footer are all supplied by `base.html`. The template above never appears to contain them, and never should. ## Hard rules ### 1. Extend the base template Every page is `{% extends "base.html" %}`. Page CSS is added only through `{% block extra_head %}`; page JS only through `{% block extra_js %}`. A page never includes its own ``, ``, or ``, and never links `variables.css` / `base.css` / `components.css` (the base already does). ### 2. The header is shared, never re-implemented The top nav is `base.html`'s `.topnav`. Pages do not build their own header or navigation bar; the active link is derived from the request path inside `base.html`. A page-level toolbar (tabs, filters) lives *inside the content*, like the feed's `.feed-nav` strip, below the breadcrumb, never as a second site header. ### 3. Breadcrumbs are mandatory (this is the most-broken rule) A page **must** pass at least two breadcrumbs (Home plus the current page) through its SEO context: ```python seo_ctx = list_page_seo( request, title="Projects", breadcrumbs=[{"name": "Home", "url": "/feed"}, {"name": "Projects", "url": "/projects"}], ) ``` This is primarily for SEO and orientation. Clearing the fixed top nav is handled once, globally, by `body { padding-top: var(--nav-height) }`, so a page is never hidden behind the header whether or not it has a breadcrumb. Still supply two or more crumbs on any nested page for navigation and breadcrumb structured data. ### 4. All content lives in the single content root `base.html` already wraps the `content` block in `
` (`max-width: 1200px`, centred, `padding: 1rem`). Therefore a page: - puts everything inside one top-level layout container (a grid like `.feed-layout`, or a single column); - never adds a second centred / `max-width` wrapper inside `.page`; - never re-declares the maximum content width. See [Layout](/docs/styles-layout.html) for the approved layout containers. ### 5. Multi-column structure is grid, and it collapses Side columns are `
Anatomy of a page (what base.html owns vs what the page supplies)
DevPlace · Home Posts News Gists Projectsbase.html: .topnav (fixed)
Home / Projectsbase.html: .breadcrumb (clears the nav)
Your content, inside one layout container.page: block content, inside .page
DevPlace · footer linksbase.html: .site-footer