polish: chips bar + appearance menu placement + brand title (v0.2.2)

- appearance menu drops below the active-filter chips row when it is shown,
  and sits 10px further from the right edge
- "Скопировать ссылку" moved to the left of the chips, separated by a divider
- enlarge "Green Media" title so it is flush with the "Адресная программа"
  line below it

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
aaverbitskiy 2026-08-14 16:00:47 +00:00
parent aeb4651f6f
commit b4d56d0540
3 changed files with 33 additions and 21 deletions

View File

@ -1,7 +1,7 @@
{
"name": "mapdash-frontend",
"private": true,
"version": "0.2.1",
"version": "0.2.2",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -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);

View File

@ -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,