diff --git a/frontend/index.html b/frontend/index.html
index 77c3c3e..13c0ddc 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -123,9 +123,9 @@
diff --git a/frontend/package.json b/frontend/package.json
index 0e4603a..ef699d9 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "mapdash-frontend",
"private": true,
- "version": "0.2.10",
+ "version": "0.2.11",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index 792f595..6c112be 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -454,7 +454,7 @@ async function init(): Promise {
rebuildDecorMenu();
view.applyLayout();
await loadData(true);
- const defaultZoomIdx = 3;
+ const defaultZoomIdx = 1; // 12М
el.zoomSlider.value = String(defaultZoomIdx);
el.zoomLabel.textContent = zoomSteps[defaultZoomIdx]!.label;
view.setScale(zoomSteps[defaultZoomIdx]!.days);
diff --git a/frontend/src/map.ts b/frontend/src/map.ts
index c1b8114..2130bf9 100644
--- a/frontend/src/map.ts
+++ b/frontend/src/map.ts
@@ -301,22 +301,22 @@ function ensureMapPanel(): Panel {
function showMapPanel(surfaces: MapSurface[], idx: number, place: PanelPlace): void {
const p = ensureMapPanel();
- const firstOpen = p.el.style.display === 'none';
p.surfaces = surfaces;
- if (firstOpen) {
- // Fresh open: reset size. Widen when there are many surfaces so the tab list
- // flows into more columns (a shorter panel, less scrolling).
- p.el.style.height = '';
- p.el.style.maxHeight = '';
- const n = surfaces.length;
- const cols = n <= 8 ? 2 : n <= 24 ? 3 : 4;
- p.el.style.width = cols > 2 ? Math.min(320 + (cols - 2) * 150, Math.round(window.innerWidth * 0.92)) + 'px' : '';
- }
+ // Every click is a fresh panel: reset size, widen when there are many surfaces
+ // (tabs flow into more columns → shorter panel), then reposition next to the
+ // just-clicked cluster. A new click never reuses the previous position.
+ p.el.style.height = '';
+ p.el.style.maxHeight = '';
+ const n = surfaces.length;
+ const cols = n <= 8 ? 2 : n <= 24 ? 3 : 4;
+ p.el.style.width = cols > 2 ? Math.min(320 + (cols - 2) * 150, Math.round(window.innerWidth * 0.92)) + 'px' : '';
p.el.style.display = '';
renderPanel(idx);
- // Position only on a fresh open (measure the now-rendered size first, so we can
- // offset it toward the free side); keep position/size while it stays open.
- if (firstOpen) positionPanel(p.el, place);
+ positionPanel(p.el, place); // measures the rendered size, then offsets to the free side
+ // Restart the pop-in animation so each click reads as a new panel appearing.
+ p.el.style.animation = 'none';
+ void p.el.offsetHeight;
+ p.el.style.animation = '';
}
function closeMapPanel(): void {
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 7110ed3..20d78d0 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -460,6 +460,7 @@ html.role-pending .manager-only { display: none !important; }
background: var(--bg); border: 1px solid var(--border);
border-radius: var(--radius); box-shadow: var(--shadow-md);
font-size: 13px; color: var(--text);
+ animation: pop-in .13s var(--ease-3);
}
.mpanel-head {
position: sticky; top: 0; z-index: 1; background: var(--bg);
@@ -571,12 +572,14 @@ html.role-pending .manager-only { display: none !important; }
.vis-current-time { background-color: var(--today); }
/* Column resize handle */
+/* Matches #split-resizer: a 6px solid bar that turns accent on hover/drag, so
+ both dividers look identical. */
#col-resizer {
- position: absolute; top: 0; bottom: 0; width: 9px; margin-left: -4px;
- cursor: col-resize; z-index: 25; display: none;
+ position: absolute; top: 0; bottom: 0; width: 6px; margin-left: -3px;
+ background: var(--border); cursor: col-resize; z-index: 25; display: none;
+ transition: background var(--transition);
}
-#col-resizer::after { content: ""; position: absolute; top: 0; bottom: 0; left: 4px; width: 1px; background: var(--border); }
-#col-resizer:hover::after, #col-resizer.dragging::after { background: var(--accent); width: 2px; left: 3px; }
+#col-resizer:hover, #col-resizer.dragging { background: var(--accent); }
/* Hovered-month column highlight */
.vis-item.vis-background.month-hover-bg { background-color: var(--month-hover); }
diff --git a/frontend/src/timeline.ts b/frontend/src/timeline.ts
index fb49db5..402e855 100644
--- a/frontend/src/timeline.ts
+++ b/frontend/src/timeline.ts
@@ -28,16 +28,11 @@ export interface TimelineElements {
const PLANFIX_TASK_URL = 'https://green-media.planfix.ru/task/';
export const zoomSteps: ReadonlyArray<{ days: number; label: string }> = [
- { days: 91, label: '3 месяца' },
- { days: 183, label: '6 месяцев' },
- { days: 274, label: '9 месяцев' },
- { days: 365, label: '12 месяцев' },
- { days: 457, label: '15 месяцев' },
- { days: 548, label: '18 месяцев' },
- { days: 639, label: '21 месяц' },
- { days: 731, label: '24 месяца' },
- { days: 822, label: '27 месяцев' },
- { days: 913, label: '30 месяцев' },
+ { days: 183, label: '6М' },
+ { days: 365, label: '12М' },
+ { days: 548, label: '18М' },
+ { days: 731, label: '24М' },
+ { days: 913, label: '30М' },
];
const MONTH_BG_ID = '__month_hover_bg';