diff --git a/app.css b/app.css index 81ca47f..9a35fde 100644 --- a/app.css +++ b/app.css @@ -5540,3 +5540,187 @@ footer a:hover { color: var(--accent-2); } .cc-salary-box { margin: 0 1rem .6rem; padding: .6rem .8rem; } .cc-skill-section, .cc-qual-section, .cc-overview { padding-left: 1rem; padding-right: 1rem; } } + +/* ── TouristTrip — Travel Itinerary ── */ +.card.itinerary-card { + border-color: rgba(13,148,136,.12); + overflow: hidden; +} +.card.itinerary-card .hd.hidden { display: none; } + +/* Hero header */ +.ti-hero { + position: relative; + height: 260px; + overflow: hidden; +} +.ti-hero-img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.ti-hero-scrim { + position: absolute; + inset: 0; + background: linear-gradient(to bottom, + rgba(0,0,0,0) 0%, + rgba(0,0,0,.1) 40%, + rgba(0,0,0,.6) 70%, + rgba(0,0,0,.88) 100%); + pointer-events: none; +} +.ti-hero-overlay { + position: absolute; + bottom: 0; + left: 0; + right: 0; + padding: 0 1.5rem 1.2rem; + z-index: 2; +} +.ti-hero-icon { + font-size: 1.5rem; + display: block; + margin-bottom: .2rem; +} +.ti-hero-title { + font-size: 1.6rem; + font-weight: 800; + color: #fff; + line-height: 1.2; + letter-spacing: -.015em; + margin: 0; + text-shadow: 0 2px 12px rgba(0,0,0,.5); +} + +/* Trip-style chips */ +.ti-trip-chips { + display: flex; + flex-wrap: wrap; + gap: .35rem; + padding: .8rem 1.5rem .4rem; +} +.ti-trip-chip { + display: inline-flex; + align-items: center; + gap: .25rem; + font-size: .73rem; + font-weight: 600; + padding: .25rem .65rem; + border-radius: 4px; + background: rgba(13,148,136,.08); + color: #0d9488; + border: 1px solid rgba(13,148,136,.15); +} +.ti-chip-icon { + font-size: .8rem; +} + +/* Section label */ +.ti-section-label { + font-size: .7rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .12em; + color: var(--muted-2); + margin-bottom: .4rem; +} + +/* Vertical timeline */ +.ti-timeline { + padding: .6rem 1.5rem .4rem; + position: relative; +} +.ti-timeline::before { + content: ""; + position: absolute; + left: calc(1.5rem + 14px); + top: 1.2rem; + bottom: .8rem; + width: 2px; + background: linear-gradient(to bottom, #0d9488, #f59e0b); + border-radius: 1px; +} +.ti-timeline-stop { + display: flex; + gap: 1rem; + padding-bottom: 1rem; + position: relative; +} +.ti-timeline-dot { + flex-shrink: 0; + width: 30px; height: 30px; + border-radius: 50%; + background: linear-gradient(135deg, #0d9488, #14b8a6); + color: #fff; + font-size: .72rem; + font-weight: 800; + display: inline-flex; + align-items: center; + justify-content: center; + box-shadow: 0 2px 6px rgba(13,148,136,.3); + border: 2px solid var(--card-bg, #fff); + z-index: 1; +} +.ti-timeline-content { + flex: 1; + padding-top: .15rem; +} +.ti-timeline-label { + font-size: .72rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .1em; + color: #0d9488; + margin-bottom: .2rem; +} +.ti-timeline-body { + font-size: .82rem; + line-height: 1.65; + color: var(--ink-2); + margin: 0; +} + +/* Overview fallback */ +.ti-overview { + padding: .6rem 1.5rem .8rem; +} +.ti-overview-body { + font-size: .84rem; + line-height: 1.75; + color: var(--muted); + margin: 0; +} + +/* Book CTA */ +.ti-book-cta { + display: inline-flex; + align-items: center; + gap: .35rem; + margin: .4rem 1.5rem 1rem; + padding: .6rem 1.4rem; + background: linear-gradient(135deg, #0d9488, #f59e0b); + color: #fff; + font-size: .85rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: .03em; + border-radius: 6px; + text-decoration: none; + box-shadow: 0 3px 10px rgba(13,148,136,.3); + transition: filter .15s; +} +.ti-book-cta:hover { + filter: brightness(1.1); +} + +@media (max-width: 480px) { + .ti-hero { height: 200px; } + .ti-hero-title { font-size: 1.25rem; } + .ti-hero-overlay { padding: 0 1rem .8rem; } + .ti-trip-chips { padding: .6rem 1rem .3rem; } + .ti-timeline { padding: .5rem 1rem .3rem; } + .ti-timeline::before { left: calc(1rem + 14px); } + .ti-overview { padding: .5rem 1rem .6rem; } + .ti-book-cta { margin: .3rem 1rem .8rem; } +} diff --git a/app.js b/app.js index 8f14a68..5657357 100644 --- a/app.js +++ b/app.js @@ -3640,6 +3640,107 @@ } } + // ── TOURISTTRIP (Travel Itinerary) ── + if (cfg.type === "TouristTrip") { + const card = document.querySelector(".card"); + if (card) card.classList.add("itinerary-card"); + + // Hide normal header + const hd = document.querySelector(".hd"); + if (hd) hd.classList.add("hidden"); + + // Remove generic hero + const heroMount = document.getElementById("hero-mount"); + if (heroMount) heroMount.querySelector('.hero')?.remove(); + + // ── Hero header with trip name + image ── + const tiHeader = document.createElement("div"); tiHeader.className = "ti-hero"; + const imgUrl = data["image"]; + if (imgUrl) { + const img = document.createElement("img"); img.className = "ti-hero-img"; + img.src = imgUrl; img.alt = data[cfg.titleProp] || ""; + img.loading = "lazy"; + tiHeader.appendChild(img); + const scrim = document.createElement("div"); scrim.className = "ti-hero-scrim"; + tiHeader.appendChild(scrim); + handled.add("image"); + } + const tiOverlay = document.createElement("div"); tiOverlay.className = "ti-hero-overlay"; + const tiIcon = document.createElement("span"); tiIcon.className = "ti-hero-icon"; + tiIcon.textContent = "\u{1F9C3}"; + tiOverlay.appendChild(tiIcon); + const h1 = document.createElement("h1"); h1.className = "ti-hero-title"; + h1.textContent = data[cfg.titleProp] || ""; + tiOverlay.appendChild(h1); + tiHeader.appendChild(tiOverlay); + heroMount.appendChild(tiHeader); + handled.add("name"); + + // ── Trip-style chips from touristType ── + const touristType = data["touristType"]; + if (touristType) { + const chipRow = document.createElement("div"); chipRow.className = "ti-trip-chips"; + touristType.split(",").forEach(t => { + const chip = document.createElement("span"); chip.className = "ti-trip-chip"; + chip.innerHTML = "\u{1F6E9}\uFE0F " + t.trim(); + chipRow.appendChild(chip); + }); + view.appendChild(chipRow); + handled.add("touristType"); + } + + // ── Day-by-day timeline from description ── + const desc = data["description"]; + if (desc) { + // Parse "Day one: ... Day two: ..." or "Day 1: ... Day 2: ..." patterns + const dayParts = desc.split(/\s*Day\s+(?:one|two|three|four|five|six|seven|eight|1|2|3|4|5|6|7|8)[:.]?\s*/i) + .filter(s => s.trim()); + const dayLabels = desc.match(/Day\s+(?:one|two|three|four|five|six|seven|eight|1|2|3|4|5|6|7|8)[:.]?/gi); + + if (dayParts.length >= 2 && dayLabels && dayLabels.length >= 2) { + // Render as vertical timeline + const timeline = document.createElement("div"); timeline.className = "ti-timeline"; + dayParts.forEach((text, i) => { + const stop = document.createElement("div"); stop.className = "ti-timeline-stop"; + const dot = document.createElement("div"); dot.className = "ti-timeline-dot"; + dot.textContent = String(i + 1); + stop.appendChild(dot); + const content = document.createElement("div"); content.className = "ti-timeline-content"; + const label = document.createElement("div"); label.className = "ti-timeline-label"; + label.textContent = dayLabels[i] ? dayLabels[i].replace(/[:.]?$/, "") : ("Day " + (i + 1)); + content.appendChild(label); + const body = document.createElement("p"); body.className = "ti-timeline-body"; + body.textContent = text.trim(); + content.appendChild(body); + stop.appendChild(content); + timeline.appendChild(stop); + }); + view.appendChild(timeline); + } else { + // No day pattern — show as overview + const overview = document.createElement("div"); overview.className = "ti-overview"; + const label = document.createElement("div"); label.className = "ti-section-label"; + label.textContent = "Trip Overview"; + overview.appendChild(label); + const body = document.createElement("p"); body.className = "ti-overview-body"; + body.textContent = desc; + overview.appendChild(body); + view.appendChild(overview); + } + handled.add("description"); + } + + // ── Book This Trip CTA ── + const url = data["url"]; + if (url) { + const cta = document.createElement("a"); cta.className = "ti-book-cta"; + cta.href = url; cta.target = "_blank"; cta.rel = "noopener"; + cta.innerHTML = "\u2708\uFE0F Book This Trip \u2192"; + view.appendChild(cta); + handled.add("url"); + } + } + return handled; }