added default images for card ui & fixed ui
This commit is contained in:
BIN
src/assets/default-1.jpeg
Normal file
BIN
src/assets/default-1.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 788 KiB |
BIN
src/assets/default-2.jpeg
Normal file
BIN
src/assets/default-2.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 663 KiB |
BIN
src/assets/default-3.jpeg
Normal file
BIN
src/assets/default-3.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 566 KiB |
@@ -226,7 +226,7 @@
|
||||
{#each ['solo','friends','family'] as t}
|
||||
<label class="toggle-opt" class:active={tripType === t}>
|
||||
<input type="radio" name="nc-tripType" value={t} bind:group={tripType} />
|
||||
{t === 'solo' ? '🧑 Solo' : t === 'friends' ? '👥 With friends' : '👨👩👧👦 With family'}
|
||||
{t === 'solo' ? 'Solo' : t === 'friends' ? 'With friends' : 'With family'}
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
@@ -264,7 +264,7 @@
|
||||
|
||||
{#each questions as q, i}
|
||||
<div class="q-card">
|
||||
<p class="q-text">{q}{country.trim() ? ` in ${country}` : ''}</p>
|
||||
<p class="q-text">{q}</p>
|
||||
<textarea class="q-input" rows="3" placeholder="Your answer…" bind:value={answers[i]}></textarea>
|
||||
</div>
|
||||
{/each}
|
||||
@@ -422,22 +422,23 @@
|
||||
}
|
||||
.input:focus { border-color: var(--accent-border); }
|
||||
|
||||
.toggle-row { display: flex; gap: 10px; flex-wrap: wrap; }
|
||||
.toggle-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
.toggle-opt {
|
||||
display: flex; align-items: center; justify-content: center; gap: 8px;
|
||||
font-size: 16px; font-weight: 400; color: var(--text);
|
||||
padding: 12px 14px; border-radius: 10px;
|
||||
display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
|
||||
font-size: 14px; font-weight: 400; color: var(--text);
|
||||
padding: 16px 10px; border-radius: 10px;
|
||||
border: 1px solid var(--border);
|
||||
cursor: pointer; transition: border-color 0.15s, background 0.15s, color 0.15s, box-shadow 0.15s;
|
||||
background: var(--bg-subtle);
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
.toggle-opt input { display: none; }
|
||||
.toggle-opt.active { border-color: var(--accent); background: var(--accent-bg); color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
|
||||
.toggle-opt.active img { filter: brightness(0) saturate(100%) invert(27%) sepia(98%) saturate(1169%) hue-rotate(239deg) brightness(80%) contrast(92%); }
|
||||
|
||||
.transport-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
|
||||
.transport-img { width: 30px; height: 30px; object-fit: contain; flex-shrink: 0; }
|
||||
.transport-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
|
||||
.transport-img { width: 44px; height: 44px; object-fit: contain; flex-shrink: 0; }
|
||||
|
||||
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
|
||||
.tag {
|
||||
@@ -464,8 +465,8 @@
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.06);
|
||||
}
|
||||
.q-text {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: var(--text-h);
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
|
||||
@@ -42,10 +42,6 @@
|
||||
|
||||
<div class="pc-header">
|
||||
<span class="pc-brand">MAP JOURNAL</span>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="pc-share-icon">
|
||||
<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/>
|
||||
<path d="m8.59 13.51 6.83 3.98M15.41 6.51l-6.82 3.98"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div class="pc-hero">
|
||||
@@ -83,7 +79,10 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="pc-cta">Share your journey →</div>
|
||||
<svg class="pc-share-icon-corner" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/>
|
||||
<path d="m8.59 13.51 6.83 3.98M15.41 6.51l-6.82 3.98"/>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
|
||||
@@ -143,7 +142,13 @@
|
||||
letter-spacing: 0.2em;
|
||||
color: #a5b4fc;
|
||||
}
|
||||
.pc-share-icon { color: #a5b4fc; flex-shrink: 0; }
|
||||
.pc-share-icon-corner {
|
||||
position: absolute;
|
||||
bottom: 14px;
|
||||
right: 14px;
|
||||
color: #a5b4fc;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.pc-hero {
|
||||
position: relative;
|
||||
@@ -231,5 +236,6 @@
|
||||
letter-spacing: 0.04em;
|
||||
padding-top: 4px;
|
||||
border-top: 1px solid rgba(255,255,255,0.08);
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
<script>
|
||||
import { flagEmoji } from '../../shared/countries.js';
|
||||
import default1 from '../../../assets/default-1.jpeg';
|
||||
import default2 from '../../../assets/default-2.jpeg';
|
||||
import default3 from '../../../assets/default-3.jpeg';
|
||||
|
||||
/** @type {{ entry: import('../shared/types.js').JournalEntry, onClick: () => void }} */
|
||||
let { entry, onClick } = $props();
|
||||
|
||||
const defaults = [default1, default2, default3];
|
||||
|
||||
function formatDate(/** @type {string} */ iso) {
|
||||
return new Date(iso).toLocaleDateString('en-US', {
|
||||
month: 'short', day: 'numeric', year: 'numeric',
|
||||
});
|
||||
}
|
||||
|
||||
let mainPhoto = $derived(entry.photos[0] ?? null);
|
||||
// Pick a stable random default based on the entry id
|
||||
function defaultPhoto(id) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < id.length; i++) hash = (hash * 31 + id.charCodeAt(i)) >>> 0;
|
||||
return defaults[hash % defaults.length];
|
||||
}
|
||||
|
||||
let mainPhoto = $derived(entry.photos[0] ?? defaultPhoto(entry.id));
|
||||
let thumbPhotos = $derived(entry.photos.slice(1, 4));
|
||||
let extraCount = $derived(entry.photos.length > 4 ? entry.photos.length - 4 : 0);
|
||||
|
||||
@@ -29,10 +41,11 @@
|
||||
<div class="v-dot" aria-hidden="true"></div>
|
||||
|
||||
<div class="v-content">
|
||||
<!-- Country above card -->
|
||||
<!-- Country + cities above card -->
|
||||
<div class="above-card">
|
||||
<span class="flag">{flagEmoji(entry.location.country)}</span>
|
||||
<span class="country-name">{entry.location.country}</span>
|
||||
<span class="city-inline">· {entry.location.cities.join(', ')}</span>
|
||||
</div>
|
||||
|
||||
<!-- Card -->
|
||||
@@ -40,36 +53,10 @@
|
||||
onclick={onClick}
|
||||
onkeydown={(e) => e.key === 'Enter' && onClick()}>
|
||||
|
||||
<!-- Trip badge — top-right of card, outside photo -->
|
||||
<span class="trip-badge trip-badge--{entry.tripType}">
|
||||
{entry.tripType === 'solo' ? 'Solo' : entry.tripType === 'family' ? 'Family' : 'Friends'}
|
||||
</span>
|
||||
|
||||
<!-- Photos -->
|
||||
<div class="photo-grid" class:has-thumbs={thumbPhotos.length > 0}>
|
||||
<div class="photo-main">
|
||||
{#if mainPhoto}
|
||||
<img src={mainPhoto} alt="" loading="lazy"
|
||||
onerror={(e) => {
|
||||
e.currentTarget.style.display = 'none';
|
||||
e.currentTarget.nextElementSibling.style.display = 'flex';
|
||||
}} />
|
||||
<div class="photo-fallback" style="display:none">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2">
|
||||
<rect x="3" y="3" width="18" height="18" rx="3"/>
|
||||
<circle cx="8.5" cy="8.5" r="1.5"/>
|
||||
<path d="M21 15l-5-5L5 21"/>
|
||||
</svg>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="photo-fallback">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2">
|
||||
<rect x="3" y="3" width="18" height="18" rx="3"/>
|
||||
<circle cx="8.5" cy="8.5" r="1.5"/>
|
||||
<path d="M21 15l-5-5L5 21"/>
|
||||
</svg>
|
||||
</div>
|
||||
{/if}
|
||||
<img src={mainPhoto} alt="" loading="lazy" />
|
||||
</div>
|
||||
|
||||
{#if thumbPhotos.length > 0}
|
||||
@@ -99,18 +86,17 @@
|
||||
|
||||
<!-- Info bar -->
|
||||
<div class="card-info">
|
||||
<span class="city">{entry.location.cities.join(', ')}</span>
|
||||
<span class="days-label">{entry.days} {entry.days === 1 ? 'day' : 'days'}</span>
|
||||
<div class="meta">
|
||||
{#if entry.transport}
|
||||
<span class="transport-chip transport-chip--{entry.transport}">
|
||||
{@html transportIcons[entry.transport] ?? ''}
|
||||
{transportLabel}
|
||||
</span>
|
||||
<span class="dot-sep">·</span>
|
||||
{/if}
|
||||
<span>{formatDate(entry.date)}</span>
|
||||
<span class="dot-sep">·</span>
|
||||
<span>{entry.days} {entry.days === 1 ? 'day' : 'days'}</span>
|
||||
<span class="trip-badge trip-badge--{entry.tripType}">
|
||||
{entry.tripType === 'solo' ? 'Solo' : entry.tripType === 'family' ? 'Family' : 'Friends'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -172,6 +158,14 @@
|
||||
color: var(--text-h);
|
||||
letter-spacing: -0.2px;
|
||||
}
|
||||
.city-inline {
|
||||
font-size: 13px;
|
||||
font-weight: 300;
|
||||
color: var(--text-sub);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* ── Card ── */
|
||||
.entry-card {
|
||||
@@ -191,22 +185,18 @@
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
/* ── Trip badge — absolute top-right of card ── */
|
||||
/* ── Trip badge — inline in info bar ── */
|
||||
.trip-badge {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
z-index: 2;
|
||||
font-size: 11px;
|
||||
font-weight: 300;
|
||||
padding: 3px 10px;
|
||||
font-weight: 400;
|
||||
padding: 2px 8px;
|
||||
border-radius: 20px;
|
||||
letter-spacing: 0.04em;
|
||||
backdrop-filter: blur(6px);
|
||||
letter-spacing: 0.03em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.trip-badge--solo { background: rgba(245,158,11,0.85); color: #fff; }
|
||||
.trip-badge--friends { background: rgba(124,58,237,0.85); color: #fff; }
|
||||
.trip-badge--family { background: rgba(16,185,129,0.85); color: #fff; }
|
||||
.trip-badge--solo { background: rgba(245,158,11,0.12); color: #b45309; border: 1px solid rgba(245,158,11,0.25); }
|
||||
.trip-badge--friends { background: rgba(124,58,237,0.07); color: #7c3aed; border: 1px solid rgba(124,58,237,0.2); }
|
||||
.trip-badge--family { background: rgba(16,185,129,0.08); color: #059669; border: 1px solid rgba(16,185,129,0.2); }
|
||||
|
||||
/* ── Photo grid — fixed height, always consistent ── */
|
||||
.photo-grid {
|
||||
@@ -294,16 +284,12 @@
|
||||
padding: 10px 14px;
|
||||
background: var(--bg);
|
||||
border-top: 1px solid var(--border);
|
||||
gap: 8px;
|
||||
min-height: 44px;
|
||||
}
|
||||
.city {
|
||||
font-size: 13px;
|
||||
.days-label {
|
||||
font-size: 12px;
|
||||
font-weight: 300;
|
||||
color: var(--text);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--text-sub);
|
||||
}
|
||||
.meta {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user