source: Klonkt/src/views/partials/fedi-interact-styles.ejs@ 9eb6e1b

main
Last change on this file since 9eb6e1b was 9eb6e1b, checked in by Robin <roboburr@…>, 7 hours ago

Een fediverse-post ziet eruit als een post, ook in de zoekbalk

Plak je een link in de zoekbalk, dan laadt de uitklaplijst nu de post zelf
in plaats van te zoeken naar de tekst van de link. Dezelfde kaart staat op de
zoekpagina en op /authorize_interaction, dus één render op drie plekken.

DE KAART. Wat eromheen stond is teruggebracht tot een kop met gezicht, de
inhoud, en één rij knoppen: Reageer, Like, Boost en het origineel. Weg zijn de
zin "je reageert op", de aparte knop naar het origineel, de twee grote pillen,
"of reageer:" en het antwoordvenster dat altijd openstond. Antwoorden klapt
open als je erom vraagt; melden staat onderaan en niet in de weg.

Foto's staan in een raster met vaste rijhoogtes. Met verhoudingen groeide het
mee met de breedte, en werd op een desktop de eerste van drie foto's zo hoog
dat de knoppen onder de vouw van de uitklaplijst verdwenen.

EEN INHOUDSWAARSCHUWING WORDT GERESPECTEERD. De oude render toonde alles open,
ook wat de schrijver achter een waarschuwing had gezet.

MOBIEL. Elke knop minstens 44 punten. Op een smal scherm vallen de woorden weg
en blijven de tekens staan, gelijk verdeeld; de woorden blijven bestaan voor
wie het scherm voorgelezen krijgt. Nagemeten op 375 pixels: geen horizontale
overloop, kleinste tikdoel 44, de knoppen in beeld zonder te scrollen.

DE PREVIEW IS COMPACT. Waarderen en boosten kan ter plekke; antwoorden en
melden gaan naar de volle pagina, met ?reply=1 of ?report=1 zodat dat deel
daar al openstaat. Een editor in een uitklaplijst is op een telefoon geen plek
om te schrijven. Zonder JS doet dezelfde link hetzelfde.

/search/remote levert het fragment, achter dezelfde grens als de volle
pagina: alleen wie de site beheert laat ophalen. Die grens weegt hier zwaarder,
want deze route wordt bij elke toetsaanslag geraakt; zonder hem is hij een
haalservice die iedereen deze server op adressen naar keuze laat afsturen.
Voor een bezoeker 204, en dan valt de zoekbalk terug op de gewone suggesties.
Elke toetsaanslag krijgt een volgnummer, zodat een traag antwoord op een oude
vraag niet overschrijft wat je inmiddels hebt getypt.

Waarderen en boosten ter plekke verhuisde van authorize-interaction.js naar
chrome.js: de kaart staat nu op elke pagina, via de zoekbalk. De zoekpagina
stuurde je bij een like eerder weg naar /authorize_interaction.

Onderweg: /authorize_interaction haalt nu ook ondertekend op, net als de
zoekbalk. Anders zegt die pagina "niet gevonden" over een post voor volgers die
de preview wel liet zien.

Getoetst: de preview met de post, ondertekend; wat er in de compacte kaart wel
en niet staat; dat een bezoeker via de preview niets laat ophalen; dat een
zoekterm niets ophaalt; de waarschuwing; het venster op verzoek. Tegenproef:
rechtencheck eruit, waarschuwing genegeerd, compact genegeerd en anoniem
ophalen laten elk hun eigen toets omvallen. Volledige suite 1283 groen.

Het gedrag in chrome.js is in de browser nagelopen met een nagebootste
server: herkennen, laden, invoegen, de volgorde bij een traag antwoord, de
terugval bij 204, waarderen en boosten heen en terug, en het antwoordvenster
open en dicht met de focus op de goede plek.

shaer-utpi

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

  • Property mode set to 100644
File size: 14.3 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 live-preview: open-link onder de kaart, en de kaart zonder rand-marge. */
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 .ss-remote { padding: 4px 0 6px; }
166 .ss-remote-note { padding: .8rem .6rem; color: var(--ink-soft, var(--ink-muted)); font-size: .9rem; }
167 .ss-remote-loading { display: flex; align-items: center; gap: 10px; padding: .9rem .6rem; color: var(--ink-soft, var(--ink-muted)); font-size: .9rem; }
168 .ss-remote-loading::before { content: ''; width: 16px; height: 16px; border-radius: 50%; flex: 0 0 16px;
169 border: 2px solid color-mix(in srgb, var(--accent, #06c) 30%, transparent); border-top-color: var(--accent, #06c);
170 animation: ss-spin .8s linear infinite; }
171 @keyframes ss-spin { to { transform: rotate(360deg); } }
172 @media (prefers-reduced-motion: reduce) { .ss-remote-loading::before { animation: none; } }
173
174 /* Smal scherm: alleen de tekens, gelijk verdeeld over de breedte. De woorden
175 blijven bestaan voor wie het scherm voorgelezen krijgt. */
176 @media (max-width: 480px) {
177 .rp-card { padding: 12px 12px 2px; border-radius: 14px; }
178 .rp-actions { margin: 8px -4px 0; justify-content: space-between; }
179 .rp-act .rp-act-label { position: absolute; width: 1px; height: 1px; overflow: hidden;
180 clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
181 .rp-src { margin-left: 0; }
182 .rp-media-1 img { max-height: 360px; }
183 }
184</style>
Note: See TracBrowser for help on using the repository browser.