Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 117 additions & 21 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,55 @@
flex-shrink: 0;
}

.sheet-header {
display: flex;
align-items: center;
padding: 0 8px 10px 16px;
flex-shrink: 0;
gap: 4px;
}

.sheet-title {
font-size: 10.5px;
font-weight: 600;
color: var(--muted-light);
letter-spacing: 0.1em;
text-transform: uppercase;
padding: 0 16px 10px;
flex-shrink: 0;
flex: 1;
cursor: pointer;
user-select: none;
}

.sheet-header-actions {
display: flex;
gap: 2px;
}

.sheet-action {
width: 28px;
height: 28px;
border: none;
background: transparent;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: var(--muted-light);
transition: background 0.15s, color 0.15s;
padding: 0;
}
.sheet-action:active { background: var(--warm-sand); }
.sheet-action.active { color: var(--terracotta); background: var(--warm-sand); }

.sheet-collapse-icon {
transition: transform 0.2s;
}
.sheet.collapsed .sheet-collapse-icon {
transform: rotate(180deg);
}
.sheet.collapsed .gem-list {
display: none;
}

.gem-list {
Expand Down Expand Up @@ -879,8 +920,26 @@ <h1>Hidden Gems</h1>
</div>

<div class="sheet" id="sheet">
<div class="sheet-handle"></div>
<div class="sheet-title" id="sheetTitle">Your gems</div>
<div class="sheet-handle" onclick="toggleSheet()"></div>
<div class="sheet-header">
<div class="sheet-title" id="sheetTitle" onclick="toggleSheet()">Your gems</div>
<div class="sheet-header-actions">
<button class="sheet-action" id="viewportFilterBtn" onclick="toggleViewportFilter()" title="Show only gems visible on map">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
<circle cx="8" cy="8" r="5"/>
<line x1="8" y1="1" x2="8" y2="3.5"/>
<line x1="8" y1="12.5" x2="8" y2="15"/>
<line x1="1" y1="8" x2="3.5" y2="8"/>
<line x1="12.5" y1="8" x2="15" y2="8"/>
</svg>
</button>
<button class="sheet-action" id="sheetCollapseBtn" onclick="toggleSheet()" title="Collapse list">
<svg class="sheet-collapse-icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 6l4 4 4-4"/>
</svg>
</button>
</div>
</div>
<div class="gem-list" id="gemList">
<div class="empty-state"><span>🌿</span>Tap + to add your first hidden gem</div>
</div>
Expand Down Expand Up @@ -1047,28 +1106,65 @@ <h1>Hidden Gems</h1>

// ── List ──────────────────────────────────────────────────────────────────────

let filterByViewport = false;

function toggleSheet() {
document.getElementById('sheet').classList.toggle('collapsed');
}

function toggleViewportFilter() {
filterByViewport = !filterByViewport;
document.getElementById('viewportFilterBtn').classList.toggle('active', filterByViewport);
if (filterByViewport) {
map.on('moveend zoomend', renderList);
} else {
map.off('moveend zoomend', renderList);
}
renderList();
}

function renderList() {
const list = document.getElementById('gemList');
const title = document.getElementById('sheetTitle');
title.textContent = gems.length === 1 ? '1 gem' : `${gems.length} gems`;
if (gems.length === 0) {
list.innerHTML = `<div class="empty-state">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<polygon points="24,4 42,14 42,34 24,44 6,34 6,14" stroke="#2d6a4f" stroke-width="2" fill="none"/>
<polygon points="24,4 42,14 24,24" fill="#2d6a4f" opacity="0.3"/>
<polygon points="24,4 6,14 24,24" fill="#2d6a4f" opacity="0.15"/>
<polygon points="6,14 24,24 6,34" fill="#2d6a4f" opacity="0.12"/>
<polygon points="42,14 24,24 42,34" fill="#2d6a4f" opacity="0.22"/>
<polygon points="24,24 6,34 24,44" fill="#2d6a4f" opacity="0.1"/>
<polygon points="24,24 42,34 24,44" fill="#2d6a4f" opacity="0.18"/>
<circle cx="24" cy="24" r="3" fill="#2d6a4f" opacity="0.5"/>
</svg>
<div class="empty-state-title">No gems yet</div>
<div class="empty-state-sub">Tap + to drop your first hidden gem on the map</div>
</div>`;

let visible = gems;
if (filterByViewport && map) {
const bounds = map.getBounds();
visible = gems.filter(g => g.lat && g.lng && bounds.contains([g.lat, g.lng]));
}

if (filterByViewport) {
title.textContent = `${visible.length} of ${gems.length} in view`;
} else {
title.textContent = gems.length === 1 ? '1 gem' : `${gems.length} gems`;
}

if (visible.length === 0) {
if (filterByViewport && gems.length > 0) {
list.innerHTML = `<div class="empty-state">
<div class="empty-state-title">No gems in this area</div>
<div class="empty-state-sub">Pan or zoom the map to find your gems</div>
</div>`;
} else {
list.innerHTML = `<div class="empty-state">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<polygon points="24,4 42,14 42,34 24,44 6,34 6,14" stroke="#2d6a4f" stroke-width="2" fill="none"/>
<polygon points="24,4 42,14 24,24" fill="#2d6a4f" opacity="0.3"/>
<polygon points="24,4 6,14 24,24" fill="#2d6a4f" opacity="0.15"/>
<polygon points="6,14 24,24 6,34" fill="#2d6a4f" opacity="0.12"/>
<polygon points="42,14 24,24 42,34" fill="#2d6a4f" opacity="0.22"/>
<polygon points="24,24 6,34 24,44" fill="#2d6a4f" opacity="0.1"/>
<polygon points="24,24 42,34 24,44" fill="#2d6a4f" opacity="0.18"/>
<circle cx="24" cy="24" r="3" fill="#2d6a4f" opacity="0.5"/>
</svg>
<div class="empty-state-title">No gems yet</div>
<div class="empty-state-sub">Tap + to drop your first hidden gem on the map</div>
</div>`;
}
return;
}
list.innerHTML = gems.map(g => {

list.innerHTML = visible.map(g => {
const thumb = g.photo_url
? `<img class="gem-photo-thumb" data-path="${g.photo_url}" src="" alt="" />`
: `<div class="gem-emoji">${g.emoji || '🌿'}</div>`;
Expand Down
Loading