source: Klonkt/src/views/partials/fedi-interact-styles.ejs@ 19e28ce

main
Last change on this file since 19e28ce was fd8faf5, checked in by Robin <roboburr@…>, 5 hours ago

Zoeken is één vlak: de balk bovenaan, de resultaten eronder, en @naam@server

Robins ontwerp van 30-9: de aparte resultatenpagina is niet meer nodig als het
vak onder de zoekbalk blijft staan. De balk en het vak eronder zijn samen het
hele zoeken, en het vak krijgt alle ruimte die er onder de balk is.

EEN VORM, TWEE INGANGEN. partials/search-surface.ejs is de balk plus het vak;
de overlay op elke pagina gebruikt hem, en /search?q=... ook. De resultaten
zelf staan in partials/search-results.ejs, en het live vak haalt precies die
render op (/search/results). De pagina bevat dus teken voor teken wat het vak
toont; een toets bewaakt dat, want twee renders lopen gegarandeerd uit de pas.
/search blijft bestaan zodat een gedeelde link en Enter zonder JavaScript op
hetzelfde beeld uitkomen.

/search/suggest (JSON, dat de browser tot een eigen lijstje bouwde, anders dan
de pagina) en /search/remote (alleen het adres) zijn weg; niets anders
gebruikte ze. remote-preview.ejs ging mee.

HET VLAK. Vaste positie over het hele scherm, de balk bovenaan, het vak vult
de rest en scrolt zelf. Op z-index 1060: de vorige overlay lag op 200, onder de
tabbalk (1050), zodat op een telefoon het onderste stuk resultaten wegviel. Enter
blijft staan en zoekt meteen, want het vak ís de resultaten. Op de pagina beweegt
het adres mee (/search?q=...), zodat wat je ziet te delen blijft; sluiten is daar
teruggaan. Balk en resultaten staan op één lijn: een scrollbalk alleen rechts
schoof de kolom anders zo'n 9 pixels naar links.

WEBFINGER. @naam@server (met of zonder @ vooraan, zoals Mastodon) haalt het
profiel op, met de volgknop. Zonder eerst een post te proberen: een handle is
nooit een post. De server moet een echte domeinnaam zijn; "@robin" blijft een
naam om naar te zoeken. WebFinger zelf is openbaar en loopt via safeFetch;
het profiel erachter gaat ondertekend, en alleen namens een ingelogde
beheerder, dezelfde grens als een geplakte link.

Onderweg gevonden: search-results.ejs verwees kaal naar queryError, en een
aanroeper die hem vergat liet de hele render omvallen. Alles gaat nu via
locals. In de app gaf gather hem altijd mee, dus live ging het goed; het was
één vergeten veld van een kapotte zoekpagina.

Nagelopen in de browser op 375 en 1280 pixels: de balk bovenaan, het vak tot
de onderrand, tabbalk bedekt, geen horizontale overloop, tikdoelen 44, balk en
resultaten op één lijn. Het gedrag met de echte chrome.js: openen vers en met
focus, typen, Enter zonder weg te gaan, de wachtregel bij een link en een
handle, een traag antwoord dat niets overschrijft, een resultaat aantikken en
Escape sluiten, en het adres dat op de pagina meebeweegt.

Getoetst: pagina en vak teken voor teken gelijk, de handle-herkenning, een
handle ondertekend en zonder post-poging, en niet ingelogd geen enkel verzoek.
Tegenproef: pagina laten afwijken, handle niet herkennen, bij een handle toch
een post proberen en de inlogcontrole eruit laten elk hun toetsen omvallen.
Volledige suite 1292 groen.

shaer-utpi

Co-Authored-By: Claude Opus 5.5 <noreply@…>

  • Property mode set to 100644
File size: 13.6 KB
Line 
1<%#
2 De opmaak van de fediverse-interactieschermen. Staat apart zodat de pagina en
3 de zoekresultaten dezelfde render krijgen zonder de regels twee keer op te
4 schrijven (een tweede kopie loopt gegarandeerd uit de pas).
5%>
6<style>
7 .auth-interact { max-width: 640px; margin: 1rem auto; padding: 0 1rem; }
8 .auth-interact-title { margin: 0 0 1rem; }
9 .auth-interact-form { display: flex; flex-direction: column; gap: .75rem; }
10 .auth-interact-form textarea, .auth-interact-form input[type=url] {
11 width: 100%; box-sizing: border-box; padding: .6rem .8rem; font: inherit; resize: vertical;
12 border-radius: 12px; border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent);
13 background: var(--paper, #fff); color: var(--ink, #000);
14 }
15 .auth-interact-actions { display: flex; gap: .5rem; align-items: center; }
16 .auth-interact-note { color: var(--ink-soft, #999); font-size: .85rem; margin-top: 1rem; }
17 .fedi-manage { list-style: none; padding: 0; margin: 1.25rem 0 1rem; display: flex; flex-direction: column; gap: .7rem; }
18 .fedi-manage-item { padding: .9rem 1rem; border-radius: 14px; background: color-mix(in srgb, var(--ink, #000) 3.5%, transparent); border: 1px solid color-mix(in srgb, var(--ink, #000) 9%, transparent); transition: border-color .15s ease, box-shadow .15s ease; }
19 .fedi-manage-item:hover { border-color: color-mix(in srgb, var(--accent, #888) 28%, transparent); box-shadow: 0 2px 12px color-mix(in srgb, var(--ink, #000) 6%, transparent); }
20 .fedi-manage-head { display: flex; align-items: center; gap: .5rem; margin: 0 0 .5rem; }
21 .fedi-manage-icon { flex: 0 0 26px; width: 26px; height: 26px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
22 background: color-mix(in srgb, var(--accent, #888) 16%, transparent); color: var(--accent, #06c); }
23 .fedi-manage-icon svg { width: 14px; height: 14px; }
24 .fedi-manage-to { font-weight: 600; color: var(--ink, inherit); font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
25 .fedi-manage-time { color: var(--ink-soft, #999); font-size: .76rem; margin-left: auto; flex: 0 0 auto; white-space: nowrap; }
26 .fedi-manage-content { line-height: 1.55; overflow-wrap: anywhere; padding-left: calc(26px + .5rem); }
27 .fedi-manage-content p { margin: .15rem 0; }
28 .fedi-manage-content p:first-child { margin-top: 0; }
29 .fedi-manage-content p:last-child { margin-bottom: 0; }
30 .fedi-manage-foot { display: flex; align-items: center; justify-content: flex-start; flex-wrap: wrap; gap: .5rem; margin-top: .65rem; }
31 .fedi-goto-btn { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid color-mix(in srgb, var(--accent, #888) 45%, transparent); background: color-mix(in srgb, var(--accent, #888) 12%, transparent); color: var(--accent, #06c); border-radius: 999px; padding: .3rem .8rem; font-size: .82rem; text-decoration: none; transition: background .15s ease; }
32 .fedi-goto-btn:hover { background: color-mix(in srgb, var(--accent, #888) 22%, transparent); }
33 .fedi-del-btn { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid color-mix(in srgb, #d9534f 45%, transparent); background: color-mix(in srgb, #d9534f 12%, transparent); color: #e06b66; border-radius: 999px; padding: .3rem .8rem; font: inherit; font-size: .82rem; cursor: pointer; transition: background .15s ease; }
34 .fedi-del-btn:hover { background: color-mix(in srgb, #d9534f 24%, transparent); }
35 .fedi-bm { margin: 0 0 1.5rem; padding: 1rem; border-radius: 14px;
36 border: 1px dashed color-mix(in srgb, var(--accent, #888) 45%, transparent);
37 background: color-mix(in srgb, var(--accent, #888) 7%, transparent); }
38 .fedi-bm-btn { display: inline-flex; align-items: center; gap: .45rem; padding: .5rem 1rem; border-radius: 999px;
39 background: var(--accent, #06c); color: #fff; font: inherit; font-weight: 600; font-size: .9rem; text-decoration: none;
40 cursor: grab; user-select: none; box-shadow: 0 2px 8px color-mix(in srgb, var(--accent, #000) 30%, transparent); }
41 .fedi-bm-btn:active { cursor: grabbing; }
42 .fedi-bm-btn.nudge { animation: fedi-bm-nudge .6s ease; }
43 @keyframes fedi-bm-nudge { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-4px); } 75% { transform: translateX(4px); } }
44 .fedi-bm-help { color: var(--ink-soft, #888); font-size: .82rem; line-height: 1.5; margin: .6rem 0 0; }
45 .fedi-edit-btn { display: inline-flex; align-items: center; gap: .35rem; border: 1px solid color-mix(in srgb, var(--ink, #888) 28%, transparent);
46 background: color-mix(in srgb, var(--ink, #888) 8%, transparent); color: var(--ink-soft, #aaa); border-radius: 999px; padding: .3rem .8rem;
47 font: inherit; font-size: .82rem; cursor: pointer; transition: background .15s ease, color .15s ease; }
48 .fedi-edit-btn:hover { background: color-mix(in srgb, var(--ink, #888) 16%, transparent); }
49 .fedi-edit-btn.is-open { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
50 .fedi-del-form { margin-left: auto; }
51 .fedi-edit-form { display: none; margin: .55rem 0 0; }
52 .fedi-edit-form.is-open { display: block; }
53 .fedi-edit-ta { width: 100%; box-sizing: border-box; min-height: 70px; resize: vertical; padding: .55rem .7rem;
54 border: 1.5px solid var(--rule, #333); border-radius: 10px; background: var(--paper-2, #14141a); color: var(--ink, #eee); font: inherit; font-size: .9rem; }
55 .fedi-edit-ta:focus { outline: none; border-color: var(--accent); }
56 .fedi-edit-actions { display: flex; justify-content: flex-end; margin-top: .5rem; }
57 .fedi-edit-save { padding: .4rem 1rem; border: 0; border-radius: 999px; background: var(--accent); color: var(--paper, #fff);
58 font: inherit; font-weight: 600; font-size: .82rem; cursor: pointer; }
59
60 /* ── De kaart van een post of profiel van een andere server ──────────────
61 Eén kaart voor de live-preview, de zoekpagina en /authorize_interaction.
62 De telefoon is het uitgangspunt: knoppen van minstens 44 punten, en op
63 een smal scherm vallen de woorden weg en blijven de tekens staan. */
64 .rp-card { position: relative; padding: 14px 16px 4px; border-radius: 16px;
65 border: 1px solid color-mix(in srgb, var(--ink, #000) 10%, transparent);
66 background: color-mix(in srgb, var(--ink, #000) 2.5%, var(--paper, transparent));
67 color: var(--ink, inherit); overflow: hidden; }
68 .rp-head { display: flex; align-items: center; gap: 10px; min-width: 0; margin: 0 0 10px; }
69 .rp-avatar { flex: 0 0 40px; width: 40px; height: 40px; border-radius: 50%; object-fit: cover;
70 background: color-mix(in srgb, var(--ink, #000) 8%, transparent); }
71 .rp-profile .rp-avatar { flex-basis: 56px; width: 56px; height: 56px; }
72 .rp-avatar-empty { display: inline-flex; align-items: center; justify-content: center;
73 font-weight: 700; color: var(--ink-soft, #888); }
74 .rp-who { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
75 .rp-name { font-weight: 700; color: var(--ink, inherit); text-decoration: none;
76 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
77 .rp-name:hover { text-decoration: underline; }
78 .rp-handle { font-size: .82rem; color: var(--ink-soft, #888); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
79
80 .rp-body { line-height: 1.55; overflow-wrap: anywhere; }
81 .rp-body p { margin: .45rem 0; }
82 .rp-body > :first-child { margin-top: 0; }
83 .rp-body > :last-child { margin-bottom: 0; }
84 .rp-body a { color: var(--accent, #06c); }
85 .rp-body img { max-width: 100%; height: auto; }
86
87 /* Beeld als raster: één foto op volle breedte, meer als tegels, zodat een
88 lange reeks de knoppen niet van het scherm duwt. */
89 /* Vaste rijhoogtes in plaats van verhoudingen: met verhoudingen groeit het
90 raster mee met de breedte, en werd op een desktop de eerste van drie foto's
91 zo hoog dat de knoppen onder de vouw van de uitklaplijst verdwenen. */
92 .rp-media { display: grid; gap: 3px; margin: 10px 0 0; border-radius: 12px; overflow: hidden; }
93 .rp-media a { display: block; min-width: 0; }
94 .rp-media img { display: block; width: 100%; height: 100%; object-fit: cover; }
95 .rp-media-1 img { height: auto; max-height: 480px; }
96 .rp-media-2, .rp-media-3, .rp-media-4 { grid-template-columns: 1fr 1fr; grid-auto-rows: clamp(120px, 28vw, 220px); }
97 .rp-media-3 a:first-child { grid-column: 1 / -1; }
98 .rp-compact .rp-media-1 img { max-height: 240px; }
99 .rp-compact .rp-media-2, .rp-compact .rp-media-3, .rp-compact .rp-media-4 { grid-auto-rows: 110px; }
100
101 /* Een inhoudswaarschuwing: dicht tot je ervoor kiest. */
102 .rp-cw > summary { list-style: none; display: flex; align-items: center; justify-content: space-between; gap: 10px;
103 min-height: 44px; padding: 8px 12px; border-radius: 10px; cursor: pointer; font-weight: 600;
104 background: color-mix(in srgb, #e8b04b 12%, transparent); border: 1px solid color-mix(in srgb, #e8b04b 35%, transparent); }
105 .rp-cw > summary::-webkit-details-marker { display: none; }
106 .rp-cw-text { min-width: 0; overflow-wrap: anywhere; }
107 .rp-cw-open { flex: 0 0 auto; font-size: .8rem; color: var(--accent, #06c); }
108 .rp-cw[open] > summary { margin: 0 0 10px; }
109 .rp-cw[open] .rp-cw-open { display: none; }
110
111 /* De rij knoppen: gelijke tekens, het origineel rechts. */
112 .rp-actions { display: flex; align-items: center; gap: 2px; margin: 10px -8px 0; padding: 2px 0;
113 border-top: 1px solid color-mix(in srgb, var(--ink, #000) 8%, transparent); }
114 .rp-actions form { margin: 0; }
115 .rp-act { display: inline-flex; align-items: center; justify-content: center; gap: 6px;
116 min-width: 44px; min-height: 44px; padding: 0 12px; border: 0; border-radius: 999px;
117 background: transparent; color: var(--ink-soft, #888); font: inherit; font-size: .88rem; font-weight: 600;
118 text-decoration: none; cursor: pointer; white-space: nowrap; -webkit-tap-highlight-color: transparent;
119 transition: background .12s, color .12s; }
120 .rp-act svg { flex: 0 0 18px; width: 18px; height: 18px; }
121 .rp-act:hover { background: color-mix(in srgb, var(--ink, #000) 6%, transparent); color: var(--ink, inherit); }
122 .rp-act:focus-visible { outline: 2px solid var(--accent, #06c); outline-offset: 2px; }
123 .rp-act[disabled] { opacity: .55; cursor: progress; }
124 .rp-like.is-on { color: #d99a1e; }
125 .rp-like.is-on svg { fill: currentColor; }
126 .rp-boost.is-on { color: #2fa85a; }
127 .rp-reply-btn[aria-expanded="true"] { color: var(--accent, #06c); }
128 .rp-src { margin-left: auto; }
129 .rp-primary { background: var(--accent, #06c); color: var(--paper, #fff); }
130 .rp-primary:hover { background: var(--accent, #06c); color: var(--paper, #fff); filter: brightness(1.08); }
131 .rp-profile .rp-actions { border-top: 0; margin-top: 4px; padding-bottom: 8px; }
132 .rp-profile .rp-actions form { flex: 0 0 auto; }
133
134 /* Een peiling in de kaart. */
135 .rp-poll { display: flex; flex-direction: column; gap: 6px; margin: 12px 0 0; }
136 .rp-poll-choice { display: flex; align-items: center; gap: 10px; min-height: 44px; padding: 0 12px; border-radius: 10px; cursor: pointer;
137 border: 1px solid color-mix(in srgb, var(--ink, #000) 14%, transparent); }
138 .rp-poll-choice:hover { border-color: var(--accent, #06c); }
139 .rp-poll-choice input { accent-color: var(--accent, #06c); }
140 .rp-poll-res { position: relative; display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-radius: 10px; overflow: hidden;
141 background: color-mix(in srgb, var(--ink, #000) 6%, transparent); }
142 .rp-poll-fill { position: absolute; inset: 0 auto 0 0; background: color-mix(in srgb, var(--accent, #06c) 22%, transparent); }
143 .rp-poll-name { position: relative; flex: 1; }
144 .rp-poll-pct { position: relative; font-variant-numeric: tabular-nums; font-weight: 600; }
145 .rp-poll-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap;
146 font-size: .82rem; color: var(--ink-soft, #888); }
147
148 /* Wat er onder de kaart staat, op de volle pagina. */
149 .rp-reply { margin: 12px 0 0; }
150 .rp-reply-where { margin: 0 0 8px; font-size: .85rem; line-height: 1.5; color: var(--ink-soft, #888); }
151 .rp-reply-foot { display: flex; justify-content: flex-end; margin-top: 4px; }
152 .rp-as { margin: 12px 2px 0; font-size: .8rem; color: var(--ink-soft, #999); }
153 .rp-report { margin: 6px 2px 0; }
154 .rp-report > summary { display: inline-block; padding: 8px 0; cursor: pointer; font-size: .8rem; color: var(--ink-soft, #888); }
155 .rp-report > summary:hover, .rp-report[open] > summary { color: #c0392b; }
156 .rp-report-form { display: flex; flex-direction: column; gap: .6rem; }
157 .rp-report-note { margin: 0; font-size: .82rem; color: var(--ink-soft, #999); }
158 .rp-report-form textarea { width: 100%; box-sizing: border-box; padding: .6rem .8rem; font: inherit; resize: vertical; border-radius: 12px;
159 border: 1px solid color-mix(in srgb, var(--ink, #000) 18%, transparent); background: var(--paper, #fff); color: var(--ink, #000); }
160
161 /* De compacte kaart in het zoekvak: de link naar de volle pagina eronder. */
162 .rp-open { display: block; padding: 10px 4px 2px; text-align: right; font-weight: 600; font-size: .88rem;
163 color: var(--accent, #06c); text-decoration: none; }
164 .rp-open:hover { text-decoration: underline; }
165
166 /* Smal scherm: alleen de tekens, gelijk verdeeld over de breedte. De woorden
167 blijven bestaan voor wie het scherm voorgelezen krijgt. */
168 @media (max-width: 480px) {
169 .rp-card { padding: 12px 12px 2px; border-radius: 14px; }
170 .rp-actions { margin: 8px -4px 0; justify-content: space-between; }
171 .rp-act .rp-act-label { position: absolute; width: 1px; height: 1px; overflow: hidden;
172 clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
173 .rp-src { margin-left: 0; }
174 .rp-media-1 img { max-height: 360px; }
175 }
176</style>
Note: See TracBrowser for help on using the repository browser.