source: Klonkt/src/views/partials/shared-styles.ejs@ 3597763

main
Last change on this file since 3597763 was 7b04d3b, checked in by Robin <roboburr@…>, 7 weeks ago

Feature: Load more on News feed, page 72 (klonkt-demo-r9u, slice 1/4)

News (Krant) now pages in blocks of 72 (divisible by 2/3/4 so grid
columns stay full) with an htmx "Load more" button instead of a hard
60-item cap. getTimeline gains an offset arg; the route fetches 72+1 to
know whether the button belongs, and serves an append fragment
(partials/news-append) that swaps the next items beforeend into #tl-feed
and OOB-replaces the button with the next offset (or drops it on the
last page).

Reusable pieces for the other three views (Solo, Cirkel, Messages):

  • partials/load-more.ejs (the button + OOB wrapper)
  • partials/tl-item.ejs (extracted the timeline item so full page and append render identically)
  • .load-more-* CSS in shared-styles, i18n feed.load_more (NL/EN/DE)

Tests: feed-pagination.test.js (offset paging, no overlap, probe of
PAGE+1, past-end empty). Browser-verified: 72 -> 144 -> 150 then the
button disappears.

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

  • Property mode set to 100644
File size: 9.0 KB
Line 
1<style>
2/* ─────────────────────────────────────────────────
3 View switcher (timeline ↔ grid + grid-cols picker)
4 ───────────────────────────────────────────────── */
5.view-switcher-wrap {
6 border-bottom: 1px solid var(--rule);
7 background: var(--paper);
8 /* No extra margin-top: this centres the pill between the profile-header
9 rule (above) and the own border (below). Equal space above/below the
10 pill comes from the symmetric container padding below. The margin-bottom
11 (1.5rem in style.css) keeps breathing room toward the feed. */
12 margin-top: 0;
13}
14.view-switcher-wrap .container {
15 display: flex; align-items: center; justify-content: center; gap: 0.75rem;
16 /* Symmetric padding → equal space above and below the pill (≈8px),
17 centred between the two dividing lines. */
18 padding: 0.5rem 1rem;
19 max-width: 1200px; margin: 0 auto;
20 flex-wrap: wrap;
21}
22.view-switcher {
23 display: inline-flex;
24 background: var(--paper-2);
25 border: 1px solid var(--rule);
26 border-radius: 999px;
27 padding: 0.15rem;
28}
29.view-switch-btn {
30 display: inline-flex; align-items: center; gap: 0.35rem;
31 padding: 0.35rem 0.85rem;
32 border: 0; background: transparent; color: var(--ink-muted, var(--ink-soft));
33 cursor: pointer; border-radius: 999px;
34 font-size: 0.85rem; font-family: inherit;
35 transition: background 120ms, color 120ms;
36}
37.view-switch-btn:hover { color: var(--ink); }
38/* Active = white (light background, dark text). Via aria-selected (element
39 attribute, set by syncAria + on htmx:afterSettle) → htmx-robust. On non-
40 feed pages syncAria sets aria-selected=false → both grey. */
41.view-switch-btn[aria-selected="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); }
42
43/* Agenda = its OWN pill (separate from Timeline/Grid, so the feed-toggle is never
44 disturbed). Same look as the view-switcher pill. Visible in all modes. */
45.agenda-pill { display: inline-flex; align-items: center; } /* no box — standalone icon+text link */
46.vs-agenda {
47 display: inline-flex; align-items: center; gap: 0.4rem;
48 padding: 0.35rem 0.5rem;
49 color: var(--ink-muted, var(--ink-soft));
50 text-decoration: none;
51 font-size: 0.9rem; font-family: inherit;
52 transition: color 120ms;
53}
54.vs-agenda:hover { color: var(--ink); }
55/* Active (on the agenda page) = bright/white. Element-class (in the OOB-rendered
56 chrome) rather than body-class CSS → stays reliable after htmx navigation. */
57.vs-agenda.is-active { color: var(--ink); font-weight: 600; }
58
59/* Mobile: Agenda on its own row at the top, Solo/Circle + Timeline/Grid together
60 on the row below (together ~330px → fits within a phone, instead of the old
61 unbalanced split Agenda+Solo / Timeline). */
62@media (max-width: 520px) {
63 .view-switcher-wrap .agenda-pill { flex: 0 0 100%; justify-content: center; }
64}
65
66.grid-cols-picker {
67 display: none; /* desktop-only, see media query */
68 gap: 0.2rem;
69}
70.grid-cols-btn {
71 width: 28px; height: 28px;
72 border: 1px solid var(--rule);
73 background: var(--paper-2);
74 color: var(--ink-muted, var(--ink-soft));
75 border-radius: 4px;
76 font-size: 0.8rem; font-weight: 600;
77 cursor: pointer;
78 font-variant-numeric: tabular-nums;
79}
80.grid-cols-btn:hover { color: var(--ink); border-color: var(--accent); }
81.grid-cols-btn.is-active { background: var(--accent); color: white; border-color: var(--accent); }
82
83/* Show grid-cols picker only on grid view + desktop */
84@media (min-width: 720px) {
85 body[data-feed-view="grid"] .grid-cols-picker { display: inline-flex; }
86}
87
88/* Switcher is hidden only on admin pages — admin has a dedicated layout
89 and its own back-button flow where Tijdlijn/Grid is irrelevant. On
90 every other page (home, post, tag, archive, search, account) it stays
91 visible so the user keeps a consistent return-to-feed control. */
92.on-admin .view-switcher-wrap { display: none; }
93
94/* On a standalone post there is no feed to switch, so no button should look "active"
95 (coloured). The active state lives in style.css on body[data-feed-view]
96 / body[data-grid-cols] (background:var(--ink)); we override that MORE SPECIFICALLY
97 via body.on-post so the buttons become neutral/grey — but remain clickable
98 (the click-handler then navigates to the feed in that view). The
99 body-class switches client-side on HTMX-nav, so this works without a reload too. */
100body.on-post[data-feed-view="timeline"] .view-switch-btn[data-view="timeline"],
101body.on-post[data-feed-view="grid"] .view-switch-btn[data-view="grid"],
102body.on-post[data-grid-cols="2"] .grid-cols-btn[data-cols="2"],
103body.on-post[data-grid-cols="3"] .grid-cols-btn[data-cols="3"],
104body.on-post[data-grid-cols="4"] .grid-cols-btn[data-cols="4"] {
105 background: transparent;
106 color: var(--ink-muted, var(--ink-soft));
107 border-color: var(--rule);
108}
109
110
111/* Spacing between switcher-bar and the page content below.
112 .feed-timeline (used on home + archive + post-list pages) gets a top
113 margin so the first post doesn't collide with the switcher's border.
114 .feed-grid already has its own top spacing from grid-tile padding. */
115.view-switcher-wrap + #pcms-main .feed-timeline,
116.view-switcher-wrap + #pcms-main .container:first-child {
117 margin-top: 1.5rem;
118}
119
120/* Feed layout switching is in the v9 style.css (style.css):
121 .feed-timeline always rendered, .feed-grid hidden unless on-home + grid-mode. */
122
123/* ─────────────────────────────────────────────────
124 PWA install button (lives in topnav, hidden by default)
125 ───────────────────────────────────────────────── */
126#pwa-install-btn { color: var(--accent); }
127#pwa-install-btn:hover { background: var(--paper-2); }
128
129/* Shared button + form styles (used across pages) */
130.btn {
131 display: inline-flex;
132 align-items: center;
133 gap: 0.4rem;
134 padding: 0.55rem 1rem;
135 border: 1px solid var(--rule);
136 background: var(--paper-2);
137 color: var(--ink);
138 font-family: var(--font-ui, system-ui), sans-serif;
139 font-size: 0.9rem;
140 font-weight: 500;
141 text-decoration: none;
142 border-radius: 5px;
143 cursor: pointer;
144 transition: background 150ms, border-color 150ms;
145}
146.btn:hover { border-color: var(--accent); }
147.btn-primary { background: var(--accent); color: white; border-color: var(--accent); }
148.btn-primary:hover { opacity: 0.92; border-color: var(--accent); }
149.btn-success { background: #16a34a; color: white; border-color: #16a34a; }
150.btn-danger { background: #dc2626; color: white; border-color: #dc2626; }
151
152.alert { padding: 0.75rem 1rem; border-radius: 5px; margin-bottom: 1rem; }
153.alert-error { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
154.alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
155
156.auth-page { max-width: 420px; margin: 3rem auto; padding: 0 1rem; }
157.auth-page h1 { font-family: var(--font-display, serif); text-align: center; margin: 0 0 1.5rem; }
158.auth-form { display: flex; flex-direction: column; gap: 1rem; }
159.auth-form label { display: flex; flex-direction: column; gap: 0.3rem; }
160.auth-form label > span { font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); }
161.auth-form input { padding: 0.6rem 0.75rem; border: 1px solid var(--rule); border-radius: 4px; background: var(--paper); color: var(--ink); font-size: 1rem; }
162.auth-form .btn { justify-content: center; padding: 0.7rem; font-size: 1rem; margin-top: 0.5rem; }
163.auth-link { text-align: center; color: var(--ink-muted); font-size: 0.9rem; margin: 1rem 0 0; }
164.auth-link a { color: var(--accent); }
165.auth-intro { text-align: center; color: var(--ink-muted); font-size: 0.95rem; margin: 0 0 1rem; }
166.auth-divider { display: flex; align-items: center; gap: 0.75rem; margin: 1.25rem 0; color: var(--ink-muted); font-size: 0.85rem; }
167.auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--rule); }
168
169/* HTMX loading indicator */
170.pcms-loading {
171 display: none;
172 position: fixed;
173 top: 60px;
174 right: 1rem;
175 width: 24px;
176 height: 24px;
177 border: 3px solid var(--paper-2);
178 border-top-color: var(--accent);
179 border-radius: 50%;
180 animation: spin 0.8s linear infinite;
181 z-index: 1000;
182}
183.htmx-request .pcms-loading { display: block; }
184@keyframes spin { to { transform: rotate(360deg); } }
185
186/* Load more (Solo, Cirkel, News, Messages) — page size 72, htmx append. */
187.load-more-wrap { display: flex; justify-content: center; margin: 1.5rem 0 .5rem; }
188.load-more-wrap:empty { margin: 0; }
189.load-more-btn { padding: .6rem 1.4rem; border-radius: 999px; cursor: pointer;
190 font: inherit; font-weight: 600; color: var(--ink, inherit);
191 background: color-mix(in srgb, var(--ink, #000) 5%, transparent);
192 border: 1px solid color-mix(in srgb, var(--ink, #000) 14%, transparent); }
193.load-more-btn:hover { background: color-mix(in srgb, var(--ink, #000) 9%, transparent); }
194.load-more-btn.htmx-request { opacity: .6; pointer-events: none; }
195</style>
Note: See TracBrowser for help on using the repository browser.