release: v0.20.0
This commit is contained in:
179
app/globals.css
179
app/globals.css
@@ -5,6 +5,11 @@
|
||||
@import url('./themes/noir.css');
|
||||
@import url('./themes/monograph.css');
|
||||
@import url('./themes/studio-modern.css');
|
||||
@import url('./themes/kunsthalle.css');
|
||||
@import url('./themes/ma.css');
|
||||
@import url('./themes/cyanotype.css');
|
||||
@import url('./themes/salon.css');
|
||||
@import url('./themes/birch.css');
|
||||
|
||||
@import url('./tokens.css');
|
||||
@import url('./leaflet.css');
|
||||
@@ -27,7 +32,7 @@
|
||||
|
||||
.skip-link:focus {
|
||||
top: 0;
|
||||
outline: 2px solid var(--text-primary);
|
||||
outline: 2px solid var(--focus-ring);
|
||||
}
|
||||
|
||||
/* ── Screen-reader-only text ──────────────────────── */
|
||||
@@ -207,6 +212,32 @@
|
||||
/* 56px header + 48px original padding */
|
||||
}
|
||||
|
||||
/* Sticky footer: on a short page (a journal with two entries, the 404) the
|
||||
footer used to end wherever the content did, floating mid-viewport. The
|
||||
visitor chrome is a column whose <main> takes the spare height. Scoped to
|
||||
pages that carry that chrome — the admin, the setup screen and the site
|
||||
gate render straight into <body> and keep their own layout. The header,
|
||||
skip link, lightbox and dialogs are fixed or absolute, so they stay out of
|
||||
the column. */
|
||||
body:has(> #main-content) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
body:has(> #main-content) > .main {
|
||||
flex: 1 0 auto;
|
||||
/* A flex item with auto side margins shrinks to its content; the width
|
||||
puts it back to full width, --max-width still caps it. */
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body:has(> #main-content) > .footer {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Simple CSS Page Fade-In (Replaces Framer Motion).
|
||||
*
|
||||
* Opacity only — no `transform`. A transform on `.main` (even the identity
|
||||
@@ -391,6 +422,12 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The aperture sign inside EXIF lines (components/ExifText.tsx). Presets that
|
||||
set EXIF in capitals would otherwise print "Ƒ/4". */
|
||||
.exif-fsign {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/* ── Hero: Fullbleed Layout ─────────────────────── */
|
||||
.hero--fullbleed {
|
||||
position: relative;
|
||||
@@ -1537,6 +1574,13 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* The wall label (PhotoGrid's figcaption): number, caption, EXIF under the
|
||||
photo. Hidden unless a preset hangs its photos with one (kunsthalle), so
|
||||
every other preset lays out as if it were not there. */
|
||||
.photo-grid__label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hover-only overlays leave keyboard and touch visitors out (#696). A tile
|
||||
with keyboard focus shows its overlay like a hovered one, and on devices
|
||||
without hover — phones, and tablets wider than the 640px mobile rules — the
|
||||
@@ -1881,38 +1925,94 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ─ Passepartout photo frame ─ */
|
||||
[data-photo-frame='passepartout'] .photo-grid__item {
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
padding: 8px 8px 24px;
|
||||
margin-bottom: var(--grid-gap, 24px);
|
||||
background: #111;
|
||||
/* ─ Photo box inside a grid tile ─ */
|
||||
/* Covers the tile (the box next/image `fill` used to take from the tile
|
||||
itself) unless a frame sets the mat variables. Clips the hover zoom to the
|
||||
photo, so it cannot spill onto a mat. */
|
||||
.photo-grid__media {
|
||||
position: absolute;
|
||||
inset: var(--photo-mat, 0px) var(--photo-mat, 0px) var(--photo-mat-caption, 0px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'][data-theme='light'] .photo-grid__item {
|
||||
border-color: rgba(0, 0, 0, 0.1);
|
||||
background: #fff;
|
||||
/* ─ Passepartout photo frame ─ */
|
||||
/* A mat board around each photo, with the EXIF line printed in the wider
|
||||
bottom band like the caption under a print: always shown, never over the
|
||||
photo. The tile is the mat; PhotoGrid's .photo-grid__media holds the photo
|
||||
and is inset by the mat below (without a frame it covers the tile, the
|
||||
variables being unset). The geometry lives in these variables so the grain
|
||||
overlay and the justified row math (lib/justifiedRow.ts) inset by exactly
|
||||
the same amounts. Colours are the --mat-* tokens in tokens.css. */
|
||||
[data-photo-frame='passepartout'] .photo-grid {
|
||||
--photo-mat: 8px;
|
||||
--photo-mat-caption: 32px;
|
||||
--photo-mat-border: 1px;
|
||||
/* Everything around the photo, border included, across and down. */
|
||||
--photo-mat-x: calc(2 * (var(--photo-mat) + var(--photo-mat-border)));
|
||||
--photo-mat-y: calc(var(--photo-mat) + var(--photo-mat-caption) + 2 * var(--photo-mat-border));
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'] .photo-grid__item-exif {
|
||||
position: relative;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
right: auto;
|
||||
/* Also reaches the essay images, which share the class but have no mat. */
|
||||
[data-photo-frame='passepartout'] .photo-grid__item {
|
||||
border: 1px solid var(--mat-border);
|
||||
padding: 8px 8px 24px;
|
||||
margin-bottom: var(--grid-gap, 24px);
|
||||
background: var(--mat-bg);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'] .photo-grid .photo-grid__item {
|
||||
/* The aspect ratio a layout gives the tile (the photo's own in masonry) has
|
||||
to size the photo, not the photo plus its mat. */
|
||||
box-sizing: content-box;
|
||||
border-width: var(--photo-mat-border);
|
||||
padding: var(--photo-mat) var(--photo-mat) var(--photo-mat-caption);
|
||||
}
|
||||
|
||||
/* The rule above re-adds the masonry row spacing; these layouts space their
|
||||
rows with the grid or flex gap, and doubled it under this frame. */
|
||||
[data-photo-frame='passepartout'] .photo-grid--uniform .photo-grid__item,
|
||||
[data-photo-frame='passepartout'] .photo-grid--showcase .photo-grid__item,
|
||||
[data-photo-frame='passepartout'] .photo-grid--filmstrip .photo-grid__item,
|
||||
[data-photo-frame='passepartout'] .photo-grid--editorial-flow .photo-grid__item,
|
||||
[data-photo-frame='passepartout'] .photo-grid--justified .photo-grid__item {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Justified tiles fill a wrapper whose size already counts the mat. */
|
||||
[data-photo-frame='passepartout'] .photo-grid--justified .photo-grid__item {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'] .photo-grid .photo-grid__item-play {
|
||||
inset: var(--photo-mat) var(--photo-mat) var(--photo-mat-caption);
|
||||
}
|
||||
|
||||
/* Specific enough to beat the presets' own EXIF styles (noir, monograph,
|
||||
studio-modern), which are overlays meant for a frameless tile. */
|
||||
[data-photo-frame='passepartout'] .photo-grid .photo-grid__item-exif {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: auto;
|
||||
left: var(--photo-mat);
|
||||
right: var(--photo-mat);
|
||||
bottom: 0;
|
||||
height: var(--photo-mat-caption);
|
||||
line-height: var(--photo-mat-caption);
|
||||
padding: 0;
|
||||
background: none;
|
||||
padding: 8px 0 0;
|
||||
color: var(--text-muted);
|
||||
-webkit-backdrop-filter: none;
|
||||
backdrop-filter: none;
|
||||
transform: none;
|
||||
color: var(--mat-text);
|
||||
font-family: var(--font-caption);
|
||||
font-style: italic;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.02em;
|
||||
white-space: normal;
|
||||
opacity: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'] .photo-grid__item:hover .photo-grid__item-exif {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -1928,13 +2028,14 @@
|
||||
}
|
||||
|
||||
/* ─ Film grain overlay ─ */
|
||||
/* Over the photo only: the passepartout mat variables, 0 without a frame. */
|
||||
[data-grain='true'] .photo-grid__item::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
bottom: 24px;
|
||||
top: var(--photo-mat, 0px);
|
||||
left: var(--photo-mat, 0px);
|
||||
right: var(--photo-mat, 0px);
|
||||
bottom: var(--photo-mat-caption, 0px);
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
|
||||
background-size: 128px 128px;
|
||||
pointer-events: none;
|
||||
@@ -1942,15 +2043,6 @@
|
||||
mix-blend-mode: overlay;
|
||||
}
|
||||
|
||||
/* Grain without passepartout — fill the whole item */
|
||||
[data-grain='true'][data-photo-frame='none'] .photo-grid__item::after,
|
||||
[data-grain='true'][data-photo-frame='shadow'] .photo-grid__item::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
/* ── Gallery Aesthetics (all themes) ─────────────── */
|
||||
|
||||
/* Generous spacing — gallery exhibition feel */
|
||||
@@ -2015,7 +2107,7 @@
|
||||
|
||||
.hero__nav-link:hover {
|
||||
border-bottom-color: var(--accent);
|
||||
color: var(--accent);
|
||||
color: var(--accent-text);
|
||||
}
|
||||
|
||||
/* Album cards */
|
||||
@@ -2045,17 +2137,17 @@
|
||||
/* Accent hover effects (works with any accent color) */
|
||||
.header__nav-link:hover,
|
||||
.header__nav-link.active {
|
||||
color: var(--accent);
|
||||
color: var(--accent-text);
|
||||
border-bottom-color: var(--accent);
|
||||
}
|
||||
|
||||
.footer__link:hover {
|
||||
color: var(--accent);
|
||||
color: var(--accent-text);
|
||||
}
|
||||
|
||||
.scroll-to-top:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
color: var(--accent-text);
|
||||
}
|
||||
|
||||
/* ── Tablet (iPad, kleine Laptops) ─────────────────── */
|
||||
@@ -2151,8 +2243,13 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'] .photo-grid__item {
|
||||
padding: 6px 6px 18px;
|
||||
[data-photo-frame='passepartout'] .photo-grid {
|
||||
--photo-mat: 6px;
|
||||
--photo-mat-caption: 26px;
|
||||
}
|
||||
|
||||
[data-photo-frame='passepartout'] .photo-grid .photo-grid__item-exif {
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
|
||||
/* Minimal: adjust fullbleed hero for mobile */
|
||||
|
||||
Reference in New Issue
Block a user