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:
parent
aeb4651f6f
commit
b4d56d0540
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "mapdash-frontend",
|
||||
"private": true,
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user