Skip to content

Commit 2c11d5c

Browse files
committed
feat(share-public): folder gallery UI in share.html
Replaces the placeholder with a gallery rendered by publicShare.js against the new public endpoints. - Grid / list view toggle (localStorage) - Image thumbs and lazy-loaded video posters - Click-to-open lightbox with Esc / arrow nav - ZIP download for the current folder - Subfolder navigation via URL hash, History API for back share.html itself only adds an icons.js module import and empties #share-folder for JS to populate.
1 parent 3256681 commit 2c11d5c

3 files changed

Lines changed: 942 additions & 46 deletions

File tree

static/css/views/share-public.css

Lines changed: 388 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,391 @@ FIXME: use components/buttons.css ?
144144
padding: 1.5rem;
145145
}
146146
}
147+
148+
/* ── Folder gallery ────────────────────────────────────────────── */
149+
body.gallery-mode {
150+
align-items: flex-start;
151+
padding: 1.5rem 1rem;
152+
}
153+
body.gallery-mode .share-card {
154+
max-width: 1100px;
155+
padding: 1.75rem 1.5rem 2.5rem;
156+
text-align: left;
157+
}
158+
body.gallery-mode .share-logo {
159+
margin-bottom: 1rem;
160+
text-align: center;
161+
}
162+
163+
#share-folder {
164+
width: 100%;
165+
}
166+
167+
.gallery-loading,
168+
.gallery-empty,
169+
.gallery-error {
170+
text-align: center;
171+
color: var(--color-text-gray);
172+
padding: 3rem 1rem;
173+
border: 1px dashed var(--color-border);
174+
border-radius: var(--radius, 12px);
175+
}
176+
.gallery-error {
177+
color: var(--color-error-text);
178+
}
179+
180+
.gallery-header {
181+
display: flex;
182+
flex-wrap: wrap;
183+
align-items: center;
184+
gap: 0.75rem;
185+
margin-bottom: 1rem;
186+
}
187+
.gallery-title {
188+
flex: 1 1 200px;
189+
font-size: 1.25rem;
190+
font-weight: 600;
191+
margin: 0;
192+
word-break: break-word;
193+
color: var(--color-text-heading);
194+
}
195+
.gallery-actions {
196+
display: flex;
197+
flex-wrap: wrap;
198+
align-items: center;
199+
gap: 0.5rem;
200+
}
201+
.gallery-back {
202+
display: inline-flex;
203+
align-items: center;
204+
gap: 0.4rem;
205+
text-decoration: none;
206+
color: var(--color-text-heading);
207+
font-size: 0.85rem;
208+
padding: 0.4rem 0.85rem;
209+
border-radius: 999px;
210+
background: var(--color-bg-hover);
211+
border: 1px solid var(--color-border);
212+
transition: background 0.15s;
213+
}
214+
.gallery-back:hover {
215+
background: var(--color-border);
216+
}
217+
218+
.gallery-view-toggle {
219+
display: inline-flex;
220+
background: var(--color-bg-hover);
221+
border: 1px solid var(--color-border);
222+
border-radius: 999px;
223+
padding: 3px;
224+
}
225+
.gallery-view-toggle button {
226+
background: transparent;
227+
border: none;
228+
color: var(--color-text-gray);
229+
padding: 0.35rem 0.75rem;
230+
border-radius: 999px;
231+
cursor: pointer;
232+
font-size: 0.85rem;
233+
display: inline-flex;
234+
align-items: center;
235+
transition:
236+
background 0.15s,
237+
color 0.15s;
238+
}
239+
.gallery-view-toggle button[aria-pressed="true"] {
240+
background: var(--color-primary);
241+
color: var(--color-bg-surface);
242+
}
243+
.gallery-zip {
244+
display: inline-flex;
245+
align-items: center;
246+
gap: 0.45rem;
247+
padding: 0.55rem 1rem;
248+
border-radius: 999px;
249+
width: auto;
250+
font-size: 0.85rem;
251+
}
252+
253+
.gallery-section-title {
254+
font-size: 0.75rem;
255+
font-weight: 600;
256+
text-transform: uppercase;
257+
letter-spacing: 0.5px;
258+
color: var(--color-text-gray);
259+
margin: 1.25rem 0 0.5rem;
260+
}
261+
262+
.gallery-folders {
263+
display: grid;
264+
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
265+
gap: 0.6rem;
266+
}
267+
.folder-card {
268+
display: flex;
269+
align-items: center;
270+
gap: 0.75rem;
271+
padding: 0.75rem 0.85rem;
272+
background: var(--color-bg-hover);
273+
border: 1px solid var(--color-border);
274+
border-radius: 12px;
275+
color: var(--color-text-heading);
276+
text-decoration: none;
277+
transition:
278+
background 0.15s,
279+
transform 0.15s;
280+
}
281+
.folder-card:hover {
282+
background: var(--color-border);
283+
transform: translateY(-1px);
284+
}
285+
.folder-card .folder-icon {
286+
width: 28px;
287+
height: 28px;
288+
color: var(--color-primary);
289+
}
290+
.folder-card .card-name {
291+
font-size: 0.9rem;
292+
font-weight: 500;
293+
overflow: hidden;
294+
text-overflow: ellipsis;
295+
white-space: nowrap;
296+
}
297+
.folder-card .card-meta {
298+
font-size: 0.75rem;
299+
color: var(--color-text-gray);
300+
}
301+
302+
.gallery-files {
303+
display: grid;
304+
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
305+
gap: 0.75rem;
306+
}
307+
.file-card {
308+
display: block;
309+
background: var(--color-bg-hover);
310+
border: 1px solid var(--color-border);
311+
border-radius: 12px;
312+
color: var(--color-text-heading);
313+
text-decoration: none;
314+
overflow: hidden;
315+
transition:
316+
background 0.15s,
317+
transform 0.15s,
318+
box-shadow 0.15s;
319+
}
320+
.file-card:hover {
321+
background: var(--color-border);
322+
transform: translateY(-2px);
323+
box-shadow: 0 8px 20px -10px var(--color-shadow-sm);
324+
}
325+
.file-thumb {
326+
width: 100%;
327+
aspect-ratio: 4 / 3;
328+
background: var(--color-bg-surface);
329+
position: relative;
330+
overflow: hidden;
331+
}
332+
.file-thumb img,
333+
.file-thumb video {
334+
position: absolute;
335+
inset: 0;
336+
width: 100%;
337+
height: 100%;
338+
object-fit: cover;
339+
display: block;
340+
}
341+
.file-thumb video {
342+
pointer-events: none;
343+
background: #000;
344+
}
345+
.file-thumb .file-type-icon {
346+
position: absolute;
347+
inset: 0;
348+
margin: auto;
349+
width: 48px;
350+
height: 48px;
351+
color: var(--color-text-gray);
352+
}
353+
.file-thumb .video-marker {
354+
position: absolute;
355+
inset: 0;
356+
display: grid;
357+
place-items: center;
358+
pointer-events: none;
359+
}
360+
.file-thumb .video-marker::before {
361+
content: "▶";
362+
color: rgba(255, 255, 255, 0.95);
363+
font-size: 28px;
364+
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
365+
}
366+
.file-card .card-body {
367+
padding: 0.5rem 0.7rem 0.65rem;
368+
min-width: 0;
369+
}
370+
.file-card .card-name {
371+
font-size: 0.85rem;
372+
font-weight: 500;
373+
overflow: hidden;
374+
text-overflow: ellipsis;
375+
white-space: nowrap;
376+
}
377+
.file-card .card-meta {
378+
font-size: 0.75rem;
379+
color: var(--color-text-gray);
380+
margin-top: 2px;
381+
}
382+
383+
/* ── List view ───────────────────────────────────────────────── */
384+
body[data-share-view="list"] .gallery-files {
385+
display: block;
386+
}
387+
body[data-share-view="list"] .file-card {
388+
display: flex;
389+
align-items: center;
390+
gap: 0.75rem;
391+
padding: 0.5rem 0.75rem;
392+
margin-bottom: 0.35rem;
393+
border-radius: 10px;
394+
}
395+
body[data-share-view="list"] .file-card:hover {
396+
transform: none;
397+
}
398+
body[data-share-view="list"] .file-thumb {
399+
width: 44px;
400+
height: 44px;
401+
aspect-ratio: 1 / 1;
402+
flex: none;
403+
border-radius: 8px;
404+
}
405+
body[data-share-view="list"] .file-thumb .file-type-icon {
406+
width: 24px;
407+
height: 24px;
408+
}
409+
body[data-share-view="list"] .file-thumb .video-marker::before {
410+
font-size: 14px;
411+
}
412+
body[data-share-view="list"] .file-card .card-body {
413+
padding: 0;
414+
flex: 1 1 auto;
415+
min-width: 0;
416+
}
417+
418+
/* ── Lightbox ──────────────────────────────────────────────────── */
419+
.lightbox {
420+
position: fixed;
421+
inset: 0;
422+
background: rgba(0, 0, 0, 0.92);
423+
display: flex;
424+
flex-direction: column;
425+
z-index: 1000;
426+
animation: lb-fade 180ms ease;
427+
}
428+
.lightbox.hidden {
429+
display: none;
430+
}
431+
@keyframes lb-fade {
432+
from {
433+
opacity: 0;
434+
}
435+
to {
436+
opacity: 1;
437+
}
438+
}
439+
.lb-bar {
440+
display: flex;
441+
align-items: center;
442+
gap: 0.5rem;
443+
padding: 0.75rem 1rem;
444+
color: rgba(255, 255, 255, 0.9);
445+
}
446+
.lb-title {
447+
flex: 1 1 auto;
448+
font-size: 0.9rem;
449+
overflow: hidden;
450+
text-overflow: ellipsis;
451+
white-space: nowrap;
452+
}
453+
.lb-bar a,
454+
.lb-bar button {
455+
background: rgba(255, 255, 255, 0.12);
456+
color: rgba(255, 255, 255, 0.95);
457+
border: none;
458+
border-radius: 999px;
459+
padding: 0.5rem 0.85rem;
460+
font-size: 0.85rem;
461+
text-decoration: none;
462+
cursor: pointer;
463+
display: inline-flex;
464+
align-items: center;
465+
transition: background 0.15s;
466+
}
467+
.lb-bar a:hover,
468+
.lb-bar button:hover {
469+
background: rgba(255, 255, 255, 0.22);
470+
}
471+
.lb-stage {
472+
flex: 1 1 auto;
473+
display: flex;
474+
align-items: center;
475+
justify-content: center;
476+
padding: 0 1rem 1.5rem;
477+
position: relative;
478+
min-height: 0;
479+
min-width: 0;
480+
overflow: hidden;
481+
}
482+
.lb-content {
483+
width: 100%;
484+
height: 100%;
485+
max-width: 100%;
486+
max-height: 100%;
487+
display: flex;
488+
align-items: center;
489+
justify-content: center;
490+
min-width: 0;
491+
min-height: 0;
492+
}
493+
.lb-content img,
494+
.lb-content video {
495+
max-width: 100%;
496+
max-height: 100%;
497+
width: auto;
498+
height: auto;
499+
object-fit: contain;
500+
background: #000;
501+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
502+
}
503+
.lb-nav {
504+
position: absolute;
505+
top: 50%;
506+
transform: translateY(-50%);
507+
background: rgba(255, 255, 255, 0.12);
508+
color: rgba(255, 255, 255, 0.95);
509+
border: none;
510+
width: 44px;
511+
height: 44px;
512+
border-radius: 50%;
513+
cursor: pointer;
514+
display: grid;
515+
place-items: center;
516+
transition: background 0.15s;
517+
}
518+
.lb-nav:hover {
519+
background: rgba(255, 255, 255, 0.22);
520+
}
521+
.lb-nav:disabled {
522+
opacity: 0.3;
523+
cursor: default;
524+
}
525+
.lb-prev {
526+
left: 1rem;
527+
}
528+
.lb-next {
529+
right: 1rem;
530+
}
531+
.lb-nav .oxi-icon {
532+
width: 16px;
533+
height: 16px;
534+
}

0 commit comments

Comments
 (0)