| 1 | <footer class="site-footer">
|
|---|
| 2 | <div class="container site-footer-inner">
|
|---|
| 3 | <div>
|
|---|
| 4 | <span>© <%= new Date().getFullYear() %> <%= (site && site.title) || 'PrutFolio' %></span>
|
|---|
| 5 | </div>
|
|---|
| 6 | <div class="footer-meta">
|
|---|
| 7 | <span>PrutFolio v1</span>
|
|---|
| 8 | <%# Mobile-only theme toggle. On desktop the topnav has its own toggle
|
|---|
| 9 | so we hide this one to avoid two visible toggles at once. The same
|
|---|
| 10 | toggleTheme handler in topnav.ejs picks this button up by id. %>
|
|---|
| 11 | <button type="button" class="footer-theme-toggle" id="theme-toggle-footer"
|
|---|
| 12 | aria-label="Thema wisselen" title="Thema wisselen">
|
|---|
| 13 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
|---|
| 14 | stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|---|
| 15 | <circle cx="12" cy="12" r="4"/>
|
|---|
| 16 | <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
|
|---|
| 17 | </svg>
|
|---|
| 18 | </button>
|
|---|
| 19 | </div>
|
|---|
| 20 | </div>
|
|---|
| 21 |
|
|---|
| 22 | <%# Install-app button. JS detects platform & opens a modal with PWA-install
|
|---|
| 23 | steps (iOS share-sheet / Android Chrome / desktop). PWA only — geen APK. %>
|
|---|
| 24 | <div class="site-footer-install container">
|
|---|
| 25 | <button type="button" class="install-app-btn" data-pcms-install-app>
|
|---|
| 26 | <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="M5 20h14v-2H5v2zm7-18L5.33 9h3.84v6h5.66V9h3.84L12 2z" fill="currentColor"/></svg>
|
|---|
| 27 | <span>Installeer app</span>
|
|---|
| 28 | </button>
|
|---|
| 29 | </div>
|
|---|
| 30 | </footer>
|
|---|
| 31 |
|
|---|
| 32 | <style>
|
|---|
| 33 | /* Make sure the page itself is at least viewport-tall so the flex sticky-
|
|---|
| 34 | footer logic (body display:flex, main flex:1) can push the footer down.
|
|---|
| 35 | 100dvh is dynamic viewport height — handles mobile address-bar collapse. */
|
|---|
| 36 | html { min-height: 100dvh; }
|
|---|
| 37 |
|
|---|
| 38 | .site-footer {
|
|---|
| 39 | border-top: 1px solid var(--rule);
|
|---|
| 40 | margin-top: 4rem;
|
|---|
| 41 | padding: 2rem 0;
|
|---|
| 42 | padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0));
|
|---|
| 43 | font-size: 0.85rem;
|
|---|
| 44 | color: var(--ink-muted);
|
|---|
| 45 | background: var(--paper);
|
|---|
| 46 | /* When fixed bars (mini-player / bottom-tab) sit at the bottom of the
|
|---|
| 47 | viewport they overlap the footer at scroll-end. The clearance below
|
|---|
| 48 | mirrors the .pcms-main rule in audio.css — content goes at the top of
|
|---|
| 49 | the footer, the player floats over the empty padding underneath. */
|
|---|
| 50 | transition: padding-bottom .2s ease;
|
|---|
| 51 | }
|
|---|
| 52 | /* Audio player visible (desktop, no bottom-tab): clear ~80px */
|
|---|
| 53 | body.has-audio-player .site-footer {
|
|---|
| 54 | padding-bottom: calc(2rem + 80px + env(safe-area-inset-bottom, 0));
|
|---|
| 55 | }
|
|---|
| 56 | @media (max-width: 767px) {
|
|---|
| 57 | /* Bottom-tab visible alone: ~56px tab */
|
|---|
| 58 | body.has-bottom-tab .site-footer {
|
|---|
| 59 | padding-bottom: calc(2rem + 56px + env(safe-area-inset-bottom, 0));
|
|---|
| 60 | }
|
|---|
| 61 | /* Bottom-tab + audio-player stacked: ~56px tab + ~72px player */
|
|---|
| 62 | body.has-bottom-tab.has-audio-player .site-footer {
|
|---|
| 63 | padding-bottom: calc(2rem + 56px + 72px + env(safe-area-inset-bottom, 0));
|
|---|
| 64 | }
|
|---|
| 65 | }
|
|---|
| 66 | .site-footer-inner {
|
|---|
| 67 | max-width: 800px;
|
|---|
| 68 | margin: 0 auto;
|
|---|
| 69 | padding: 0 1rem;
|
|---|
| 70 | display: flex;
|
|---|
| 71 | justify-content: space-between;
|
|---|
| 72 | align-items: center;
|
|---|
| 73 | flex-wrap: wrap;
|
|---|
| 74 | gap: 1rem;
|
|---|
| 75 | }
|
|---|
| 76 | .footer-meta {
|
|---|
| 77 | font-size: 0.8rem; opacity: 0.7;
|
|---|
| 78 | display: inline-flex; align-items: center; gap: 0.75rem;
|
|---|
| 79 | }
|
|---|
| 80 | .pcms-main { min-height: 50vh; }
|
|---|
| 81 |
|
|---|
| 82 | /* Mobile theme toggle in footer. Pill-style button matching topnav nav-btn.
|
|---|
| 83 | Hidden on desktop; the topnav already has a toggle there. */
|
|---|
| 84 | .footer-theme-toggle {
|
|---|
| 85 | display: none;
|
|---|
| 86 | align-items: center; justify-content: center;
|
|---|
| 87 | width: 36px; height: 36px;
|
|---|
| 88 | padding: 0; margin: 0;
|
|---|
| 89 | background: transparent; color: var(--ink);
|
|---|
| 90 | border: 1px solid var(--rule); border-radius: 999px;
|
|---|
| 91 | cursor: pointer;
|
|---|
| 92 | transition: background-color 120ms, border-color 120ms;
|
|---|
| 93 | -webkit-tap-highlight-color: transparent;
|
|---|
| 94 | opacity: 1; /* override .footer-meta dim */
|
|---|
| 95 | }
|
|---|
| 96 | .footer-theme-toggle:hover { background: var(--paper-2); border-color: var(--accent); }
|
|---|
| 97 | .footer-theme-toggle:active { transform: scale(0.96); }
|
|---|
| 98 | .footer-theme-toggle svg { width: 18px; height: 18px; }
|
|---|
| 99 |
|
|---|
| 100 | @media (max-width: 768px) {
|
|---|
| 101 | .footer-theme-toggle { display: inline-flex; }
|
|---|
| 102 | }
|
|---|
| 103 |
|
|---|
| 104 | /* Install-app button container — sits centered under the footer-inner row */
|
|---|
| 105 | .site-footer-install {
|
|---|
| 106 | display: flex;
|
|---|
| 107 | justify-content: center;
|
|---|
| 108 | margin-top: 1.25rem;
|
|---|
| 109 | }
|
|---|
| 110 | </style>
|
|---|