@@ -206,6 +243,12 @@
gap: 6px;
}
+ .label-row {
+ display: flex;
+ align-items: baseline;
+ justify-content: space-between;
+ }
+
.label {
font-size: 11px;
font-weight: 400;
@@ -214,6 +257,15 @@
color: var(--text-sub);
}
+ .char-count {
+ font-size: 11px;
+ font-weight: 300;
+ color: var(--text-sub);
+ transition: color 0.15s;
+ }
+ .char-count.over { color: #dc2626; }
+ .input-over { border-color: #fca5a5; }
+
.req {
color: var(--accent);
font-size: 11px;
diff --git a/src/lib/timeline/TimelineView.svelte b/src/lib/timeline/TimelineView.svelte
index c7e9668..5e79106 100644
--- a/src/lib/timeline/TimelineView.svelte
+++ b/src/lib/timeline/TimelineView.svelte
@@ -7,9 +7,18 @@
import JournalSummary from './JournalSummary.svelte';
import EditForm from './EditForm.svelte';
- let { onDetailChange = () => {} } = $props();
+ let { onDetailChange = () => {}, pendingCountry = '', onNewEntryClear = () => {} } = $props();
let selectedId = $state(/** @type {string|null} */(null));
- let view = $state(/** @type {'list'|'detail'|'edit'} */('list'));
+ let view = $state(/** @type {'list'|'detail'|'edit'|'new'} */('list'));
+
+ // When App passes a country from the map, open new-entry form automatically
+ $effect(() => {
+ if (pendingCountry) {
+ selectedId = null;
+ view = 'new';
+ onNewEntryClear();
+ }
+ });
let selected = $derived(selectedId ? (entries.find(e => e.id === selectedId) ?? null) : null);
let entries = $state(get(journals));
@@ -39,7 +48,11 @@
- {#if view === 'edit' && selected}
+ {#if view === 'new'}
+
+ { view = 'list'; onDetailChange(false); }} />
+
+ {:else if view === 'edit' && selected}
{ view = 'detail'; }} />
@@ -54,7 +67,15 @@
{:else}
-
My Journey
+
@@ -218,11 +239,37 @@
}
.sort-select:hover { border-color: var(--border-bright); color: var(--text-h); }
+ .page-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 16px;
+ }
+
.page-title {
font-size: var(--text-xl);
font-weight: 400;
color: var(--text-h);
letter-spacing: -0.5px;
- margin: 0 0 16px;
+ margin: 0;
}
+
+ .new-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-family: var(--sans);
+ font-size: 13px;
+ font-weight: 300;
+ color: #fff;
+ background: var(--accent);
+ border: 1px solid var(--accent);
+ border-radius: 8px;
+ padding: 7px 14px;
+ cursor: pointer;
+ transition: background 0.15s;
+ white-space: nowrap;
+ flex-shrink: 0;
+ }
+ .new-btn:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
diff --git a/src/lib/world-map/WorldMap.svelte b/src/lib/world-map/WorldMap.svelte
index 46571f4..41410c8 100644
--- a/src/lib/world-map/WorldMap.svelte
+++ b/src/lib/world-map/WorldMap.svelte
@@ -5,6 +5,8 @@
import worldData from 'world-atlas/countries-50m.json';
import { getSelected, toggle, setTotalCount } from '../layout/selection.svelte.js';
+ let { onCountryClick = (_name) => {} } = $props();
+
const TERRITORY_PARENT = {
'016': '840', '060': '826', '086': '826', '092': '826', '136': '826',
'184': '554', '234': '208', '238': '826', '239': '826', '248': '246',
@@ -60,6 +62,7 @@
.on('click', (event, d) => {
toggle(effId(d));
updateFill(d3.select(event.currentTarget));
+ onCountryClick(d.properties.name);
})
.on('mouseenter', (event, d) => {
d3.select(event.currentTarget).attr('fill', getSelected().has(effId(d)) ? '#16a34a' : '#f0f6fa');