added default images for card ui & fixed ui

This commit is contained in:
Haeri Kim
2026-06-16 21:55:29 +09:00
parent 9109d6a861
commit ed415a78a1
6 changed files with 62 additions and 69 deletions

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 KiB

BIN
src/assets/default-3.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 KiB

View File

@@ -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;

View File

@@ -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>

View File

@@ -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;