Add network map UX and theme support.

Introduce network map view/components with filtering and positioning, expand contacts/map backend fields and migrations, and add a persistent light/dark theme toggle with graph label color updates for readability.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-28 13:24:48 +03:00
co-authored by Cursor
parent 81ba6cd076
commit b668ee8507
49 changed files with 4679 additions and 129 deletions
@@ -0,0 +1,103 @@
<template>
<div class="network-map-top-panel" :class="{ collapsed }">
<button
class="panel-toggle-btn"
@click="$emit('toggle-collapse')"
:title="collapsed ? 'Развернуть панель' : 'Свернуть панель'"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline v-if="!collapsed" points="18 15 12 9 6 15" />
<polyline v-else points="6 9 12 15 18 9" />
</svg>
</button>
<div class="network-map-header" v-show="!collapsed">
<div>
<h2>{{ title }}</h2>
<p class="network-map-sub">{{ subtitle }}</p>
</div>
<div class="flex gap-2">
<button class="btn btn-secondary btn-sm" @click="$emit('fit')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" />
</svg>
По центру
</button>
</div>
</div>
<div class="network-map-toolbar" v-show="!collapsed">
<slot name="filters" />
</div>
<div v-show="!collapsed">
<slot name="legend" />
</div>
</div>
</template>
<script setup>
defineProps({
collapsed: { type: Boolean, default: false },
title: { type: String, default: 'Карта сети' },
subtitle: {
type: String,
default:
'Три круга — поддержка, продуктивность, развитие. Секторы — сферы жизни. Толстая линия — частые контакты, пунктир — редкие. Стрелка — от инициатора связи.',
},
})
defineEmits(['toggle-collapse', 'fit'])
</script>
<style scoped>
.network-map-top-panel {
position: relative;
border-bottom: 1px solid var(--border);
}
.network-map-top-panel.collapsed {
height: 26px;
}
.panel-toggle-btn {
position: absolute;
top: 4px;
right: 8px;
z-index: 3;
width: 24px;
height: 18px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--surface-alt);
color: var(--text-muted);
display: grid;
place-items: center;
cursor: pointer;
}
.panel-toggle-btn:hover {
color: var(--text);
border-color: var(--accent);
}
.network-map-header {
flex-shrink: 0;
padding: 12px 28px 8px;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
}
.network-map-header h2 {
font-size: 18px;
font-weight: 600;
margin: 0 0 6px;
}
.network-map-sub {
margin: 0;
font-size: 13px;
color: var(--text-muted);
max-width: 640px;
line-height: 1.45;
}
.network-map-toolbar {
flex-shrink: 0;
padding: 0 28px 10px;
}
</style>