From 9203b44b756dc2d054664a99a2fcbe18a5f8961f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Mon, 31 Aug 2026 00:12:41 +0200 Subject: [PATCH 1/3] Fix show-on-scroll header and social links --- AGENTS.md | 4 ++-- dist/truechristian-theme.css | 12 +++++++++++ dist/truechristian-theme.js | 34 ++++++++++++++++++++++++++++++++ dist/truechristian-theme.min.css | 2 +- docs/component-inventory.md | 2 +- docs/footer.md | 6 +++--- docs/header.md | 4 +++- examples/style-guide.html | 2 +- scripts/validate.mjs | 11 +++++++++++ src/css/header.css | 12 +++++++++++ src/data/site-chrome.json | 2 -- src/html/site-footer.html | 6 ------ src/js/site-header.js | 34 ++++++++++++++++++++++++++++++++ 13 files changed, 114 insertions(+), 17 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5812924..242629d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -46,7 +46,7 @@ Every site MUST include a responsive header with the following behavior: - Navigation entries belonging to the site or page being built MUST follow `Home` and use the same visual treatment. - On the main church site, the canonical entries are `The Holy Scriptures`, `Sermons`, `Articles`, `Daily`, and `Services` with the `Join us` subtitle. Preserve the full extracted menu data in `src/data/main-site-navigation.json`. - Desktop navigation MUST use the white bar, thin cyan top rule, uppercase widely spaced labels, and active/hover contrast shown in the reference screenshot. -- The desktop header SHOULD be sticky and reveal on upward scroll when the host framework supports it. +- The header MUST remain visible at the top of the page, hide when the visitor scrolls downward, and reveal again when the visitor scrolls upward. Portable implementations MUST provide this behavior through `dist/truechristian-theme.js` or an equivalent implementation. - Below the desktop breakpoint, use a menu toggle and off-canvas or equivalent accessible navigation. Keep the logo centered and never squeeze the complete desktop menu into a narrow row. - Dropdown triggers MUST be keyboard operable and expose `aria-expanded`; the mobile menu MUST have an accessible close control. - Portable implementations MUST load `dist/truechristian-theme.js` (built from `src/js/site-header.js`) or provide equivalent menu, submenu, Escape-key, focus, and breakpoint behavior. @@ -70,7 +70,7 @@ This terminology prevents the YOOtheme region name `tm-bottom` from being confus - Use four desktop columns in this exact order: `Church Info`, `Projects`, `Welcome`, `Social Outreach`. - Use the exact labels, URLs, order, and external-link behavior in `src/data/site-chrome.json`. - The data preserves the source's root-relative URLs. On a different domain, resolve every root-relative global-footer URL against `https://truechristian.church`; the portable HTML template already does this. -- `Social Outreach` MUST contain X/Twitter, Facebook, GitHub, and Telegram icon links. +- `Social Outreach` MUST contain only GitHub and Telegram icon links, in that order. - The source skyline file is `/images/city-skyline-skyscrapers-top.jpg`. It was not supplied separately; `assets/footer/city-skyline-reference.png` is an exact-size reference crop from the owner-supplied screenshot. Preserve its `270px × 180px` slot and do not substitute unrelated stock imagery. - On medium layouts, the four columns MAY become a two-by-two grid. On narrow layouts, stack them and center headings, links, and social controls. - Keep the generous light-grey spacing, uppercase headings and links, circular social buttons, rounded image treatment, and subdued shadow shown in `docs/reference/footer-desktop.png`. diff --git a/dist/truechristian-theme.css b/dist/truechristian-theme.css index 55afc94..3654aec 100644 --- a/dist/truechristian-theme.css +++ b/dist/truechristian-theme.css @@ -126,6 +126,18 @@ p { position: sticky; z-index: 1000; top: 0; + transform: translateY(0); + transition: transform 220ms ease; + will-change: transform; +} + +.tcc-site-header[data-scroll-hidden="true"] { + transform: translateY(calc(-100% - 1px)); +} + +.tcc-site-header[data-menu-open="true"], +.tcc-site-header:focus-within { + transform: translateY(0); } .tcc-header__container { diff --git a/dist/truechristian-theme.js b/dist/truechristian-theme.js index acc5fe8..5a30540 100644 --- a/dist/truechristian-theme.js +++ b/dist/truechristian-theme.js @@ -16,6 +16,10 @@ const scrim = header.querySelector(".tcc-header__scrim"); const submenuButtons = header.querySelectorAll(".has-submenu > button"); let returnFocusTo = null; + let lastScrollY = Math.max(0, window.scrollY); + let directionStartY = lastScrollY; + let scrollDirection = 0; + let scrollFrame = null; if (!toggle || !navigation || !closeButton || !scrim) return; @@ -30,6 +34,7 @@ const setMenuOpen = (open, restoreFocus = true) => { const nextOpen = Boolean(open && mobileQuery.matches); header.dataset.menuOpen = String(nextOpen); + if (nextOpen) header.removeAttribute("data-scroll-hidden"); toggle.setAttribute("aria-expanded", String(nextOpen)); navigation.toggleAttribute("inert", mobileQuery.matches && !nextOpen); if (mobileQuery.matches) navigation.setAttribute("aria-hidden", String(!nextOpen)); @@ -100,6 +105,35 @@ if (!header.contains(event.target)) collapseSubmenus(); }); + header.addEventListener("focusin", () => header.removeAttribute("data-scroll-hidden")); + + const updateScrollState = () => { + scrollFrame = null; + const currentY = Math.max(0, window.scrollY); + const delta = currentY - lastScrollY; + const nextDirection = delta > 0 ? 1 : delta < 0 ? -1 : scrollDirection; + + if (nextDirection !== scrollDirection) { + scrollDirection = nextDirection; + directionStartY = lastScrollY; + } + + const distanceInDirection = Math.abs(currentY - directionStartY); + if (currentY <= 4 || header.dataset.menuOpen === "true") { + header.removeAttribute("data-scroll-hidden"); + } else if (nextDirection === 1 && currentY > header.offsetHeight && distanceInDirection >= 12) { + header.dataset.scrollHidden = "true"; + } else if (nextDirection === -1 && distanceInDirection >= 8) { + header.removeAttribute("data-scroll-hidden"); + } + + lastScrollY = currentY; + }; + + window.addEventListener("scroll", () => { + if (scrollFrame === null) scrollFrame = window.requestAnimationFrame(updateScrollState); + }, { passive: true }); + const syncBreakpoint = () => setMenuOpen(false, false); if (mobileQuery.addEventListener) mobileQuery.addEventListener("change", syncBreakpoint); else mobileQuery.addListener?.(syncBreakpoint); diff --git a/dist/truechristian-theme.min.css b/dist/truechristian-theme.min.css index 4e5e57f..99ef7a7 100644 --- a/dist/truechristian-theme.min.css +++ b/dist/truechristian-theme.min.css @@ -1 +1 @@ -:root{--tcc-color-white:#ffffff;--tcc-color-cyan:#00cadb;--tcc-color-directory:#f7f7f7;--tcc-color-charcoal:#303033;--tcc-color-ink:#2d2e33;--tcc-color-nav-muted:#b4b5ba;--tcc-color-footer-text:rgb(255 255 255 / 70%);--tcc-color-social-icon:#6c6d74;--tcc-color-border:#e5e5e7;--tcc-font-body:"Raleway","Helvetica Neue",Arial,sans-serif;--tcc-font-display:"Montserrat",Arial,sans-serif;--tcc-container-max:1200px;--tcc-space-1:0.5rem;--tcc-space-2:1rem;--tcc-space-3:1.5rem;--tcc-space-4:2rem;--tcc-space-5:3rem;--tcc-space-6:4rem;--tcc-space-7:4.375rem;--tcc-radius-small:5px;--tcc-radius-round:999px;--tcc-shadow-medium:0 5px 15px rgb(0 0 0 / 8%);--tcc-focus-ring:0 0 0 4px rgb(0 202 219 / 35%);--tcc-breakpoint-small:640px;--tcc-breakpoint-medium:960px;} *,*::before,*::after{box-sizing:border-box;} html{color:var(--tcc-color-ink);font-family:var(--tcc-font-body);line-height:1.7;text-rendering:optimizeLegibility;} body{margin:0;background:var(--tcc-color-white);color:var(--tcc-color-ink);} img{display:block;max-width:100%;height:auto;} a{color:inherit;text-decoration-thickness:0.08em;text-underline-offset:0.18em;} a:focus-visible,button:focus-visible{outline:2px solid var(--tcc-color-ink);outline-offset:4px;box-shadow:var(--tcc-focus-ring);} button,input,select,textarea{font:inherit;} .tcc-container{width:min(calc(100% - 3rem),var(--tcc-container-max));margin-inline:auto;} @media (max-width:639px){.tcc-container{width:min(calc(100% - 2rem),var(--tcc-container-max));}} h1,h2,h3,h4,h5,h6{margin-block:0 0.75em;color:var(--tcc-color-ink);font-family:var(--tcc-font-display);font-weight:400;line-height:1.25;} p{margin-block:0 1.25em;} .tcc-eyebrow{font-family:var(--tcc-font-display);font-size:0.8125rem;letter-spacing:0.22em;text-transform:uppercase;} .tcc-site-header,.tm-header .uk-navbar-container,.tm-header-mobile .uk-navbar-container{border-top:1px solid var(--tcc-color-cyan);background:var(--tcc-color-white);} .tcc-site-header{position:sticky;z-index:1000;top:0;} .tcc-header__container{display:flex;min-height:80px;align-items:center;justify-content:space-between;gap:var(--tcc-space-2);} .tcc-header__brand{display:inline-flex;flex:0 0 auto;align-items:center;} .tcc-header__brand img,.tm-header .uk-logo img,.tm-header-mobile .uk-logo img{width:288px;height:77px;object-fit:contain;} .tm-header .uk-navbar-container>.uk-container{max-width:var(--tcc-container-max);} .tcc-header__menu,.tcc-header__menu ul{margin:0;padding:0;list-style:none;} .tcc-header__menu{display:flex;align-items:center;gap:0;} .tcc-header__menu>li{position:relative;} .tcc-header__menu>li>a,.tcc-header__menu>li>button,.tm-header .uk-navbar-nav>li>a{display:inline-flex;min-height:44px;align-items:center;border:0;padding-inline:15px;background:transparent;color:var(--tcc-color-nav-muted);cursor:pointer;font-family:var(--tcc-font-display);font-size:0.6875rem;font-weight:400;letter-spacing:2px;text-decoration:none;text-transform:uppercase;white-space:nowrap;} .tcc-header__menu>li:last-child>a{padding-right:0;} .tcc-header__menu>li>a:hover,.tcc-header__menu>li>button:hover,.tcc-header__menu>li>a:focus-visible,.tcc-header__menu>li>button:focus-visible,.tcc-header__menu>.is-active>a,.tm-header .uk-navbar-nav>.uk-active>a,.tm-header .uk-navbar-nav>li>a:hover{color:var(--tcc-color-ink);} .tcc-header__menu ul{position:absolute;top:100%;left:0;display:none;min-width:220px;padding:var(--tcc-space-2);border:1px solid var(--tcc-color-border);background:var(--tcc-color-white);box-shadow:var(--tcc-shadow-medium);} .tcc-header__menu ul a{display:block;padding:0.35rem 0.5rem;color:var(--tcc-color-ink);font-size:0.875rem;text-decoration:none;} .tcc-header__services>a{gap:0.7rem;} .tcc-header__services small{display:block;margin-top:0.15rem;font-family:var(--tcc-font-display);font-size:0.75rem;letter-spacing:0.0125rem;text-transform:none;} .tcc-header__services-icon{width:20px;height:20px;flex:0 0 20px;letter-spacing:0;} .tcc-icon{display:block;width:20px;height:20px;fill:currentcolor;} .tcc-icon--stroke{fill:none;stroke:currentcolor;} .tcc-header__toggle{display:none;min-width:44px;min-height:44px;border:0;background:transparent;color:var(--tcc-color-charcoal);font-size:1.5rem;} .tcc-header__close,.tcc-header__scrim{display:none;} @media (max-width:959px){html.tcc-menu-open{overflow:hidden;} .tcc-header__container{min-height:80px;justify-content:center;} .tcc-header__brand img{width:min(240px,66vw);height:auto;} .tcc-header__toggle{position:absolute;left:1rem;display:inline-grid;place-items:center;} .tcc-header__navigation{position:fixed;z-index:1001;inset:0 auto 0 0;width:min(88vw,360px);padding:6rem 2rem 2rem;overflow-y:auto;background:var(--tcc-color-white);box-shadow:var(--tcc-shadow-medium);visibility:hidden;pointer-events:none;transform:translateX(-105%);transition:transform 180ms ease,visibility 0s linear 180ms;} .tcc-site-header[data-menu-open="true"] .tcc-header__navigation{visibility:visible;pointer-events:auto;transform:translateX(0);transition-delay:0s;} .tcc-header__close{position:absolute;top:1rem;right:1rem;display:inline-grid;width:44px;height:44px;place-items:center;border:0;background:transparent;color:var(--tcc-color-ink);font-size:1.75rem;line-height:1;} .tcc-header__scrim{position:fixed;z-index:1000;inset:0;display:block;border:0;padding:0;background:rgb(45 46 51 / 45%);opacity:0;visibility:hidden;pointer-events:none;transition:opacity 180ms ease,visibility 0s linear 180ms;} .tcc-site-header[data-menu-open="true"] .tcc-header__scrim{opacity:1;visibility:visible;pointer-events:auto;transition-delay:0s;} .tcc-header__menu{display:grid;align-items:stretch;gap:0.4rem;} .tcc-header__menu>li>a,.tcc-header__menu>li>button{width:100%;justify-content:flex-start;padding-inline:0;white-space:normal;} .tcc-header__menu ul{position:static;display:none;border:0;padding:0 0 0 var(--tcc-space-2);box-shadow:none;} .tcc-header__menu li[data-submenu-open="true"]>ul{display:grid;gap:0.4rem;}} @media (min-width:960px){.tm-header .uk-navbar,.tm-header .uk-navbar-item,.tm-header .uk-navbar-nav>li>a{min-height:80px;} .tcc-header__menu>li.has-submenu:hover>ul,.tcc-header__menu>li[data-submenu-open="true"]>ul{display:grid;gap:0.4rem;}} .tcc-footer-directory,.tm-bottom.uk-section-muted{background:var(--tcc-color-directory);color:var(--tcc-color-ink);} .tcc-footer-directory,.tm-bottom.uk-section-muted{padding-block:var(--tcc-space-7);} .tm-bottom>.uk-container,.tm-page>footer .uk-container{max-width:var(--tcc-container-max);} .tcc-footer-directory__grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:40px;} .tcc-footer-group h2,.tm-bottom .uk-h5{margin:0 0 20px;color:var(--tcc-color-ink);font-family:var(--tcc-font-display);font-size:1rem;font-weight:400;letter-spacing:2px;line-height:1.4;text-transform:uppercase;} .tcc-footer-group ul{margin:0;padding:0;list-style:none;} .tcc-footer-group li + li{margin-top:10px;} .tcc-footer-group li a,.tm-bottom .uk-h6,.tm-bottom .uk-h6 a{color:var(--tcc-color-ink);font-family:var(--tcc-font-display);font-size:0.6875rem;font-weight:400;letter-spacing:2px;line-height:1.4;text-decoration:none;text-transform:uppercase;} .tcc-footer-group li a:hover,.tcc-footer-group li a:focus-visible,.tm-bottom .uk-h6 a:hover{text-decoration:underline;} .tcc-footer-social__links{display:flex;flex-wrap:wrap;gap:20px;margin-top:20px;} .tcc-footer-social__links a,.tm-bottom .uk-icon-button{display:inline-grid;width:36px;height:36px;place-items:center;border:1px solid var(--tcc-color-border);border-radius:var(--tcc-radius-round);background:var(--tcc-color-white);color:var(--tcc-color-social-icon);font-family:var(--tcc-font-display);font-size:0.875rem;font-weight:600;text-decoration:none;} .tcc-footer-social img,.tm-bottom .uk-border-rounded{width:270px;height:180px;margin-top:20px;border-radius:var(--tcc-radius-small);box-shadow:var(--tcc-shadow-medium);object-fit:cover;} .tcc-footer-copyright,.tm-page>footer .uk-section-primary{background:var(--tcc-color-charcoal);color:var(--tcc-color-footer-text);} .tcc-footer-copyright,.tm-page>footer .uk-section-primary{padding-block:var(--tcc-space-7);font-family:var(--tcc-font-body);font-size:1rem;font-weight:400;line-height:1.6;} .tcc-footer-copyright a,.tm-page>footer #license a{color:var(--tcc-color-white);text-decoration:none;} .tcc-footer-copyright a:hover,.tcc-footer-copyright a:focus-visible,.tm-page>footer #license a:hover{color:var(--tcc-color-white);text-decoration:underline;} .tcc-footer-copyright a:focus-visible,.tm-page>footer #license a:focus-visible{outline-color:var(--tcc-color-white);} @media (max-width:959px){.tcc-footer-directory__grid{grid-template-columns:repeat(2,minmax(0,1fr));} .tcc-footer-copyright{padding-block:var(--tcc-space-5);font-size:1rem;} .tm-page>footer .uk-section-primary{padding-block:var(--tcc-space-5);} .tcc-footer-social img{display:none;}} @media (max-width:639px){.tcc-footer-directory,.tm-bottom.uk-section-muted{padding-block:var(--tcc-space-5);} .tcc-footer-directory__grid{grid-template-columns:1fr;gap:var(--tcc-space-4);text-align:center;} .tcc-footer-social__links{justify-content:center;} .tcc-footer-copyright{text-align:center;}} .tcc-visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;white-space:nowrap !important;border:0 !important;} @media (prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto !important;transition-duration:0.01ms !important;animation-duration:0.01ms !important;animation-iteration-count:1 !important;}} @media print{.tcc-site-header{position:static;} .tcc-header__toggle,.tcc-footer-social{display:none !important;} .tcc-footer-directory,.tcc-footer-copyright{padding-block:1.5rem;background:#fff !important;color:#000 !important;}} +:root{--tcc-color-white:#ffffff;--tcc-color-cyan:#00cadb;--tcc-color-directory:#f7f7f7;--tcc-color-charcoal:#303033;--tcc-color-ink:#2d2e33;--tcc-color-nav-muted:#b4b5ba;--tcc-color-footer-text:rgb(255 255 255 / 70%);--tcc-color-social-icon:#6c6d74;--tcc-color-border:#e5e5e7;--tcc-font-body:"Raleway","Helvetica Neue",Arial,sans-serif;--tcc-font-display:"Montserrat",Arial,sans-serif;--tcc-container-max:1200px;--tcc-space-1:0.5rem;--tcc-space-2:1rem;--tcc-space-3:1.5rem;--tcc-space-4:2rem;--tcc-space-5:3rem;--tcc-space-6:4rem;--tcc-space-7:4.375rem;--tcc-radius-small:5px;--tcc-radius-round:999px;--tcc-shadow-medium:0 5px 15px rgb(0 0 0 / 8%);--tcc-focus-ring:0 0 0 4px rgb(0 202 219 / 35%);--tcc-breakpoint-small:640px;--tcc-breakpoint-medium:960px;} *,*::before,*::after{box-sizing:border-box;} html{color:var(--tcc-color-ink);font-family:var(--tcc-font-body);line-height:1.7;text-rendering:optimizeLegibility;} body{margin:0;background:var(--tcc-color-white);color:var(--tcc-color-ink);} img{display:block;max-width:100%;height:auto;} a{color:inherit;text-decoration-thickness:0.08em;text-underline-offset:0.18em;} a:focus-visible,button:focus-visible{outline:2px solid var(--tcc-color-ink);outline-offset:4px;box-shadow:var(--tcc-focus-ring);} button,input,select,textarea{font:inherit;} .tcc-container{width:min(calc(100% - 3rem),var(--tcc-container-max));margin-inline:auto;} @media (max-width:639px){.tcc-container{width:min(calc(100% - 2rem),var(--tcc-container-max));}} h1,h2,h3,h4,h5,h6{margin-block:0 0.75em;color:var(--tcc-color-ink);font-family:var(--tcc-font-display);font-weight:400;line-height:1.25;} p{margin-block:0 1.25em;} .tcc-eyebrow{font-family:var(--tcc-font-display);font-size:0.8125rem;letter-spacing:0.22em;text-transform:uppercase;} .tcc-site-header,.tm-header .uk-navbar-container,.tm-header-mobile .uk-navbar-container{border-top:1px solid var(--tcc-color-cyan);background:var(--tcc-color-white);} .tcc-site-header{position:sticky;z-index:1000;top:0;transform:translateY(0);transition:transform 220ms ease;will-change:transform;} .tcc-site-header[data-scroll-hidden="true"]{transform:translateY(calc(-100% - 1px));} .tcc-site-header[data-menu-open="true"],.tcc-site-header:focus-within{transform:translateY(0);} .tcc-header__container{display:flex;min-height:80px;align-items:center;justify-content:space-between;gap:var(--tcc-space-2);} .tcc-header__brand{display:inline-flex;flex:0 0 auto;align-items:center;} .tcc-header__brand img,.tm-header .uk-logo img,.tm-header-mobile .uk-logo img{width:288px;height:77px;object-fit:contain;} .tm-header .uk-navbar-container>.uk-container{max-width:var(--tcc-container-max);} .tcc-header__menu,.tcc-header__menu ul{margin:0;padding:0;list-style:none;} .tcc-header__menu{display:flex;align-items:center;gap:0;} .tcc-header__menu>li{position:relative;} .tcc-header__menu>li>a,.tcc-header__menu>li>button,.tm-header .uk-navbar-nav>li>a{display:inline-flex;min-height:44px;align-items:center;border:0;padding-inline:15px;background:transparent;color:var(--tcc-color-nav-muted);cursor:pointer;font-family:var(--tcc-font-display);font-size:0.6875rem;font-weight:400;letter-spacing:2px;text-decoration:none;text-transform:uppercase;white-space:nowrap;} .tcc-header__menu>li:last-child>a{padding-right:0;} .tcc-header__menu>li>a:hover,.tcc-header__menu>li>button:hover,.tcc-header__menu>li>a:focus-visible,.tcc-header__menu>li>button:focus-visible,.tcc-header__menu>.is-active>a,.tm-header .uk-navbar-nav>.uk-active>a,.tm-header .uk-navbar-nav>li>a:hover{color:var(--tcc-color-ink);} .tcc-header__menu ul{position:absolute;top:100%;left:0;display:none;min-width:220px;padding:var(--tcc-space-2);border:1px solid var(--tcc-color-border);background:var(--tcc-color-white);box-shadow:var(--tcc-shadow-medium);} .tcc-header__menu ul a{display:block;padding:0.35rem 0.5rem;color:var(--tcc-color-ink);font-size:0.875rem;text-decoration:none;} .tcc-header__services>a{gap:0.7rem;} .tcc-header__services small{display:block;margin-top:0.15rem;font-family:var(--tcc-font-display);font-size:0.75rem;letter-spacing:0.0125rem;text-transform:none;} .tcc-header__services-icon{width:20px;height:20px;flex:0 0 20px;letter-spacing:0;} .tcc-icon{display:block;width:20px;height:20px;fill:currentcolor;} .tcc-icon--stroke{fill:none;stroke:currentcolor;} .tcc-header__toggle{display:none;min-width:44px;min-height:44px;border:0;background:transparent;color:var(--tcc-color-charcoal);font-size:1.5rem;} .tcc-header__close,.tcc-header__scrim{display:none;} @media (max-width:959px){html.tcc-menu-open{overflow:hidden;} .tcc-header__container{min-height:80px;justify-content:center;} .tcc-header__brand img{width:min(240px,66vw);height:auto;} .tcc-header__toggle{position:absolute;left:1rem;display:inline-grid;place-items:center;} .tcc-header__navigation{position:fixed;z-index:1001;inset:0 auto 0 0;width:min(88vw,360px);padding:6rem 2rem 2rem;overflow-y:auto;background:var(--tcc-color-white);box-shadow:var(--tcc-shadow-medium);visibility:hidden;pointer-events:none;transform:translateX(-105%);transition:transform 180ms ease,visibility 0s linear 180ms;} .tcc-site-header[data-menu-open="true"] .tcc-header__navigation{visibility:visible;pointer-events:auto;transform:translateX(0);transition-delay:0s;} .tcc-header__close{position:absolute;top:1rem;right:1rem;display:inline-grid;width:44px;height:44px;place-items:center;border:0;background:transparent;color:var(--tcc-color-ink);font-size:1.75rem;line-height:1;} .tcc-header__scrim{position:fixed;z-index:1000;inset:0;display:block;border:0;padding:0;background:rgb(45 46 51 / 45%);opacity:0;visibility:hidden;pointer-events:none;transition:opacity 180ms ease,visibility 0s linear 180ms;} .tcc-site-header[data-menu-open="true"] .tcc-header__scrim{opacity:1;visibility:visible;pointer-events:auto;transition-delay:0s;} .tcc-header__menu{display:grid;align-items:stretch;gap:0.4rem;} .tcc-header__menu>li>a,.tcc-header__menu>li>button{width:100%;justify-content:flex-start;padding-inline:0;white-space:normal;} .tcc-header__menu ul{position:static;display:none;border:0;padding:0 0 0 var(--tcc-space-2);box-shadow:none;} .tcc-header__menu li[data-submenu-open="true"]>ul{display:grid;gap:0.4rem;}} @media (min-width:960px){.tm-header .uk-navbar,.tm-header .uk-navbar-item,.tm-header .uk-navbar-nav>li>a{min-height:80px;} .tcc-header__menu>li.has-submenu:hover>ul,.tcc-header__menu>li[data-submenu-open="true"]>ul{display:grid;gap:0.4rem;}} .tcc-footer-directory,.tm-bottom.uk-section-muted{background:var(--tcc-color-directory);color:var(--tcc-color-ink);} .tcc-footer-directory,.tm-bottom.uk-section-muted{padding-block:var(--tcc-space-7);} .tm-bottom>.uk-container,.tm-page>footer .uk-container{max-width:var(--tcc-container-max);} .tcc-footer-directory__grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:40px;} .tcc-footer-group h2,.tm-bottom .uk-h5{margin:0 0 20px;color:var(--tcc-color-ink);font-family:var(--tcc-font-display);font-size:1rem;font-weight:400;letter-spacing:2px;line-height:1.4;text-transform:uppercase;} .tcc-footer-group ul{margin:0;padding:0;list-style:none;} .tcc-footer-group li + li{margin-top:10px;} .tcc-footer-group li a,.tm-bottom .uk-h6,.tm-bottom .uk-h6 a{color:var(--tcc-color-ink);font-family:var(--tcc-font-display);font-size:0.6875rem;font-weight:400;letter-spacing:2px;line-height:1.4;text-decoration:none;text-transform:uppercase;} .tcc-footer-group li a:hover,.tcc-footer-group li a:focus-visible,.tm-bottom .uk-h6 a:hover{text-decoration:underline;} .tcc-footer-social__links{display:flex;flex-wrap:wrap;gap:20px;margin-top:20px;} .tcc-footer-social__links a,.tm-bottom .uk-icon-button{display:inline-grid;width:36px;height:36px;place-items:center;border:1px solid var(--tcc-color-border);border-radius:var(--tcc-radius-round);background:var(--tcc-color-white);color:var(--tcc-color-social-icon);font-family:var(--tcc-font-display);font-size:0.875rem;font-weight:600;text-decoration:none;} .tcc-footer-social img,.tm-bottom .uk-border-rounded{width:270px;height:180px;margin-top:20px;border-radius:var(--tcc-radius-small);box-shadow:var(--tcc-shadow-medium);object-fit:cover;} .tcc-footer-copyright,.tm-page>footer .uk-section-primary{background:var(--tcc-color-charcoal);color:var(--tcc-color-footer-text);} .tcc-footer-copyright,.tm-page>footer .uk-section-primary{padding-block:var(--tcc-space-7);font-family:var(--tcc-font-body);font-size:1rem;font-weight:400;line-height:1.6;} .tcc-footer-copyright a,.tm-page>footer #license a{color:var(--tcc-color-white);text-decoration:none;} .tcc-footer-copyright a:hover,.tcc-footer-copyright a:focus-visible,.tm-page>footer #license a:hover{color:var(--tcc-color-white);text-decoration:underline;} .tcc-footer-copyright a:focus-visible,.tm-page>footer #license a:focus-visible{outline-color:var(--tcc-color-white);} @media (max-width:959px){.tcc-footer-directory__grid{grid-template-columns:repeat(2,minmax(0,1fr));} .tcc-footer-copyright{padding-block:var(--tcc-space-5);font-size:1rem;} .tm-page>footer .uk-section-primary{padding-block:var(--tcc-space-5);} .tcc-footer-social img{display:none;}} @media (max-width:639px){.tcc-footer-directory,.tm-bottom.uk-section-muted{padding-block:var(--tcc-space-5);} .tcc-footer-directory__grid{grid-template-columns:1fr;gap:var(--tcc-space-4);text-align:center;} .tcc-footer-social__links{justify-content:center;} .tcc-footer-copyright{text-align:center;}} .tcc-visually-hidden{position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;white-space:nowrap !important;border:0 !important;} @media (prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto !important;transition-duration:0.01ms !important;animation-duration:0.01ms !important;animation-iteration-count:1 !important;}} @media print{.tcc-site-header{position:static;} .tcc-header__toggle,.tcc-footer-social{display:none !important;} .tcc-footer-directory,.tcc-footer-copyright{padding-block:1.5rem;background:#fff !important;color:#000 !important;}} diff --git a/docs/component-inventory.md b/docs/component-inventory.md index 4825059..986c0da 100644 --- a/docs/component-inventory.md +++ b/docs/component-inventory.md @@ -17,7 +17,7 @@ The compiled contents of `theme.13.css` were not included in the supplied HTML. | Area | Source roles/classes | Meaning for implementations | | --- | --- | --- | | Page shell | `tm-page`, `tm-main`, `uk-container`, `uk-container-expand` | Full-width bands with centered content containers | -| Header | `tm-header`, `tm-header-mobile`, `uk-navbar*`, `uk-logo`, `uk-sticky` | Desktop sticky navbar plus mobile replacement | +| Header | `tm-header`, `tm-header-mobile`, `uk-navbar*`, `uk-logo`, `uk-sticky` | Sticky navbar that hides on downward scroll and reveals on upward scroll, plus mobile replacement | | Navigation | `uk-nav*`, `uk-navbar-dropdown`, `uk-drop`, `uk-offcanvas`, `uk-nav-accordion` | Dropdown/mega-menu and accessible mobile drawer behavior | | Sections | `uk-section-default`, `uk-section-primary`, `uk-section-muted`, `uk-section-large`, `uk-section-xlarge` | Semantic surface and spacing variants | | Layout | `uk-grid*`, `uk-width-*`, `uk-flex*`, `uk-tile*` | Responsive grids, widths, alignment, and matched tiles | diff --git a/docs/footer.md b/docs/footer.md index d0c7a89..89b99be 100644 --- a/docs/footer.md +++ b/docs/footer.md @@ -20,7 +20,7 @@ Together they form the required bottom footer assembly. They must remain adjacen | Directory grid | Four equal `270px` tracks with `40px` gaps | | Group heading | Montserrat 400, `16px/1.4`, uppercase, `2px` tracking, `20px` bottom gap | | Group link | Montserrat 400, `11px/1.4`, uppercase, `2px` tracking, `10px` sibling gap, `#2d2e33` | -| Social controls | Four `36px` white circles, `20px` gaps, `#6c6d74` glyphs, `#e5e5e7` edge | +| Social controls | Two `36px` white circles, `20px` gaps, `#6c6d74` glyphs, `#e5e5e7` edge | | Skyline slot | Desktop only, `270 × 180px`, `20px` top gap, `5px` radius, subdued shadow | | Copyright surface | `#303033`, `70px` block padding | | Copyright line | Raleway 400, `16px/1.6`; prefix and pipes 70%-white, links white | @@ -67,11 +67,11 @@ This is a church-wide link directory. The presence of a project link does not ma ### Social Outreach -- X/Twitter -- Facebook - GitHub - Telegram +The historical source evidence includes X/Twitter and Facebook. The repository owner's current instruction supersedes that older footer content, so GitHub and Telegram are the canonical Social Outreach links. + The source also shows `/images/city-skyline-skyscrapers-top.jpg` beneath the social links on desktop. Its CSS slot is `270px × 180px`, with a `5px` radius, `20px` top margin, and subdued shadow; it is hidden below `960px`. The original image file was not supplied. `assets/footer/city-skyline-reference.png` is a correctly sized crop from the supplied footer screenshot, retained as an explicit reference/fallback rather than invented stock imagery. ## Copyright footer diff --git a/docs/header.md b/docs/header.md index 2678969..3613351 100644 --- a/docs/header.md +++ b/docs/header.md @@ -36,6 +36,8 @@ The screenshot is a 1.25× capture; its device-pixel geometry is larger than the The supplied screenshot is the home page, so `Home` is active there. The reusable fragment intentionally has no hardcoded current item; the consuming page must add `aria-current="page"` and `.is-active` to its actual route. +The header is visible when the page is at the top. Once the visitor scrolls down past the header, it slides out of view; scrolling upward reveals it again. Keep it visible while the mobile menu is open or keyboard focus is inside the header. The portable script applies small direction thresholds so minor trackpad or touch movement does not make the bar flicker. + ## Canonical main-site order 1. Home @@ -53,7 +55,7 @@ The canonical main-site mega-menu is not a generic requirement for every satelli The source uses `tm-header-mobile uk-hidden@m`, a left menu toggle, centered logo, and a slide-mode off-canvas menu. Nested entries become an accordion. Implementations on other frameworks must preserve this behavior even when class names differ. -The portable template uses `src/js/site-header.js` for open/close state, submenu state, Escape, focus containment, inert off-screen navigation, and breakpoint synchronization. Load the built script with `defer`. +The portable template uses `src/js/site-header.js` for scroll-direction visibility, open/close state, submenu state, Escape, focus containment, inert off-screen navigation, and breakpoint synchronization. Load the built script with `defer`. ## Reusable markup diff --git a/examples/style-guide.html b/examples/style-guide.html index 46b1167..a59570b 100644 --- a/examples/style-guide.html +++ b/examples/style-guide.html @@ -46,7 +46,7 @@

A True Christian Church

- + diff --git a/scripts/validate.mjs b/scripts/validate.mjs index c491331..14e08b9 100644 --- a/scripts/validate.mjs +++ b/scripts/validate.mjs @@ -53,6 +53,8 @@ const mainNavigation = JSON.parse(await readFile(path.join(root, "src/data/main- const groupLabels = chrome.footer.directoryGroups.map((group) => group.label); if (groupLabels.join("|") !== "Church Info|Projects|Welcome") throw new Error("Directory group order changed."); if (chrome.footer.social.label !== "Social Outreach") throw new Error("Social footer group is missing."); +const socialLabels = chrome.footer.social.links.map((link) => link.label); +if (socialLabels.join("|") !== "GitHub|Telegram") throw new Error("Social footer must contain only GitHub and Telegram."); const requiredCopyright = ["free distribution only", "Privacy Policy", "Mission", "Revival", "We Fear God", "Why we believe the Bible", "Trousseau Chest"]; const copyrightLabels = chrome.footer.copyright.links.map((link) => link.label); @@ -171,5 +173,14 @@ for (const value of ["--tcc-container-max: 1200px", "border-top: 1px solid", "mi for (const behavior of ["Escape", "inert", "aria-expanded", "tcc-menu-open"]) { if (!sourceScript.includes(behavior)) throw new Error(`Header script is missing behavior: ${behavior}`); } +for (const behavior of ["requestAnimationFrame", "data-scroll-hidden", 'addEventListener("scroll"']) { + if (!sourceScript.includes(behavior)) throw new Error(`Header scroll behavior is missing: ${behavior}`); +} +if (!css.includes('.tcc-site-header[data-scroll-hidden="true"]')) throw new Error("Built CSS is missing the hidden header state."); +for (const canonicalMarkup of [footer, example]) { + if (canonicalMarkup.includes("twitter.com") || canonicalMarkup.includes("facebook.com")) { + throw new Error("Canonical footer still contains X/Twitter or Facebook."); + } +} console.log("Theme validation passed."); diff --git a/src/css/header.css b/src/css/header.css index a988d9a..42e4963 100644 --- a/src/css/header.css +++ b/src/css/header.css @@ -9,6 +9,18 @@ position: sticky; z-index: 1000; top: 0; + transform: translateY(0); + transition: transform 220ms ease; + will-change: transform; +} + +.tcc-site-header[data-scroll-hidden="true"] { + transform: translateY(calc(-100% - 1px)); +} + +.tcc-site-header[data-menu-open="true"], +.tcc-site-header:focus-within { + transform: translateY(0); } .tcc-header__container { diff --git a/src/data/site-chrome.json b/src/data/site-chrome.json index 8fcb4d7..05f3348 100644 --- a/src/data/site-chrome.json +++ b/src/data/site-chrome.json @@ -92,8 +92,6 @@ "social": { "label": "Social Outreach", "links": [ - { "label": "X", "href": "https://twitter.com/llewellynvdm", "icon": "twitter", "external": true, "newTab": true }, - { "label": "Facebook", "href": "https://www.facebook.com/aTrueChristianChurch", "icon": "facebook", "external": true, "newTab": true }, { "label": "GitHub", "href": "https://github.com/trueChristian", "icon": "github", "external": true, "newTab": true }, { "label": "Telegram", "href": "/telegram", "icon": "telegram", "external": false, "newTab": true } ], diff --git a/src/html/site-footer.html b/src/html/site-footer.html index 6990b03..cb2dfa2 100644 --- a/src/html/site-footer.html +++ b/src/html/site-footer.html @@ -45,12 +45,6 @@ From c5709028a6226af8e9d015c20cca601e91805590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Mon, 31 Aug 2026 00:39:14 +0200 Subject: [PATCH 3/3] Regenerate distributable CSS --- dist/truechristian-theme.css | 1 + 1 file changed, 1 insertion(+) diff --git a/dist/truechristian-theme.css b/dist/truechristian-theme.css index cdb9a21..b6127ad 100644 --- a/dist/truechristian-theme.css +++ b/dist/truechristian-theme.css @@ -391,6 +391,7 @@ p { gap: 0.4rem; } } + @media (min-width: 960px) { .tm-header .uk-navbar, .tm-header .uk-navbar-item,