Files
Map-Jurnal/src/lib/timeline/detail/JournalSummary.svelte

199 lines
4.8 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
/** @type {{ entries: import('../shared/types.js').JournalEntry[] }} */
let { entries } = $props();
let stats = $derived.by(() => {
if (entries.length === 0) return null;
const totalDays = entries.reduce((s, e) => s + e.days, 0);
const countries = [...new Set(entries.map(e => e.location.country))];
const cities = [...new Set(entries.flatMap(e => e.location.cities))];
const years = entries.map(e => new Date(e.date).getFullYear());
const minYear = Math.min(...years);
const maxYear = Math.max(...years);
const yearRange = minYear === maxYear ? `${minYear}` : `${minYear} ${maxYear}`;
return { totalDays, countries, cities, yearRange, tripCount: entries.length };
});
</script>
{#if stats}
<div class="passport">
<!-- diagonal pattern -->
<div class="passport-body">
<!-- Left -->
<div class="passport-left">
<div class="passport-header">
<svg viewBox="0 0 32 32" fill="none" class="globe">
<circle cx="16" cy="16" r="13" stroke="currentColor" stroke-width="1.3"/>
<ellipse cx="16" cy="16" rx="5.5" ry="13" stroke="currentColor" stroke-width="1.3"/>
<line x1="3" y1="16" x2="29" y2="16" stroke="currentColor" stroke-width="1.3"/>
<line x1="5" y1="9" x2="27" y2="9" stroke="currentColor" stroke-width="1.3"/>
<line x1="5" y1="23" x2="27" y2="23" stroke="currentColor" stroke-width="1.3"/>
</svg>
<span class="issuer">TRAVEL JOURNAL</span>
</div>
<div>
<p class="type">PASSPORT</p>
<p class="years">{stats.yearRange}</p>
</div>
</div>
<div class="vdivider"></div>
<!-- Right -->
<div class="passport-right">
<div class="field">
<span class="field-label">TRIPS</span>
<span class="field-value">{stats.tripCount}</span>
</div>
<div class="field">
<span class="field-label">COUNTRIES</span>
<span class="field-value">{stats.countries.length}</span>
</div>
<div class="field">
<span class="field-label">DAYS</span>
<span class="field-value">{stats.totalDays}</span>
</div>
</div>
</div>
<!-- MRZ -->
<div class="mrz">
<span>P&lt;JNL{String(stats.tripCount).padStart(2,'0')}&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span>
<span>{stats.yearRange.replace(' ','').replace(/\s/g,'')}{'<'.repeat(12)}{String(stats.totalDays).padStart(4,'0')}</span>
</div>
</div>
{/if}
<style>
.passport {
background: #1e1b4b;
border-radius: 14px;
overflow: hidden;
color: #e0e7ff;
position: relative;
}
.passport::before {
content: '';
position: absolute;
inset: 0;
background: repeating-linear-gradient(
135deg,
transparent 0px, transparent 20px,
rgba(255,255,255,0.025) 20px, rgba(255,255,255,0.025) 21px
);
pointer-events: none;
}
/* Body: left + divider + right in a row */
.passport-body {
display: flex;
flex-direction: row;
align-items: stretch;
padding: 20px;
gap: 0;
position: relative;
z-index: 1;
}
/* Left column */
.passport-left {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 16px;
padding-right: 20px;
}
.passport-header {
display: flex;
align-items: center;
gap: 8px;
}
.globe {
width: 26px;
height: 26px;
color: #a5b4fc;
flex-shrink: 0;
}
.issuer {
font-size: 9px;
font-weight: 500;
letter-spacing: 0.18em;
color: #a5b4fc;
line-height: 1.4;
}
.type {
font-size: 10px;
font-weight: 500;
letter-spacing: 0.22em;
color: #818cf8;
margin-bottom: 4px;
}
.years {
font-size: 26px;
font-weight: 400;
color: #fff;
letter-spacing: -0.8px;
line-height: 1;
}
/* Divider */
.vdivider {
width: 1px;
background: rgba(255,255,255,0.12);
flex-shrink: 0;
align-self: stretch;
}
/* Right column */
.passport-right {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 10px;
padding-left: 20px;
}
.field {
display: flex;
flex-direction: column;
gap: 2px;
}
.field-label {
font-size: 8px;
font-weight: 500;
letter-spacing: 0.18em;
color: #818cf8;
}
.field-value {
font-size: 22px;
font-weight: 400;
color: #fff;
letter-spacing: -0.5px;
line-height: 1;
}
/* MRZ strip */
.mrz {
border-top: 1px solid rgba(255,255,255,0.1);
padding: 9px 20px;
background: rgba(0,0,0,0.18);
display: flex;
flex-direction: column;
gap: 2px;
position: relative;
z-index: 1;
}
.mrz span {
font-family: var(--mono);
font-size: 8px;
color: #6366f1;
letter-spacing: 0.06em;
white-space: nowrap;
overflow: hidden;
}
</style>