| 1 | <%#
|
|---|
| 2 | Het profiel van een ward, en het enige dat een bezoeker van de site ziet
|
|---|
| 3 | (Robins ontwerp, 30-9; zie middleware/ward-profile.js).
|
|---|
| 4 |
|
|---|
| 5 | Omdat dit ALLES is wat er openbaar staat, mag het er verzorgd uitzien: een
|
|---|
| 6 | eigen pagina en geen voorpagina met een lege stroom eronder.
|
|---|
| 7 |
|
|---|
| 8 | Dezelfde bronnen als de profielkop (partials/profile-header.ejs), zodat het
|
|---|
| 9 | profiel op geen twee plekken iets anders kan zeggen: naam uit profile_name of
|
|---|
| 10 | title, tekst uit profile_bio, description of tagline, links uit profile_links.
|
|---|
| 11 |
|
|---|
| 12 | NERGENS "KIND" OF "WARD". Dat deze account guardians heeft staat al openbaar op
|
|---|
| 13 | de fediverse (shaer:guardians, FEP-633c 2.1); deze pagina hoeft dat niet in
|
|---|
| 14 | koeienletters te herhalen. Wat een bezoeker wel hoort te weten, is dat de
|
|---|
| 15 | berichten er niet voor hem staan -- neutraal gezegd.
|
|---|
| 16 |
|
|---|
| 17 | Verwacht: site, wardHandle, wardLinks, platforms_catalog, avatar, t.
|
|---|
| 18 | %>
|
|---|
| 19 | <%
|
|---|
| 20 | const _name = site.profile_name || site.title || site.slug;
|
|---|
| 21 | const _bio = site.profile_bio || site.description || site.tagline || '';
|
|---|
| 22 | const _photo = site.profile_photo || '';
|
|---|
| 23 | const _catalog = (typeof platforms_catalog !== 'undefined' && platforms_catalog) || {};
|
|---|
| 24 | const _links = (wardLinks || []).filter(function (l) { return l && _catalog[l.platform]; });
|
|---|
| 25 | const _href = function (p, u) {
|
|---|
| 26 | u = String(u || '').trim();
|
|---|
| 27 | if (p === 'email' && u.indexOf('mailto:') !== 0) return 'mailto:' + u;
|
|---|
| 28 | if (p === 'phone' && !/^tel:/i.test(u)) return 'tel:' + u.replace(/[^\d+]/g, '');
|
|---|
| 29 | return u;
|
|---|
| 30 | };
|
|---|
| 31 | const _showFollow = site.slug && (typeof apEnabled === 'undefined' || apEnabled);
|
|---|
| 32 | %>
|
|---|
| 33 | <div class="wp" aria-labelledby="wp-name">
|
|---|
| 34 | <div class="wp-glow" aria-hidden="true"></div>
|
|---|
| 35 | <article class="wp-card">
|
|---|
| 36 | <div class="wp-photo">
|
|---|
| 37 | <% if (_photo) { %>
|
|---|
| 38 | <img src="<%= avatar(_photo, 320) %>" alt="" width="160" height="160">
|
|---|
| 39 | <% } else { %>
|
|---|
| 40 | <span class="wp-photo-initial" aria-hidden="true"><%= String(_name).charAt(0).toUpperCase() %></span>
|
|---|
| 41 | <% } %>
|
|---|
| 42 | </div>
|
|---|
| 43 |
|
|---|
| 44 | <h1 class="wp-name" id="wp-name"><%= _name %></h1>
|
|---|
| 45 | <p class="wp-handle"><span><%= wardHandle %></span></p>
|
|---|
| 46 | <% if (_bio) { %><p class="wp-bio"><%= _bio %></p><% } %>
|
|---|
| 47 |
|
|---|
| 48 | <% if (_links.length || _showFollow) { %>
|
|---|
| 49 | <ul class="wp-links">
|
|---|
| 50 | <% if (_showFollow) { %>
|
|---|
| 51 | <li>
|
|---|
| 52 | <%# Opent de volgdialoog uit de profielkop (chrome.js). Een volgverzoek
|
|---|
| 53 | aan deze account gaat eerst langs de guardians (FEP-633c 5.3). %>
|
|---|
| 54 | <button type="button" class="wp-link wp-follow profile-fedi-link" data-fedi-actor-slug="<%= site.slug %>">
|
|---|
| 55 | <span class="wp-link-ico" aria-hidden="true">
|
|---|
| 56 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>
|
|---|
| 57 | </span>
|
|---|
| 58 | <span class="wp-link-label"><%= t('fedi.profile_follow') %></span>
|
|---|
| 59 | <span class="wp-link-go" aria-hidden="true">→</span>
|
|---|
| 60 | </button>
|
|---|
| 61 | </li>
|
|---|
| 62 | <% } %>
|
|---|
| 63 | <% _links.forEach(function (l) { var meta = _catalog[l.platform]; var ext = (l.platform !== 'email' && l.platform !== 'phone'); %>
|
|---|
| 64 | <li>
|
|---|
| 65 | <a class="wp-link" href="<%= _href(l.platform, l.url) %>" <% if (ext) { %>target="_blank" rel="noopener noreferrer"<% } %> style="--brand: <%= meta.brand %>">
|
|---|
| 66 | <span class="wp-link-ico" aria-hidden="true"><%- meta.svg %></span>
|
|---|
| 67 | <span class="wp-link-label"><%= meta.label %></span>
|
|---|
| 68 | <span class="wp-link-go" aria-hidden="true"><%= ext ? '↗' : '→' %></span>
|
|---|
| 69 | </a>
|
|---|
| 70 | </li>
|
|---|
| 71 | <% }); %>
|
|---|
| 72 | </ul>
|
|---|
| 73 | <% } %>
|
|---|
| 74 |
|
|---|
| 75 | <p class="wp-note">
|
|---|
| 76 | <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg>
|
|---|
| 77 | <span><%= t('ward.followers_only', { name: _name }) %></span>
|
|---|
| 78 | </p>
|
|---|
| 79 | </article>
|
|---|
| 80 | </div>
|
|---|
| 81 |
|
|---|
| 82 | <style>
|
|---|
| 83 | /* ── Het profiel, en verder niets ───────────────────────────────────────── */
|
|---|
| 84 | body.on-ward-profile { background: var(--paper); }
|
|---|
| 85 | .wp { position: relative; min-height: calc(100svh - 9rem); display: grid; place-items: center;
|
|---|
| 86 | padding: clamp(2rem, 6vw, 4rem) 1.25rem calc(3rem + env(safe-area-inset-bottom, 0px)); overflow: hidden; isolation: isolate; }
|
|---|
| 87 | /* Een zachte gloed in de accentkleur van de site, achter de kaart. */
|
|---|
| 88 | .wp-glow { position: absolute; inset: -20% -10% auto; height: 70%; z-index: -1; pointer-events: none;
|
|---|
| 89 | background:
|
|---|
| 90 | radial-gradient(40% 55% at 30% 40%, color-mix(in srgb, var(--accent) 28%, transparent), transparent 70%),
|
|---|
| 91 | radial-gradient(35% 50% at 72% 30%, color-mix(in srgb, var(--accent) 16%, var(--ink) 4%), transparent 70%);
|
|---|
| 92 | filter: blur(28px); opacity: .9; }
|
|---|
| 93 | .wp-card { width: 100%; max-width: 30rem; text-align: center; display: flex; flex-direction: column; align-items: center; }
|
|---|
| 94 |
|
|---|
| 95 | .wp-photo { position: relative; width: 9.5rem; height: 9.5rem; border-radius: 50%; padding: 5px;
|
|---|
| 96 | background: conic-gradient(from 210deg, var(--accent), color-mix(in srgb, var(--accent) 35%, var(--paper)), var(--accent));
|
|---|
| 97 | box-shadow: 0 18px 50px color-mix(in srgb, var(--accent) 30%, transparent); }
|
|---|
| 98 | .wp-photo img, .wp-photo-initial { display: block; width: 100%; height: 100%; border-radius: 50%; object-fit: cover;
|
|---|
| 99 | border: 4px solid var(--paper); box-sizing: border-box; background: var(--paper-2, var(--paper)); }
|
|---|
| 100 | .wp-photo-initial { display: grid; place-items: center; font: 700 3.5rem/1 var(--font-display, var(--font-ui, inherit)); color: var(--accent); }
|
|---|
| 101 |
|
|---|
| 102 | .wp-name { margin: 1.4rem 0 .35rem; font-family: var(--font-display, inherit); font-size: clamp(2rem, 7vw, 2.8rem);
|
|---|
| 103 | line-height: 1.1; letter-spacing: -.01em; color: var(--ink); overflow-wrap: anywhere; }
|
|---|
| 104 | .wp-handle { margin: 0; }
|
|---|
| 105 | .wp-handle span { display: inline-block; max-width: 100%; padding: .3rem .8rem; border-radius: 999px;
|
|---|
| 106 | background: color-mix(in srgb, var(--ink) 6%, transparent); color: var(--ink-soft, var(--ink)); font-size: .9rem;
|
|---|
| 107 | user-select: all; -webkit-user-select: all; overflow-wrap: anywhere; }
|
|---|
| 108 | .wp-bio { margin: 1.1rem 0 0; font-size: 1.05rem; line-height: 1.6; color: var(--ink); max-width: 26rem; white-space: pre-line; }
|
|---|
| 109 |
|
|---|
| 110 | /* De links: brede knoppen, zoals een link-in-bio. */
|
|---|
| 111 | .wp-links { list-style: none; margin: 1.8rem 0 0; padding: 0; width: 100%; display: flex; flex-direction: column; gap: .6rem; }
|
|---|
| 112 | .wp-link { display: flex; align-items: center; gap: .85rem; width: 100%; min-height: 3.25rem; padding: .55rem .9rem .55rem .6rem;
|
|---|
| 113 | box-sizing: border-box; border-radius: 16px; border: 1px solid var(--rule); background: color-mix(in srgb, var(--paper) 88%, var(--ink) 4%);
|
|---|
| 114 | color: var(--ink); text-decoration: none; font: inherit; font-weight: 600; text-align: left; cursor: pointer;
|
|---|
| 115 | transition: transform .15s ease, border-color .15s ease, box-shadow .15s ease; -webkit-tap-highlight-color: transparent; }
|
|---|
| 116 | .wp-link:hover, .wp-link:focus-visible { transform: translateY(-1px); border-color: color-mix(in srgb, var(--brand, var(--accent)) 55%, var(--rule));
|
|---|
| 117 | box-shadow: 0 8px 22px color-mix(in srgb, var(--brand, var(--accent)) 18%, transparent); }
|
|---|
| 118 | .wp-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|---|
| 119 | .wp-link-ico { flex: 0 0 2.2rem; width: 2.2rem; height: 2.2rem; border-radius: 12px; display: grid; place-items: center;
|
|---|
| 120 | background: var(--brand, var(--accent)); color: #fff; }
|
|---|
| 121 | .wp-link-ico svg { width: 1.2rem; height: 1.2rem; fill: currentColor; }
|
|---|
| 122 | .wp-follow .wp-link-ico { background: var(--accent); }
|
|---|
| 123 | .wp-follow .wp-link-ico svg { fill: none; }
|
|---|
| 124 | .wp-link-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|---|
| 125 | .wp-link-go { flex: 0 0 auto; color: var(--ink-soft, var(--ink)); opacity: .7; }
|
|---|
| 126 |
|
|---|
| 127 | /* Loopt de zin over twee regels, dan hoort hij naast het slotje te beginnen en
|
|---|
| 128 | niet gecentreerd ver ervan af -- vandaar links uitgelijnd en een ronding die
|
|---|
| 129 | ook bij twee regels klopt. */
|
|---|
| 130 | .wp-note { display: inline-flex; align-items: center; gap: .6rem; max-width: 24rem; margin: 2rem 0 0; padding: .6rem .95rem;
|
|---|
| 131 | border-radius: 14px; text-align: left; font-size: .85rem; line-height: 1.45;
|
|---|
| 132 | color: var(--ink-soft, var(--ink)); background: color-mix(in srgb, var(--ink) 5%, transparent); }
|
|---|
| 133 | .wp-note svg { flex: 0 0 1rem; width: 1rem; height: 1rem; }
|
|---|
| 134 |
|
|---|
| 135 | /* Rustig binnenkomen; niet voor wie minder beweging wil. */
|
|---|
| 136 | @media (prefers-reduced-motion: no-preference) {
|
|---|
| 137 | .wp-card > * { animation: wp-in .5s cubic-bezier(.2, .7, .2, 1) both; }
|
|---|
| 138 | .wp-card > :nth-child(2) { animation-delay: .05s; }
|
|---|
| 139 | .wp-card > :nth-child(3) { animation-delay: .1s; }
|
|---|
| 140 | .wp-card > :nth-child(4) { animation-delay: .15s; }
|
|---|
| 141 | .wp-card > :nth-child(5) { animation-delay: .2s; }
|
|---|
| 142 | .wp-card > :nth-child(6) { animation-delay: .25s; }
|
|---|
| 143 | @keyframes wp-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
|
|---|
| 144 | }
|
|---|
| 145 | </style>
|
|---|