Update marker size and restore marker font size
This commit is contained in:
57
index.html
57
index.html
@@ -188,7 +188,7 @@ body { font-family: 'Segoe UI', sans-serif; display: flex; height: 100vh; color:
|
||||
|
||||
.num-marker {
|
||||
background: #2b6cb0; color: #fff; border-radius: 50%;
|
||||
width: 28px; height: 28px; display: flex; align-items: center;
|
||||
width: 34px; height: 34px; display: flex; align-items: center;
|
||||
justify-content: center; font-size: 12px; font-weight: 700;
|
||||
border: 3px solid #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
||||
cursor: pointer;
|
||||
@@ -288,8 +288,9 @@ body { font-family: 'Segoe UI', sans-serif; display: flex; height: 100vh; color:
|
||||
|
||||
<div class="modal-overlay" id="name-edit-modal">
|
||||
<div class="modal-box">
|
||||
<h3>Edit Name</h3>
|
||||
<input type="text" id="name-edit-input" />
|
||||
<h3>Edit Flag</h3>
|
||||
<input type="text" id="name-edit-input" placeholder="Name" />
|
||||
<input type="text" id="phrase-edit-input" placeholder="Flag phrase (optional)" />
|
||||
<div class="modal-actions">
|
||||
<button id="name-edit-cancel">Cancel</button>
|
||||
<button id="name-edit-apply" class="btn-apply">Apply</button>
|
||||
@@ -481,7 +482,7 @@ document.getElementById('api-key-btn').addEventListener('click', () => {
|
||||
function makeNumIcon(num) {
|
||||
return L.divIcon({
|
||||
html: `<div class="num-marker">${num}</div>`,
|
||||
className: '', iconSize: [28, 28], iconAnchor: [14, 14]
|
||||
className: '', iconSize: [34, 34], iconAnchor: [17, 17]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -494,6 +495,11 @@ function esc(s) {
|
||||
({'&':'&','<':'<','>':'>','"':'"'})[c]);
|
||||
}
|
||||
|
||||
function getFlagTooltipText(flag) {
|
||||
if (!flag.name) return flag.phrase || '';
|
||||
return flag.phrase ? `${flag.name} · ${flag.phrase}` : flag.name;
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// ─── Photo ─────────────────────────────────────────────
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
@@ -559,7 +565,7 @@ function renderList() {
|
||||
<span class="status-dot ${flag.placed ? 'placed' : 'unplaced'}"></span>
|
||||
<div class="info">
|
||||
<div class="name">${esc(flag.name)}</div>
|
||||
<div class="detail">${flag.number ? '#' + esc(flag.number) : ''}${detailText ? ' · ' + detailText : ''}</div>
|
||||
<div class="detail">${flag.number ? '#' + esc(flag.number) : ''}${flag.phrase ? (flag.number ? ' · ' : '') + esc(flag.phrase) : ''}${detailText ? ((flag.number || flag.phrase) ? ' · ' : '') + detailText : ''}</div>
|
||||
</div>
|
||||
<span class="chevron ${flag.expanded ? 'open' : ''}">▾</span>
|
||||
<div class="actions">
|
||||
@@ -585,6 +591,10 @@ function renderList() {
|
||||
bHTML += `<div class="detail-row"><span class="label">Address:</span>
|
||||
<span>${flag.address ? esc(flag.address) : '<span class="address-loading">Loading…</span>'}</span></div>`;
|
||||
}
|
||||
if (flag.phrase) {
|
||||
bHTML += `<div class="detail-row"><span class="label">Phrase:</span>
|
||||
<span>${esc(flag.phrase)}</span></div>`;
|
||||
}
|
||||
bHTML += `<div class="photo-section"><div class="photo-label">📷 Photo</div>`;
|
||||
if (flag.photoPath) bHTML += `<div class="photo-preview"><img src="${flag.photoPath}" alt="Photo" /></div>`;
|
||||
bHTML += `<div class="photo-actions">
|
||||
@@ -634,8 +644,8 @@ function removeFlag(id) {
|
||||
renderList();
|
||||
}
|
||||
|
||||
function addFlag(name, number) {
|
||||
const flag = { id: nextId++, name, number,
|
||||
function addFlag(name, number, phrase = '') {
|
||||
const flag = { id: nextId++, name, number, phrase,
|
||||
placed: false, lat: null, lng: null, address: null,
|
||||
marker: null, expanded: false, photoPath: null };
|
||||
flags.push(flag);
|
||||
@@ -652,18 +662,24 @@ function openNameEdit(flagId) {
|
||||
if (!flag) return;
|
||||
editingFlagId = flagId;
|
||||
document.getElementById('name-edit-input').value = flag.name;
|
||||
document.getElementById('phrase-edit-input').value = flag.phrase || '';
|
||||
document.getElementById('name-edit-modal').classList.add('open');
|
||||
}
|
||||
|
||||
document.getElementById('name-edit-apply').addEventListener('click', () => {
|
||||
const flag = flags.find(f => f.id === editingFlagId);
|
||||
if (!flag) return;
|
||||
const val = document.getElementById('name-edit-input').value.trim();
|
||||
if (val) {
|
||||
flag.name = val;
|
||||
const nameVal = document.getElementById('name-edit-input').value.trim();
|
||||
const phraseVal = document.getElementById('phrase-edit-input').value.trim();
|
||||
if (nameVal) {
|
||||
flag.name = nameVal;
|
||||
flag.phrase = phraseVal;
|
||||
if (flag.marker) {
|
||||
flag.marker.unbindTooltip();
|
||||
flag.marker.bindTooltip(esc(flag.name), { permanent: true, direction: 'right', offset: [10, 0], className: 'flag-marker-tooltip' });
|
||||
const tooltipText = esc(getFlagTooltipText(flag));
|
||||
if (tooltipText) {
|
||||
flag.marker.bindTooltip(tooltipText, { permanent: true, direction: 'right', offset: [10, 0], className: 'flag-marker-tooltip' });
|
||||
}
|
||||
}
|
||||
renderList();
|
||||
}
|
||||
@@ -712,7 +728,8 @@ map.on('click', (e) => {
|
||||
const { lat, lng } = e.latlng;
|
||||
const displayNum = flag.number || flags.indexOf(flag) + 1;
|
||||
const marker = L.marker([lat, lng], { icon: makeNumIcon(displayNum), draggable: true }).addTo(map);
|
||||
if (flag.name) marker.bindTooltip(esc(flag.name), { permanent: true, direction: 'right', offset: [10, 0], className: 'flag-marker-tooltip' });
|
||||
const tooltipText = esc(getFlagTooltipText(flag));
|
||||
if (tooltipText) marker.bindTooltip(tooltipText, { permanent: true, direction: 'right', offset: [10, 0], className: 'flag-marker-tooltip' });
|
||||
marker.on('dragend', () => {
|
||||
const p = marker.getLatLng(); flag.lat = p.lat; flag.lng = p.lng;
|
||||
scheduleGeocode(flag); renderList();
|
||||
@@ -756,8 +773,9 @@ document.getElementById('file-input').addEventListener('change', async (e) => {
|
||||
for (const row of rows) {
|
||||
const name = row.Name || row.name || row.이름 || row['Flag Name'] || Object.values(row)[0] || '';
|
||||
const number = row.Number || row.number || row.숫자 || row['Flag Number'] || Object.values(row)[1] || '';
|
||||
const phrase = row.Phrase || row.phrase || row.문구 || row['Flag Phrase'] || row['Flag Text'] || row.Text || '';
|
||||
if (!String(name).trim()) continue;
|
||||
const flag = addFlag(String(name).trim(), String(number).trim());
|
||||
const flag = addFlag(String(name).trim(), String(number).trim(), String(phrase).trim());
|
||||
|
||||
const photo = row.Photo || row.photo || '';
|
||||
if (photo) flag.photoPath = String(photo);
|
||||
@@ -767,7 +785,8 @@ document.getElementById('file-input').addEventListener('change', async (e) => {
|
||||
if (!isNaN(lat) && !isNaN(lng)) {
|
||||
const displayNum = flag.number || flags.indexOf(flag) + 1;
|
||||
const marker = L.marker([lat, lng], { icon: makeNumIcon(displayNum), draggable: true }).addTo(map);
|
||||
if (flag.name) marker.bindTooltip(esc(flag.name), { permanent: true, direction: 'right', offset: [10, 0], className: 'flag-marker-tooltip' });
|
||||
const tooltipText = esc(getFlagTooltipText(flag));
|
||||
if (tooltipText) marker.bindTooltip(tooltipText, { permanent: true, direction: 'right', offset: [10, 0], className: 'flag-marker-tooltip' });
|
||||
marker.on('dragend', () => {
|
||||
const p = marker.getLatLng(); flag.lat = p.lat; flag.lng = p.lng;
|
||||
scheduleGeocode(flag); renderList();
|
||||
@@ -794,23 +813,23 @@ document.getElementById('file-input').addEventListener('change', async (e) => {
|
||||
document.getElementById('template-btn').addEventListener('click', () => {
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, XLSX.utils.json_to_sheet([
|
||||
{ Number: 'A001', Name: 'Flag 1' },
|
||||
{ Number: 'A002', Name: 'Flag 2' },
|
||||
{ Number: 'A003', Name: 'Flag 3' },
|
||||
{ Number: 'A001', Name: 'Flag 1', Phrase: 'Welcome message' },
|
||||
{ Number: 'A002', Name: 'Flag 2', Phrase: 'Sample phrase' },
|
||||
{ Number: 'A003', Name: 'Flag 3', Phrase: 'Another note' },
|
||||
]), 'Flags');
|
||||
XLSX.writeFile(wb, 'flag_template.xlsx');
|
||||
});
|
||||
|
||||
document.getElementById('export-btn').addEventListener('click', () => {
|
||||
const rows = flags.map(f => ({
|
||||
Number: f.number, Name: f.name,
|
||||
Number: f.number, Name: f.name, Phrase: f.phrase,
|
||||
Status: f.placed ? 'Placed' : 'Unplaced',
|
||||
Latitude: f.lat ?? '', Longitude: f.lng ?? '', Address: f.address ?? '',
|
||||
Photo: f.photoPath ?? '',
|
||||
}));
|
||||
const wb = XLSX.utils.book_new();
|
||||
const ws = XLSX.utils.json_to_sheet(rows);
|
||||
ws['!cols'] = [{ wch: 12 }, { wch: 20 }, { wch: 10 }, { wch: 12 }, { wch: 12 }, { wch: 60 }, { wch: 30 }];
|
||||
ws['!cols'] = [{ wch: 12 }, { wch: 20 }, { wch: 20 }, { wch: 10 }, { wch: 12 }, { wch: 12 }, { wch: 60 }, { wch: 30 }];
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Flags');
|
||||
XLSX.writeFile(wb, 'flag_export.xlsx');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user