diff --git a/frontend/package.json b/frontend/package.json index ad84e62..696d72d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "mapdash-frontend", "private": true, - "version": "0.2.1", + "version": "0.2.2", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 819b267..1a71496 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -184,8 +184,13 @@ function rebuildDecorMenu(): void { // closer than 30px to the window edge; overflow scrolls inside. function positionDecorMenu(): void { const header = document.querySelector('header'); - const headerBottom = header ? header.getBoundingClientRect().bottom : 0; - const top = headerBottom + 25; + let refBottom = header ? header.getBoundingClientRect().bottom : 0; + // Drop below the active-filter chips row too, when it is showing. + const chips = el.filterChips; + if (chips && chips.style.display !== 'none' && chips.getClientRects().length) { + refBottom = Math.max(refBottom, chips.getBoundingClientRect().bottom); + } + const top = refBottom + 25; el.decorMenu.style.top = top + 'px'; el.decorMenu.style.maxHeight = Math.max(120, window.innerHeight - top - 30) + 'px'; } @@ -275,6 +280,27 @@ function renderChips(): void { el.filterChips.innerHTML = ''; if (!items.length) { el.filterChips.style.display = 'none'; return; } el.filterChips.style.display = ''; + + // "Скопировать ссылку" — always leftmost, separated from the chips by a rule. + const share = document.createElement('button'); + share.type = 'button'; + share.className = 'chips-share'; + share.textContent = 'Скопировать ссылку'; + share.addEventListener('click', () => { + navigator.clipboard + ?.writeText(location.href) + .then(() => { + share.textContent = 'Ссылка скопирована'; + window.setTimeout(() => { share.textContent = 'Скопировать ссылку'; }, 1600); + }) + .catch(() => { /* clipboard unavailable */ }); + }); + el.filterChips.appendChild(share); + const divider = document.createElement('span'); + divider.className = 'chips-divider'; + divider.textContent = '|'; + el.filterChips.appendChild(divider); + for (const it of items) { const chip = document.createElement('span'); chip.className = 'chip'; @@ -294,21 +320,6 @@ function renderChips(): void { clear.textContent = 'Сбросить всё'; clear.addEventListener('click', resetFilters); el.filterChips.appendChild(clear); - - const share = document.createElement('button'); - share.type = 'button'; - share.className = 'chips-share'; - share.textContent = 'Скопировать ссылку'; - share.addEventListener('click', () => { - navigator.clipboard - ?.writeText(location.href) - .then(() => { - share.textContent = 'Ссылка скопирована'; - window.setTimeout(() => { share.textContent = 'Скопировать ссылку'; }, 1600); - }) - .catch(() => { /* clipboard unavailable */ }); - }); - el.filterChips.appendChild(share); } el.emptyResetTimeline.addEventListener('click', resetFilters); el.emptyResetMap.addEventListener('click', resetFilters); diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 413c623..fabc299 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -169,7 +169,7 @@ input::placeholder { color: var(--text-muted); } bottom, level with the date fields / mode switch. */ .hgroup-brand { align-items: stretch; } .brand { display: flex; flex-direction: column; justify-content: flex-start; line-height: 1.2; } -.brand-name { font-size: 18px; font-weight: 700; white-space: nowrap; } +.brand-name { font-size: 23px; font-weight: 700; white-space: nowrap; } .brand-sub { font-size: 15px; font-weight: 400; color: var(--text-muted); white-space: nowrap; } .field { display: flex; flex-direction: column; gap: var(--size-1); } @@ -258,7 +258,7 @@ input::placeholder { color: var(--text-muted); } .decor-menu { /* Fixed to the viewport: JS sets `top` (25px below the header) and `max-height` (ending ≥30px above the window bottom) on open, so it never overflows. */ - display: none; position: fixed; right: 18px; + display: none; position: fixed; right: 28px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-md); padding: var(--size-3); z-index: 50; width: max-content; max-width: min(420px, 92vw); overflow-y: auto; @@ -596,9 +596,10 @@ html.role-pending .manager-only { display: none !important; } .chips-share { border: none; background: transparent; color: var(--accent); cursor: pointer; font-size: 12px; font-weight: 500; padding: 3px 8px; border-radius: var(--radius-sm); - margin-left: auto; transition: background var(--transition); + transition: background var(--transition); } .chips-share:hover { background: var(--accent-weak); } +.chips-divider { color: var(--border-strong); font-weight: 400; user-select: none; } /* ---- polish: focus rings, animations, scrollbars, tabular figures ---- */ button:focus-visible, input[type=text]:focus-visible, input[type=date]:focus-visible,