diff --git a/app.css b/app.css index 7154a04..30f4d3d 100644 --- a/app.css +++ b/app.css @@ -1113,6 +1113,134 @@ textarea.inline-edit { .streaming-info-num { font-size: 1.1rem; } } +/* ── Per-type bespoke: Map (stylish wayfinding card) ── */ +.card.wayfinding { overflow: hidden; } +.card.wayfinding .hd.hidden { display: none; } + +.map-frame { + padding: 1.75rem 1.75rem 0; +} + +/* Cartographic frame */ +.map-img-wrap { + position: relative; + border-radius: 12px; + overflow: hidden; + border: 3px solid color-mix(in oklab, var(--accent) 20%, var(--line)); + box-shadow: + 0 4px 16px rgba(0,0,0,.08), + inset 0 0 0 1px rgba(255,255,255,.04); + cursor: pointer; + transition: border-color .3s, box-shadow .3s; +} +.map-img-wrap:hover { + border-color: color-mix(in oklab, var(--accent) 40%, var(--line)); + box-shadow: + 0 8px 28px rgba(0,0,0,.12), + inset 0 0 0 1px rgba(255,255,255,.04); +} +.map-img { + width: 100%; + height: auto; + display: block; +} + +/* Location bar */ +.map-loc-bar { + display: flex; + align-items: center; + gap: .5rem; + padding: 1rem .25rem .75rem; + flex-wrap: wrap; +} +.map-pin { + font-size: 1.25rem; + line-height: 1; + flex-shrink: 0; +} +.map-loc-name { + font-size: 1.15rem; + font-weight: 700; + color: var(--ink); + letter-spacing: -.01em; + line-height: 1.3; +} +.map-type-chip { + margin-left: auto; + padding: .3rem .7rem; + border-radius: 100px; + background: color-mix(in oklab, var(--accent) 10%, var(--surface)); + border: 1px solid color-mix(in oklab, var(--accent) 18%, var(--line)); + font-size: .68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .06em; + color: var(--accent); +} + +/* Body */ +.card.wayfinding .bd { + padding: .5rem 1.75rem 2rem; +} +.card.wayfinding .bd::before { display: none; } + +/* Description */ +.map-description { + font-size: .88rem; + line-height: 1.7; + color: var(--ink-2); + margin-bottom: 1rem; +} + +/* Updated meta */ +.map-updated { + font-size: .75rem; + color: var(--muted); + margin-bottom: 1rem; +} +.map-updated-label { + font-weight: 700; + text-transform: uppercase; + letter-spacing: .08em; + font-size: .62rem; + color: var(--accent); + opacity: .8; +} + +/* CTA */ +.map-cta-wrap { + margin-top: .5rem; +} +.map-cta { + display: inline-flex; + align-items: center; + gap: .4rem; + padding: .6rem 1.3rem; + border-radius: 8px; + background: var(--accent); + color: #fff; + font-size: .85rem; + font-weight: 700; + text-decoration: none; + transition: transform .2s, box-shadow .2s, opacity .2s; + box-shadow: 0 2px 8px color-mix(in oklab, var(--accent) 30%, transparent); +} +.map-cta:hover { + transform: translateY(-2px); + box-shadow: 0 4px 16px color-mix(in oklab, var(--accent) 40%, transparent); + opacity: .95; +} +.map-cta:active { + transform: translateY(0); +} + +@media (max-width: 600px) { + .map-frame { padding: 1rem 1rem 0; } + .map-loc-name { font-size: 1rem; } + .map-type-chip { margin-left: 0; width: 100%; text-align: center; } + .card.wayfinding .bd { padding: .5rem 1rem 1.5rem; } +} + /* ── Per-type bespoke: Brand (bold brand identity hero) ── */ .card.brand-hero { overflow: hidden; diff --git a/app.js b/app.js index 7b58255..73f08d7 100644 --- a/app.js +++ b/app.js @@ -721,6 +721,116 @@ } } + // ── MAP (stylish wayfinding card) ── + if (cfg.type === "Map") { + const card = document.querySelector(".card"); + if (card) card.classList.add("wayfinding"); + + const heroMount = document.getElementById("hero-mount"); + const typeLabel = document.getElementById("type-label"); + const iconEl = document.getElementById("icon"); + + // Remove generic hero + heroMount.querySelector(".hero")?.remove(); + + // ── Cartographic frame around the map image ── + var imageData = data["image"]; + var mapName = data["name"] || ""; + + var mapFrame = document.createElement("div"); + mapFrame.className = "map-frame"; + + if (imageData) { + var imgWrap = document.createElement("div"); + imgWrap.className = "map-img-wrap"; + imgWrap.setAttribute("data-prop", "image"); + imgWrap.setAttribute("title", "Click to change image URL"); + imgWrap.setAttribute("tabindex", "0"); + var img = document.createElement("img"); + img.className = "map-img"; + img.src = imageData; + img.alt = mapName; + img.loading = "lazy"; + imgWrap.appendChild(img); + mapFrame.appendChild(imgWrap); + } + + // Location header with pin + place name + var locBar = document.createElement("div"); + locBar.className = "map-loc-bar"; + + var pin = document.createElement("span"); + pin.className = "map-pin"; + pin.textContent = "\u{1F4CD}"; + locBar.appendChild(pin); + + var nameSpan = document.createElement("span"); + nameSpan.className = "map-loc-name"; + nameSpan.textContent = mapName; + locBar.appendChild(nameSpan); + + // Map-type chip + var mapType = data["mapType"]; + if (mapType) { + var typeChip = document.createElement("span"); + typeChip.className = "map-type-chip"; + typeChip.textContent = mapType; + locBar.appendChild(typeChip); + handled.add("mapType"); + } + + mapFrame.appendChild(locBar); + + heroMount.appendChild(mapFrame); + + // Hide normal header + var hd = document.querySelector(".hd"); + if (hd) hd.classList.add("hidden"); + + // Mark handled props + handled.add("name"); + handled.add("image"); + + // ── Body: description + meta + CTA ── + + // Description + var desc = data["description"]; + if (desc) { + var descEl = document.createElement("div"); + descEl.className = "map-description"; + descEl.textContent = desc; + view.appendChild(descEl); + handled.add("description"); + } + + // Last updated meta + var dateMod = data["dateModified"]; + if (dateMod) { + var updated = document.createElement("div"); + updated.className = "map-updated"; + var formatted = formatDate(dateMod); + updated.innerHTML = "Last updated " + (formatted || dateMod); + view.appendChild(updated); + handled.add("dateModified"); + } + + // View full map CTA + var url = data["url"]; + if (url) { + var ctaWrap = document.createElement("div"); + ctaWrap.className = "map-cta-wrap"; + var cta = document.createElement("a"); + cta.className = "map-cta"; + cta.href = url; + cta.target = "_blank"; + cta.rel = "noopener"; + cta.innerHTML = "\u{1F5FA}\u{FE0F} View full map"; + ctaWrap.appendChild(cta); + view.appendChild(ctaWrap); + handled.add("url"); + } + } + // ── BRAND (bold brand identity hero) ── if (cfg.type === "Brand") { const card = document.querySelector(".card");