MAPPEX: прототип межведомственного пункта наблюдения

Интерактивный дашборд по макету Figma «Government Dashboards»: карта РФ
(2D, вид с дрона в 3D, спутник, гибрид), ленты событий с вызовом ведомств
в 1 клик, ИИ-автопилот назначений, журнал, профиль, радар, статистика,
режимы «Ночное время», «Плохое зрение» и «Максимальная контрастность».
Vite + React + TypeScript, MapLibre GL, zustand. Лицензия MIT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Renat Usmanov
2026-10-23 12:59:45 +03:00
co-authored by Claude Opus 5.5
commit 57a4411f57
138 changed files with 10815 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Claude Code
.claude/
+8
View File
@@ -0,0 +1,8 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "oxc"],
"rules": {
"react/rules-of-hooks": "error",
"react/only-export-components": ["warn", { "allowConstantExport": true }]
}
}
+30
View File
@@ -0,0 +1,30 @@
MIT License
Copyright (c) 2026 YappiX
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---
The MIT License covers the source code only. Photos, the tax service emblem,
avatars and other images in src/assets/figma/ come from the design mockup and
are included for demonstration purposes only; they are not licensed for reuse.
Map data © OpenStreetMap contributors (via OpenFreeMap), satellite imagery ©
Esri and its partners. The Russian regions outline in public/data/ is derived
from click_that_hood by Code for Germany (MIT).
+97
View File
@@ -0,0 +1,97 @@
# MAPPEX Dashboards
Интерактивный прототип концепта «Межведомственный наблюдательный пункт»: МЧС, МВД, Минздрав и другие службы работают с единой базой, а ИИ-автопилот назначает исполнителей, если оператор не успел отреагировать.
- **Демо:** https://mappex.yappix.ru
- **Код:** https://git.myunion.pro/yappix-samples/mappex
- **Кейс:** https://yappix.ru/eksperimenty/mappex
- **Макет:** [Figma — Government Dashboards](https://www.figma.com/design/lvFq6m1GspPNv5PaDI6pu0/Government-Dashboards?node-id=0-1) (фреймы «Dashboard» и «Dashboard 3D Map», 3840×2160)
![2D-карта](docs/screen-2d.jpg)
## Запуск
```bash
npm install
npm run dev
```
Откройте http://localhost:5173. Сборка: `npm run build`, проверка: `npx tsc -b && npm run lint`.
Нужен интернет: подложка карты — векторные тайлы [OpenFreeMap](https://openfreemap.org) (данные © OpenStreetMap), спутник — Esri World Imagery. Ключи API не нужны.
## Развернуть у себя
Прототип собирается в статическую папку `dist/`, сервер с бэкендом не нужен.
```bash
git clone https://git.myunion.pro/yappix-samples/mappex.git
cd mappex
npm ci
npm run build
```
Папку `dist/` можно выложить на любой статический хостинг: nginx, Vercel, Netlify, GitHub Pages, S3. Для nginx есть готовый конфиг: [`deploy/nginx-mappex.yappix.ru.conf`](deploy/nginx-mappex.yappix.ru.conf). Скрипт [`deploy/publish.sh`](deploy/publish.sh) собирает проект и выкладывает его по rsync: `DEPLOY_HOST=root@ваш-сервер DEPLOY_REMOTE=/var/www/mappex/ bash deploy/publish.sh`.
Воркер MapLibre — ES-модуль (`assets/maplibre-gl-worker-*.mjs`). Сервер должен отдавать `.mjs` с типом `application/javascript`, иначе карта не загрузится. Конфиг nginx выше это учитывает.
![Вид с дрона](docs/screen-3d.jpg)
## Что работает
- **Карта «Пункт наблюдения»** (MapLibre GL):
- **2D** — регионы РФ с подсветкой при наведении. Клик по региону открывает карточку с камерами городов, а «Статистика по региону» — сводку по смертности.
- **3D** — вид с дрона: переключение дронов, облёт цели ИИ-пилотом, ручное управление с клавиатуры (WASD/стрелки, Q/E, R/F, Z/X).
- **Спутник** и **Гибрид**.
- Слои: Города, Разметки, Дороги, Метки, Регионы, Черно-белое. Кнопка «Здания» включает 3D-здания на 2D-карте.
- «Глобус» в углу переключает проекцию, стрелки прокручивают карту.
- **Самые важные события** — вызов ведомства в 1 клик. Залитая кнопка значит, что служба уже выехала. «Камера» открывает 3D-вид с ближайшего дрона. На карточке идёт таймер «ИИ через N с».
- **ИИ-автопилот** — переключатель в верхней строке:
- «Автопилот» назначает исполнителей сразу.
- «Полуручной» назначает, только если оператор не успел за отведённое время.
- «Ручной» не вмешивается.
Исполнителя ИИ выбирает по релевантности, профпригодности, скорости, стрессу и расстоянию до места (`src/store/useStore.ts`, `scoreEmployee`).
- **Журнал действий** — кто, что и когда сделал, статусы «В работе», «Провалил» и время завершения, датчик-рейтинг сотрудника.
- **Мой профиль** — датчики «Стресс» и «Задачи» зависят от текущей нагрузки, плюс столбики по годам и KPI.
- **Радар событий** — следит за ближайшим к центру Москвы происшествием, умеет приближать и открывать его на карте.
- **Статистика и графика** — периоды 1-Д, 1-НЕД, 1-МЕС, 1-ГОД, выбор показателей, три типа графика, курсор с подсказкой.
- **Плитки модулей** скрывают и показывают виджеты. Авиация, Сообщения, Расписания и Задачи открываются боковой панелью.
- **Уведомления ведомств** — «Принять» создаёт задачу, «Отклонить» и «Закрыть всё» убирают уведомления.
- **Экстренный вызов** — кнопка внизу слева: набор 112, 101, 102, 103, 104, окно звонка, радиоканал.
- **Разделы меню**: «Управление задачами» (происшествия, исполнители, канбан, учёт качества сотрудников) и «Настройки системы».
Демо-симуляция каждые 40 секунд добавляет новый сигнал с дрона или камеры. Интервал и время на реакцию настраиваются в «Настройках системы».
## Специальные возможности
По умолчанию включены «Ночное время» и «Плохое зрение», как в макете. В настройках есть ещё «Максимальная контрастность» и дневная тема. Палитра пастельная: на чёрном фоне такие цвета не дают ореолов и «двоения» при астигматизме. Учитывается `prefers-reduced-motion`.
## Устройство
```
src/
store/useStore.ts состояние, ИИ-автопилот, симуляция (zustand)
data/ моковые происшествия, сотрудники, дроны, статистика
components/map/ карта, стили MapLibre, HUD дрона, попап региона, глобус
components/ панели дашборда, шапка, меню, экстренный вызов
pages/ «Управление задачами», «Настройки», заглушки разделов
styles/tokens.css токены и темы (ночь / день / контраст / плохое зрение)
assets/figma/ иконки, фото и SVG, выгруженные из Figma
public/data/ границы субъектов РФ (упрощённый GeoJSON)
```
Сетка повторяет макет: при корневом шрифте 16 px 1rem соответствует 32 px макета, поэтому на 1920×1080 раскладка совпадает с Figma в масштабе 1:2. Шрифт масштабируется с шириной экрана. На экранах уже 1100 px панели выстраиваются в колонку.
![Максимальная контрастность](docs/screen-contrast.jpg)
## Отличия от макета
- Шуточные тексты-заглушки заменены нейтральными правдоподобными, опечатки исправлены.
- Фон с гранеными ромбами нарисован на CSS, а не взят из 4K-картинки (1,6 МБ).
- Векторная карта и 3D-вид с дрона — живые (MapLibre), а не статичные картинки.
- Шрифт SF Compact Display используется, если установлен в системе, иначе подставляется Inter.
## Лицензия
Код — [MIT](LICENSE). Фото, эмблема ИФНС, аватары и прочие картинки из макета (`src/assets/figma/`) лежат в репозитории только для демонстрации и под MIT не попадают. Данные карты — © участники OpenStreetMap (через OpenFreeMap), спутниковые снимки — © Esri и партнёры. Границы субъектов РФ (`public/data/`) взяты из [click_that_hood](https://github.com/codeforgermany/click_that_hood) (Code for Germany, MIT).
+82
View File
@@ -0,0 +1,82 @@
# MAPPEX — статический прототип на mappex.yappix.ru.
# Установка на сервере:
# sudo certbot certonly --webroot -w /var/www/certbot -d mappex.yappix.ru # сертификат (нужен блок :80)
# sudo cp deploy/nginx-mappex.yappix.ru.conf /etc/nginx/sites-available/mappex.yappix.ru
# sudo ln -sf /etc/nginx/sites-available/mappex.yappix.ru /etc/nginx/sites-enabled/
# sudo nginx -t && sudo systemctl reload nginx
server {
listen 80;
listen [::]:80;
server_name mappex.yappix.ru;
location ^~ /.well-known/acme-challenge/ {
root /var/www/certbot;
default_type "text/plain";
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name mappex.yappix.ru;
ssl_certificate /etc/letsencrypt/live/mappex.yappix.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mappex.yappix.ru/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/mappex;
index index.html;
# воркер MapLibre — ES-модуль: браузер требует JavaScript-тип
types {
text/html html;
text/css css;
application/javascript js mjs;
application/json json;
application/geo+json geojson;
image/svg+xml svg;
image/png png;
image/jpeg jpg jpeg;
font/woff2 woff2;
image/x-icon ico;
}
gzip on;
gzip_vary on;
gzip_comp_level 6;
gzip_types text/css application/javascript application/json application/geo+json image/svg+xml;
# файлы сборки с хешем в имени — навсегда
location /assets/ {
add_header Cache-Control "public, max-age=31536000, immutable" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
try_files $uri =404;
}
location /data/ {
add_header Cache-Control "public, max-age=86400" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
try_files $uri =404;
}
location / {
add_header Cache-Control "no-cache" always;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
try_files $uri $uri/ /index.html;
}
# заголовки безопасности — в каждом location: add_header там отменяет наследование с уровня server
access_log /var/log/nginx/mappex-yappix-access.log;
error_log /var/log/nginx/mappex-yappix-error.log;
}
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# Выкладка прототипа на сервер: сборка → rsync dist/ → права для nginx.
# DEPLOY_HOST=root@host DEPLOY_REMOTE=/var/www/mappex/ bash deploy/publish.sh
# По умолчанию — VDS YappiX (алиас yappix-vds из ~/.ssh/config) и https://mappex.yappix.ru.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
HOST="${DEPLOY_HOST:-yappix-vds}"
REMOTE="${DEPLOY_REMOTE:-/var/www/mappex/}"
cd "$ROOT"
npm run build
ssh "$HOST" "mkdir -p $REMOTE"
# rsync переносит права macOS (например, 700) — без chmod nginx (www-data) ответит 403
rsync -az --delete dist/ "$HOST:$REMOTE"
ssh "$HOST" "chown -R www-data:www-data $REMOTE && find $REMOTE -type f -exec chmod 644 {} + && find $REMOTE -type d -exec chmod 755 {} +"
echo "Выложено: $HOST:$REMOTE"
Binary file not shown.

After

Width:  |  Height:  |  Size: 467 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 KiB

+15
View File
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="ru" data-night="true" data-low-vision="true" data-contrast="false">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#161616" />
<meta name="description" content="MAPPEX — концепт межведомственного пункта наблюдения с ИИ-автопилотом" />
<title>MAPPEX Dashboards</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+1834
View File
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
{
"name": "mappex",
"private": true,
"version": "1.0.0",
"description": "MAPPEX — концепт межведомственного пункта наблюдения: карта РФ, вид с дрона в 3D и ИИ-автопилот назначений",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://git.myunion.pro/yappix-samples/mappex.git"
},
"homepage": "https://mappex.yappix.ru",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "oxlint",
"preview": "vite preview"
},
"dependencies": {
"@fontsource-variable/inter": "^5.3.0",
"clsx": "^2.1.1",
"d3-scale": "^4.0.2",
"d3-shape": "^3.2.0",
"iconsax-react": "^0.0.8",
"maplibre-gl": "^6.15.0",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"zustand": "^5.0.16"
},
"devDependencies": {
"@types/d3-scale": "^4.0.9",
"@types/d3-shape": "^3.2.0",
"@types/node": "^24.19.2",
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.2",
"oxlint": "^1.88.0",
"typescript": "~6.0.3",
"vite": "^8.3.4"
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.1 KiB

+312
View File
@@ -0,0 +1,312 @@
/*
* Сетка повторяет макет 3840×2160: при корневом шрифте 16px 1rem = 32px макета,
* поэтому на 1920×1080 раскладка совпадает с Figma один к одному (в масштабе 1/2).
*/
.app {
--rail-w: 2.53rem;
--nav-w: 11.06rem;
display: grid;
grid-template-columns: var(--rail-w) var(--nav-w) minmax(0, 1fr);
height: 100vh;
height: 100dvh;
}
.app--nav-collapsed {
grid-template-columns: var(--rail-w) 0 minmax(0, 1fr);
}
.app-main {
grid-column: 3;
min-width: 0;
min-height: 0;
height: 100%;
overflow: hidden;
}
.dash {
height: 100%;
display: grid;
grid-template-columns: minmax(0, 73.5fr) minmax(19rem, 25.4fr);
column-gap: 2.5rem;
padding: 1.1rem 2.6rem 2.6rem 2.25rem;
}
.dash--no-right {
grid-template-columns: minmax(0, 1fr) minmax(16rem, 20rem);
}
.dash-left {
min-height: 0;
display: grid;
grid-template-rows: auto auto minmax(0, 35.6fr) minmax(0, 17.25fr);
row-gap: 0;
}
.dash-left.no-stats {
grid-template-rows: auto auto minmax(0, 1fr);
}
.dash-left.no-main {
grid-template-rows: auto auto minmax(0, 1fr);
}
.dash-strip {
height: 1rem;
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
position: relative;
z-index: 8;
}
.dash-head {
display: grid;
grid-template-columns: minmax(0, 1591fr) minmax(0, 681fr);
column-gap: 2.56rem;
margin: 1.34rem 0 1.9rem;
}
.dash-main {
min-height: 0;
display: grid;
grid-template-columns: minmax(0, 1591fr) minmax(0, 681fr);
column-gap: 2.56rem;
}
.dash-main.is-single {
grid-template-columns: minmax(0, 1fr);
}
.dash-left > .panel[data-widget='stats'] {
margin-top: 2.25rem;
}
.dash-right {
min-height: 0;
display: flex;
flex-direction: column;
gap: 2.6rem;
}
.dash-right > .status {
margin-bottom: -1.45rem;
}
.dash-right > .panel[data-widget='profile'] {
flex: 642 1 0;
}
.dash-right > .panel[data-widget='journal'] {
flex: 518 1 0;
}
.dash-right > .panel[data-widget='radar'] {
flex: 641 1 0;
}
/* невысокие экраны: в профиле оставляем главное — датчики и KPI */
@media (max-height: 900px) {
.prof-pos,
.prof-avg {
display: none;
}
.prof-head {
align-items: center;
}
}
@media (max-height: 800px) {
.prof-kpis {
display: none;
}
}
/* --- модальные окна --- */
.modal {
position: fixed;
inset: 0;
z-index: 100;
display: grid;
place-items: center;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(3px);
animation: fade-in 0.15s ease-out;
}
.modal-card {
width: min(34rem, calc(100vw - 2rem));
max-height: calc(100vh - 2rem);
overflow-y: auto;
padding: 1.3rem 1.5rem;
border-radius: 0.75rem;
border: var(--stroke) solid var(--border);
background: var(--panel-to);
display: flex;
flex-direction: column;
gap: 0.7rem;
font-size: var(--fs-sm);
}
.modal-card h2 {
font-size: var(--fs-xl);
}
.modal-card h3 {
font-size: var(--fs-md);
margin-top: 0.4rem;
}
.modal-list {
list-style: disc;
padding-left: 1.1rem;
display: flex;
flex-direction: column;
gap: 0.35rem;
color: var(--text-2);
line-height: 1.4;
}
.modal-keys {
display: grid;
grid-template-columns: max-content 1fr;
gap: 0.3rem 1rem;
margin: 0;
}
.modal-keys dt {
font-weight: var(--w-semibold);
color: var(--c-cream);
}
.modal-keys dd {
margin: 0;
color: var(--text-2);
}
.modal-close {
align-self: flex-end;
padding: 0.4rem 1rem;
font-size: var(--fs-sm);
}
.lock {
position: fixed;
inset: 0;
z-index: 110;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1.2rem;
background: var(--bg);
text-align: center;
font-size: var(--fs-md);
color: var(--text-2);
}
.lock-logo {
width: 16rem;
}
/* --- узкие экраны: панели в столбец, страница прокручивается --- */
@media (max-width: 1100px), (max-height: 620px) {
body {
overflow: auto;
}
.app {
height: auto;
min-height: 100vh;
}
.app-main {
overflow: visible;
}
.dash {
height: auto;
display: flex;
flex-direction: column;
gap: 1.2rem;
padding: 1rem;
}
.dash-left,
.dash-right {
display: flex;
flex-direction: column;
gap: 1.2rem;
}
.dash-head,
.dash-main {
display: flex;
flex-direction: column;
gap: 1.2rem;
margin: 0;
}
.dash-head .notif {
min-height: 6rem;
}
.dash-main .panel--map {
height: 70vh;
min-height: 24rem;
}
.dash-main .panel[data-widget='events'] {
height: 34rem;
}
.dash-left > .panel[data-widget='stats'] {
height: 20rem;
margin-top: 0;
}
.dash-right > .panel {
flex: none !important;
min-height: 18rem;
}
.dash-right > .status {
margin: 0;
flex-wrap: wrap;
height: auto;
gap: 0.6rem 1rem;
}
.tiles {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
.tile-label {
font-size: var(--fs-xs);
}
.groll {
display: none;
}
.page {
height: auto;
padding: 1rem;
}
.kanban,
.radio-cards {
grid-template-columns: 1fr;
}
}
@media (max-width: 700px) {
.app,
.app--nav-collapsed {
grid-template-columns: var(--rail-w) minmax(0, 1fr);
}
.app-main {
grid-column: 2;
}
.sidenav {
grid-column: 1;
position: sticky;
top: 0;
height: 100vh;
grid-template-columns: var(--rail-w) 0;
}
.sidenav .sidenav-nav-bg,
.sidenav .sidenav-logo,
.sidenav .sidenav-label {
display: none;
}
.sidenav .sidenav-fab {
grid-column: 1;
padding: 0 0 3.2rem;
display: flex;
justify-content: center;
}
.sidenav .fab {
--fab: 2rem;
width: var(--fab);
height: var(--fab);
}
.sidenav .fab-sat {
display: none;
}
.tiles {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.prof-kpis {
grid-template-columns: 1fr;
}
.tbl {
display: block;
overflow-x: auto;
}
.range {
grid-template-columns: 1fr;
}
}
+151
View File
@@ -0,0 +1,151 @@
import { useEffect, useState } from 'react'
import { useStore } from './store/useStore'
import { Sidebar } from './components/Sidebar'
import { AiModeSwitch, ModuleTiles, NotificationStack, StatusBar, Ticker, Toasts } from './components/Header'
import { ObservationMap } from './components/map/ObservationMap'
import { EventsFeed } from './components/EventsFeed'
import { StatsPanel } from './components/StatsPanel'
import { ProfilePanel } from './components/ProfilePanel'
import { JournalPanel } from './components/JournalPanel'
import { RadarPanel } from './components/RadarPanel'
import { ModuleDrawer } from './components/ModuleDrawer'
import { CallOverlay } from './components/EmergencyCall'
import { Logo } from './components/Logo'
import { PlaceholderPage, SettingsPage, TasksPage } from './pages/Pages'
import './App.css'
function Dashboard() {
const w = useStore((s) => s.widgets)
const left = [w.map, w.events].filter(Boolean).length
const right = [w.profile, w.journal, w.radar].filter(Boolean).length
return (
<div className={`dash${right ? '' : ' dash--no-right'}`}>
<div className={`dash-left${w.stats ? '' : ' no-stats'}${left ? '' : ' no-main'}`}>
<div className="dash-strip">
<Ticker />
<AiModeSwitch />
</div>
<div className="dash-head">
<ModuleTiles />
<NotificationStack />
</div>
{left > 0 && (
<div className={`dash-main${w.map && w.events ? '' : ' is-single'}`}>
{w.map && <ObservationMap />}
{w.events && <EventsFeed />}
</div>
)}
{w.stats && <StatsPanel />}
</div>
<div className="dash-right">
<StatusBar />
{w.profile && <ProfilePanel />}
{w.journal && <JournalPanel />}
{w.radar && <RadarPanel />}
</div>
</div>
)
}
function HelpModal({ onClose }: { onClose: () => void }) {
useEffect(() => {
const esc = (e: KeyboardEvent) => e.key === 'Escape' && onClose()
document.addEventListener('keydown', esc)
return () => document.removeEventListener('keydown', esc)
}, [onClose])
return (
<div className="modal" role="dialog" aria-modal="true" aria-label="Помощь" onClick={onClose}>
<div className="modal-card" onClick={(e) => e.stopPropagation()}>
<h2>Как работает пункт наблюдения</h2>
<ul className="modal-list">
<li>Дроны и камеры присылают сигналы — они появляются в «Самых важных событиях» и метками на карте.</li>
<li>Вызовите ведомство одной кнопкой в карточке события. Залитая кнопка — служба уже выехала.</li>
<li>Если оператор не успел, ИИ-автопилот сам назначит самого релевантного сотрудника (таймер «ИИ через N с»).</li>
<li>«Камера» переключает карту в 3D — вид с ближайшего дрона. ИИ-пилот облетает цель; клавиши перехватывают управление.</li>
<li>Режимы «Ночное время», «Плохое зрение» и «Максимальная контрастность» — в «Настройках системы».</li>
</ul>
<h3>Горячие клавиши (карта в 3D)</h3>
<dl className="modal-keys">
<dt>WASD / стрелки</dt>
<dd>полёт дрона</dd>
<dt>Q / E</dt>
<dd>поворот</dd>
<dt>R / F</dt>
<dd>высота</dd>
<dt>Z / X</dt>
<dd>наклон камеры</dd>
<dt>Esc</dt>
<dd>закрыть панель или окно</dd>
</dl>
<button className="btn btn--fill-green modal-close" onClick={onClose}>
Понятно
</button>
</div>
</div>
)
}
function LockScreen() {
const setLoggedOut = useStore((s) => s.setLoggedOut)
return (
<div className="lock" role="dialog" aria-modal="true" aria-label="Сеанс завершён">
<Logo className="lock-logo" />
<p>Сеанс оператора завершён. ИИ-автопилот продолжает мониторинг.</p>
<button className="seg-btn is-on" onClick={() => setLoggedOut(false)}>
Войти снова
</button>
</div>
)
}
export default function App() {
const settings = useStore((s) => s.settings)
const mapMode = useStore((s) => s.mapMode)
const section = useStore((s) => s.section)
const navCollapsed = useStore((s) => s.navCollapsed)
const loggedOut = useStore((s) => s.loggedOut)
const maximized = useStore((s) => s.maximized)
const setMaximized = useStore((s) => s.setMaximized)
const tick = useStore((s) => s.tick)
const [help, setHelp] = useState(false)
// режимы доступности → атрибуты корня, на них завязаны токены
useEffect(() => {
const r = document.documentElement
r.dataset.night = String(settings.night)
r.dataset.lowVision = String(settings.lowVision)
r.dataset.contrast = String(settings.contrast)
r.dataset.mapMode = mapMode
}, [settings.night, settings.lowVision, settings.contrast, mapMode])
// сердце симуляции: ИИ-автопилот, завершение задач, новые сигналы
useEffect(() => {
const t = setInterval(() => tick(Date.now()), 1000)
return () => clearInterval(t)
}, [tick])
useEffect(() => {
if (!maximized) return
const esc = (e: KeyboardEvent) => e.key === 'Escape' && setMaximized(null)
document.addEventListener('keydown', esc)
return () => document.removeEventListener('keydown', esc)
}, [maximized, setMaximized])
return (
<div className={`app${navCollapsed ? ' app--nav-collapsed' : ''}`}>
<Sidebar onHelp={() => setHelp(true)} />
<main className="app-main">
{section === 'dashboard' && <Dashboard />}
{section === 'tasks' && <TasksPage />}
{section === 'settings' && <SettingsPage />}
{(section === 'payments' || section === 'docs') && <PlaceholderPage kind={section} />}
</main>
<ModuleDrawer />
<CallOverlay />
<Toasts />
{help && <HelpModal onClose={() => setHelp(false)} />}
{loggedOut && <LockScreen />}
</div>
)
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

+23
View File
@@ -0,0 +1,23 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 55">
<g id="Ellipse 62" filter="url(#filter0_d_0_5)">
<circle cx="25" cy="25" r="15" fill="#222222"/>
</g>
<g id="Group 54">
<path id="Vector" d="M30.7207 22.6433C30.7207 23.8123 30.3741 24.8845 29.7775 25.7794C29.3404 26.4314 28.7717 26.9848 28.1081 27.404C27.4445 27.8233 26.7005 28.0992 25.9239 28.214C25.6498 28.2624 25.3677 28.2866 25.0774 28.2866C24.7872 28.2866 24.5051 28.2624 24.231 28.214C23.4544 28.0992 22.7104 27.8233 22.0468 27.404C21.3832 26.9848 20.8145 26.4314 20.3774 25.7794C19.7585 24.8509 19.4301 23.7591 19.4341 22.6433C19.4341 19.5234 21.9575 17 25.0774 17C28.1974 17 30.7207 19.5234 30.7207 22.6433Z" stroke-linecap="round" stroke-linejoin="round" stroke="#F1F3B8"/>
<path id="Vector_2" d="M32.5346 30.2763L31.2044 30.5907C30.9061 30.6632 30.6723 30.889 30.6078 31.1873L30.3256 32.3724C30.291 32.5178 30.2166 32.6508 30.1108 32.7564C30.0049 32.8621 29.8718 32.9362 29.7262 32.9704C29.5807 33.0047 29.4284 32.9979 29.2866 32.9506C29.1447 32.9034 29.0188 32.8176 28.9228 32.7029L25.0773 28.285L21.2318 32.711C21.1359 32.8257 21.01 32.9114 20.8681 32.9587C20.7262 33.0059 20.574 33.0128 20.4285 32.9785C20.2829 32.9442 20.1498 32.8701 20.0439 32.7645C19.9381 32.6589 19.8637 32.5259 19.8291 32.3804L19.5469 31.1953C19.5126 31.0503 19.4386 30.9177 19.3333 30.8124C19.2279 30.707 19.0953 30.633 18.9503 30.5987L17.6201 30.2843C17.4808 30.2509 17.3528 30.1811 17.2493 30.0819C17.1458 29.9828 17.0705 29.8579 17.0311 29.7201C16.9917 29.5823 16.9897 29.4366 17.0252 29.2977C17.0607 29.1589 17.1325 29.0319 17.2332 28.9299L20.3773 25.7858C20.8145 26.4378 21.3831 26.9912 22.0467 27.4104C22.7104 27.8297 23.4543 28.1056 24.2308 28.2205C24.5049 28.2689 24.7871 28.2931 25.0773 28.2931C25.3676 28.2931 25.6497 28.2689 25.9238 28.2205C27.5281 27.9867 28.9067 27.0757 29.7774 25.7858L32.9215 28.9299C33.3649 29.3653 33.1473 30.1312 32.5346 30.2763ZM25.5449 20.2086L26.0206 21.1599C26.0851 21.2889 26.2544 21.4179 26.4075 21.4421L27.2702 21.5872C27.8184 21.6759 27.9474 22.079 27.5523 22.474L26.8832 23.1431C26.7703 23.256 26.7058 23.4737 26.7461 23.6349L26.9396 24.4653C27.0928 25.1183 26.7461 25.3763 26.1657 25.0296L25.3595 24.554C25.2776 24.5103 25.1863 24.4874 25.0935 24.4874C25.0007 24.4874 24.9093 24.5103 24.8274 24.554L24.0212 25.0296C23.4408 25.3682 23.0941 25.1183 23.2473 24.4653L23.4408 23.6349C23.473 23.4817 23.4166 23.256 23.3037 23.1431L22.6346 22.474C22.2396 22.079 22.3686 21.6839 22.9168 21.5872L23.7794 21.4421C23.9245 21.4179 24.0938 21.2889 24.1583 21.1599L24.6339 20.2086C24.8677 19.6927 25.2869 19.6927 25.5449 20.2086Z" stroke-linecap="round" stroke-linejoin="round" stroke="#F1F3B8"/>
</g>
</g>
<defs>
<filter id="filter0_d_0_5" x="0" y="0" width="50" height="50" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="5"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.945098 0 0 0 0 0.952941 0 0 0 0 0.721569 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_5"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_5" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="79.1667" height="79.1667" viewBox="0 0 79.1667 79.1667" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 65">
<path id="Vector" opacity="0.4" d="M39.5833 79.1667C61.4452 79.1667 79.1667 61.4452 79.1667 39.5833C79.1667 17.7215 61.4452 0 39.5833 0C17.7215 0 0 17.7215 0 39.5833C0 61.4452 17.7215 79.1667 39.5833 79.1667Z" fill="#727272"/>
<path id="Vector_2" d="M39.5832 19.5106C31.3894 19.5106 24.7394 26.1606 24.7394 34.3544C24.7394 42.3898 31.0332 48.921 39.3852 49.1585H40.0977C43.9402 49.0322 47.583 47.4173 50.2568 44.6548C52.9306 41.8924 54.4259 38.1989 54.4269 34.3544C54.4269 26.1606 47.7769 19.5106 39.5832 19.5106ZM66.4167 68.6612C59.1115 75.4134 49.5269 79.1595 39.5792 79.1508C29.2084 79.1508 19.7875 75.1529 12.7417 68.6612C13.6917 65.0592 16.2646 61.7737 20.025 59.2404C30.8313 52.0362 48.4063 52.0362 59.1334 59.2404C62.9334 61.7737 65.4667 65.0592 66.4167 68.6612Z" fill="#727272"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1004 B

+5
View File
@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="13.5182" height="13" viewBox="0 0 13.5182 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 6">
<path id="Vector" d="M1.75128 3.73631H1.1253M12.3929 3.73631H11.7669M6.7591 0.606416V1.85837M5.82014 1.85837H7.69807M3.00324 8.11815H4.88117M8.63704 8.11815H10.515M8.95629 0.5H4.56192C3.00324 0.5 2.65895 1.27621 2.45864 2.2277L1.75128 5.61424H11.7669L11.0596 2.2277C10.8593 1.27621 10.515 0.5 8.95629 0.5ZM13.0126 11.1354C13.0815 11.8678 12.4931 12.5 11.7419 12.5H10.5651C9.889 12.5 9.7951 12.2121 9.67616 11.8552L9.55097 11.4797C9.37569 10.9664 9.26302 10.6221 8.36161 10.6221H5.1566C4.25519 10.6221 4.12374 11.0102 3.96724 11.4797L3.84205 11.8552C3.72311 12.2121 3.62921 12.5 2.95316 12.5H1.77632C1.02515 12.5 0.436726 11.8678 0.505584 11.1354L0.856132 7.32316C0.943769 6.38419 1.1253 5.61424 2.76536 5.61424H10.7528C12.3929 5.61424 12.5744 6.38419 12.6621 7.32316L13.0126 11.1354Z" stroke-linecap="round" stroke-linejoin="round" stroke="#FC003C"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="16" height="13.63" viewBox="0 0 16 13.63" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 6">
<path id="Vector" d="M8.3975 13.13H3.6575C1.2875 13.13 0.5 11.555 0.5 9.9725V3.6575C0.5 1.2875 1.2875 0.5 3.6575 0.5H8.3975C10.7675 0.5 11.555 1.2875 11.555 3.6575V9.9725C11.555 12.3425 10.76 13.13 8.3975 13.13Z" stroke-linecap="round" stroke-linejoin="round" stroke="#F1F3B8"/>
<path id="Vector_2" d="M13.64 10.64L11.555 9.17751V4.44501L13.64 2.98251C14.66 2.27001 15.5 2.70501 15.5 3.95751V9.67251C15.5 10.925 14.66 11.36 13.64 10.64ZM7.625 6.06501C7.92337 6.06501 8.20952 5.94648 8.4205 5.7355C8.63147 5.52453 8.75 5.23838 8.75 4.94001C8.75 4.64164 8.63147 4.35549 8.4205 4.14451C8.20952 3.93354 7.92337 3.81501 7.625 3.81501C7.32663 3.81501 7.04048 3.93354 6.8295 4.14451C6.61853 4.35549 6.5 4.64164 6.5 4.94001C6.5 5.23838 6.61853 5.52453 6.8295 5.7355C7.04048 5.94648 7.32663 6.06501 7.625 6.06501Z" stroke-linecap="round" stroke-linejoin="round" stroke="#F1F3B8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="13.5182" height="13" viewBox="0 0 13.5182 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 6">
<path id="Vector" d="M1.75128 3.73631H1.1253M12.3929 3.73631H11.7669M6.75911 0.606416V1.85837M5.82014 1.85837H7.69807M3.00324 8.11815H4.88117M8.63704 8.11815H10.515M8.95629 0.5H4.56192C3.00324 0.5 2.65895 1.27621 2.45864 2.2277L1.75128 5.61424H11.7669L11.0596 2.2277C10.8593 1.27621 10.515 0.5 8.95629 0.5ZM13.0126 11.1354C13.0815 11.8678 12.4931 12.5 11.7419 12.5H10.5651C9.889 12.5 9.7951 12.2121 9.67616 11.8552L9.55097 11.4797C9.37569 10.9664 9.26302 10.6221 8.36161 10.6221H5.1566C4.25519 10.6221 4.12374 11.0102 3.96724 11.4797L3.84205 11.8552C3.72311 12.2121 3.62921 12.5 2.95316 12.5H1.77632C1.02515 12.5 0.436726 11.8678 0.505584 11.1354L0.856132 7.32316C0.943769 6.38419 1.1253 5.61424 2.76536 5.61424H10.7528C12.3929 5.61424 12.5744 6.38419 12.6621 7.32316L13.0126 11.1354Z" stroke-linecap="round" stroke-linejoin="round" stroke="#222222"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="13.5182" height="13" viewBox="0 0 13.5182 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 6">
<path id="Vector" d="M1.75128 3.73631H1.1253M12.3929 3.73631H11.7669M6.75911 0.606416V1.85837M5.82014 1.85837H7.69807M3.00324 8.11815H4.88117M8.63704 8.11815H10.515M8.95629 0.5H4.56192C3.00324 0.5 2.65895 1.27621 2.45864 2.2277L1.75128 5.61424H11.7669L11.0596 2.2277C10.8593 1.27621 10.515 0.5 8.95629 0.5ZM13.0126 11.1354C13.0815 11.8678 12.4931 12.5 11.7419 12.5H10.5651C9.889 12.5 9.7951 12.2121 9.67616 11.8552L9.55097 11.4797C9.37569 10.9664 9.26302 10.6221 8.36161 10.6221H5.1566C4.25519 10.6221 4.12374 11.0102 3.96724 11.4797L3.84205 11.8552C3.72311 12.2121 3.62921 12.5 2.95316 12.5H1.77632C1.02515 12.5 0.436726 11.8678 0.505584 11.1354L0.856132 7.32316C0.943769 6.38419 1.1253 5.61424 2.76536 5.61424H10.7528C12.3929 5.61424 12.5744 6.38419 12.6621 7.32316L13.0126 11.1354Z" stroke-linecap="round" stroke-linejoin="round" stroke="#7B99FA"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="13.5182" height="13" viewBox="0 0 13.5182 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 6">
<path id="Vector" d="M1.75128 3.73631H1.1253M12.3929 3.73631H11.7669M6.75911 0.606416V1.85837M5.82014 1.85837H7.69807M3.00324 8.11815H4.88117M8.63704 8.11815H10.515M8.95629 0.5H4.56192C3.00324 0.5 2.65895 1.27621 2.45864 2.2277L1.75128 5.61424H11.7669L11.0596 2.2277C10.8593 1.27621 10.515 0.5 8.95629 0.5ZM13.0126 11.1354C13.0815 11.8678 12.4931 12.5 11.7419 12.5H10.5651C9.889 12.5 9.7951 12.2121 9.67616 11.8552L9.55097 11.4797C9.37569 10.9664 9.26302 10.6221 8.36161 10.6221H5.1566C4.25519 10.6221 4.12374 11.0102 3.96724 11.4797L3.84205 11.8552C3.72311 12.2121 3.62921 12.5 2.95316 12.5H1.77632C1.02515 12.5 0.436726 11.8678 0.505584 11.1354L0.856132 7.32316C0.943769 6.38419 1.1253 5.61424 2.76536 5.61424H10.7528C12.3929 5.61424 12.5744 6.38419 12.6621 7.32316L13.0126 11.1354Z" stroke-linecap="round" stroke-linejoin="round" stroke="#53CDD8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 6">
<circle id="Ellipse 4" cx="13.5" cy="13.5" r="13.5" fill="#222222"/>
<g id="Iconsax/Linear/video">
<path id="Vector" d="M14.3975 20.315H9.6575C7.2875 20.315 6.5 18.74 6.5 17.1575V10.8425C6.5 8.4725 7.2875 7.685 9.6575 7.685H14.3975C16.7675 7.685 17.555 8.4725 17.555 10.8425V17.1575C17.555 19.5275 16.76 20.315 14.3975 20.315Z" stroke-linecap="round" stroke-linejoin="round" stroke="white"/>
<path id="Vector_2" d="M19.64 17.825L17.555 16.3625V11.63L19.64 10.1675C20.66 9.455 21.5 9.89 21.5 11.1425V16.8575C21.5 18.11 20.66 18.545 19.64 17.825ZM13.625 13.25C13.9234 13.25 14.2095 13.1315 14.4205 12.9205C14.6315 12.7095 14.75 12.4234 14.75 12.125C14.75 11.8266 14.6315 11.5405 14.4205 11.3295C14.2095 11.1185 13.9234 11 13.625 11C13.3266 11 13.0405 11.1185 12.8295 11.3295C12.6185 11.5405 12.5 11.8266 12.5 12.125C12.5 12.4234 12.6185 12.7095 12.8295 12.9205C13.0405 13.1315 13.3266 13.25 13.625 13.25Z" stroke-linecap="round" stroke-linejoin="round" stroke="white"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+28
View File
@@ -0,0 +1,28 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="162" height="162" viewBox="0 0 162 162" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 68">
<path id="Ellipse 2" d="M162 81C162 125.735 125.735 162 81 162C36.2649 162 0 125.735 0 81C0 36.2649 36.2649 0 81 0C125.735 0 162 36.2649 162 81ZM18.2427 81C18.2427 115.66 46.3401 143.757 81 143.757C115.66 143.757 143.757 115.66 143.757 81C143.757 46.3401 115.66 18.2427 81 18.2427C46.3401 18.2427 18.2427 46.3401 18.2427 81Z" fill="url(#paint0_linear_0_7)"/>
<g id="Group 67">
<circle id="Ellipse 67" cx="80.6597" cy="80.6597" r="57.5168" fill="url(#paint1_radial_0_7)"/>
<path id="Subtract" d="M58.1585 44.6113C57.0288 45.2985 55.9268 46.0378 54.8562 46.8278C50.167 50.2881 46.2312 54.6117 43.2386 59.5312L51.1377 64.0918C53.5046 60.2521 56.5968 56.8754 60.2703 54.1646C61.0655 53.5777 61.8826 53.0261 62.7191 52.5105L58.1585 44.6113ZM64.4875 51.4895C69.3418 48.8702 74.758 47.4103 80.3079 47.2505V38.1293C73.1513 38.2932 66.1644 40.1771 59.9269 43.5903L64.4875 51.4895ZM98.1703 51.4896C93.3158 48.8702 87.8996 47.4103 82.3499 47.2505V38.1293C89.5062 38.2932 96.4932 40.1771 102.731 43.5904L98.1703 51.4896ZM102.372 54.1532C101.582 53.5706 100.77 53.0228 99.9387 52.5106L104.499 44.6114C105.622 45.2944 106.718 46.0288 107.782 46.8134C112.48 50.2761 116.422 54.6048 119.419 59.5314L111.52 64.0919C109.15 60.2467 106.052 56.8658 102.372 54.1532ZM50.1167 99.5431C49.2282 97.8964 48.4672 96.1743 47.8446 94.3908C46.6381 90.9348 45.9817 87.336 45.8777 83.7227H36.7565C36.8625 88.3531 37.6901 92.9678 39.2359 97.3961C40.0477 99.7215 41.0466 101.964 42.2175 104.104L50.1167 99.5431ZM47.4428 72.2345C46.4905 75.3171 45.9694 78.4951 45.8776 81.6807H36.7565C36.8502 77.5883 37.5076 73.5033 38.7308 69.5434C39.6184 66.6696 40.7894 63.9095 42.2175 61.2997L50.1167 65.8603C49.0258 67.882 48.1281 70.0157 47.4428 72.2345ZM111.52 101.311C109.722 104.229 107.507 106.875 104.942 109.164C103.063 110.84 102.507 113.657 103.929 115.735C105.351 117.814 108.206 118.363 110.128 116.736C113.797 113.632 116.932 109.961 119.419 105.872L111.52 101.311ZM120.44 104.104L112.541 99.543C113.433 97.8907 114.196 96.1625 114.819 94.3726C116.022 90.9221 116.676 87.3296 116.78 83.7227H125.901C125.795 88.345 124.97 92.9518 123.43 97.3732C122.616 99.7067 121.615 101.957 120.44 104.104ZM116.78 81.6807H125.901C125.807 77.5802 125.147 73.4872 123.92 69.5202C123.033 66.6548 121.864 63.9025 120.44 61.2998L112.541 65.8604C113.629 67.8765 114.525 70.0039 115.209 72.216C116.165 75.3044 116.688 78.4887 116.78 81.6807ZM43.2386 105.872L51.1377 101.312C52.9394 104.234 55.1591 106.885 57.7301 109.177C59.6097 110.852 60.1673 113.669 58.7467 115.748C57.3261 117.827 54.4712 118.377 52.5482 116.752C48.8713 113.644 45.7299 109.968 43.2386 105.872Z" fill-rule="evenodd" clip-rule="evenodd" fill="url(#paint2_linear_0_7)"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_0_7" x1="-8.5084" y1="-61.9412" x2="90.8698" y2="162" gradientUnits="userSpaceOnUse">
<stop stop-color="#616161"/>
<stop offset="0.546875" stop-color="#F1F3B8" stop-opacity="0.28"/>
<stop offset="0.671875" stop-color="#181818"/>
<stop offset="0.998511" stop-color="#ADADAD"/>
</linearGradient>
<radialGradient id="paint1_radial_0_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(36.0757 53.7731) rotate(19.8708) scale(163.209)">
<stop/>
<stop offset="0.484375"/>
<stop offset="0.671875" stop-color="#FB3D6A" stop-opacity="0.02"/>
<stop offset="0.833333" stop-color="#222222"/>
</radialGradient>
<linearGradient id="paint2_linear_0_7" x1="119.787" y1="107.206" x2="69.4171" y2="105.845" gradientUnits="userSpaceOnUse">
<stop stop-color="#FB3D6A"/>
<stop offset="0.448629" stop-color="#FFA25F"/>
<stop offset="1" stop-color="#96EAB7"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

+28
View File
@@ -0,0 +1,28 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="162" height="162" viewBox="0 0 162 162" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 68">
<path id="Ellipse 2" d="M162 81C162 125.735 125.735 162 81 162C36.2649 162 0 125.735 0 81C0 36.2649 36.2649 0 81 0C125.735 0 162 36.2649 162 81ZM18.2427 81C18.2427 115.66 46.3401 143.757 81 143.757C115.66 143.757 143.757 115.66 143.757 81C143.757 46.3401 115.66 18.2427 81 18.2427C46.3401 18.2427 18.2427 46.3401 18.2427 81Z" fill="url(#paint0_linear_0_7)"/>
<g id="Group 67">
<circle id="Ellipse 67" cx="80.6597" cy="80.6597" r="57.5168" fill="url(#paint1_radial_0_7)"/>
<path id="Subtract" d="M58.1583 44.6113C57.0286 45.2986 55.9266 46.0378 54.856 46.8278C50.1668 50.2882 46.231 54.6117 43.2384 59.5313L51.1376 64.0919C53.5044 60.2522 56.5966 56.8754 60.2701 54.1646C61.0654 53.5777 61.8824 53.0261 62.7189 52.5105L58.1583 44.6113ZM64.4873 51.4895C69.3416 48.8703 74.7578 47.4103 80.3077 47.2505V38.1293C73.1512 38.2932 66.1642 40.1771 59.9267 43.5903L64.4873 51.4895ZM98.1701 51.4895C93.3157 48.8702 87.8995 47.4103 82.3497 47.2505V38.1293C89.506 38.2932 96.493 40.1771 102.731 43.5904L98.1701 51.4895ZM102.372 54.1532C101.581 53.5706 100.769 53.0228 99.9385 52.5106L104.499 44.6114C105.622 45.2944 106.717 46.0288 107.782 46.8134C112.48 50.2761 116.422 54.6048 119.419 59.5313L111.52 64.0919C109.15 60.2467 106.052 56.8658 102.372 54.1532ZM50.1166 99.5431C49.228 97.8964 48.4671 96.1743 47.8445 94.3908C46.638 90.9348 45.9816 87.336 45.8775 83.7227H36.7563C36.8624 88.3531 37.6899 92.9678 39.2358 97.3961C40.0476 99.7215 41.0465 101.964 42.2174 104.104L50.1166 99.5431ZM47.4426 72.2345C46.4904 75.3171 45.9692 78.4951 45.8775 81.6807H36.7563C36.8501 77.5883 37.5074 73.5033 38.7306 69.5434C39.6183 66.6696 40.7892 63.9095 42.2174 61.2997L50.1165 65.8603C49.0256 67.8821 48.128 70.0157 47.4426 72.2345ZM111.52 101.311C109.722 104.229 107.507 106.875 104.942 109.164C103.063 110.84 102.507 113.657 103.929 115.735C105.35 117.814 108.206 118.363 110.128 116.736C113.797 113.632 116.932 109.961 119.419 105.872L111.52 101.311ZM120.44 104.104L112.541 99.543C113.432 97.8907 114.195 96.1625 114.819 94.3726C116.022 90.9221 116.676 87.3296 116.78 83.7227H125.901C125.795 88.345 124.97 92.9518 123.43 97.3732C122.616 99.7067 121.615 101.957 120.44 104.104ZM116.78 81.6807H125.901C125.807 77.5802 125.147 73.4872 123.92 69.5202C123.033 66.6548 121.864 63.9025 120.44 61.2998L112.541 65.8603C113.629 67.8765 114.524 70.0039 115.209 72.216C116.165 75.3044 116.688 78.4887 116.78 81.6807ZM43.2384 105.872L51.1376 101.312C52.9392 104.234 55.1589 106.885 57.73 109.177C59.6096 110.852 60.1672 113.669 58.7466 115.748C57.326 117.827 54.471 118.377 52.548 116.752C48.8712 113.644 45.7297 109.968 43.2384 105.872Z" fill-rule="evenodd" clip-rule="evenodd" fill="url(#paint2_linear_0_7)"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_0_7" x1="-13.2092" y1="-103.182" x2="81" y2="162" gradientUnits="userSpaceOnUse">
<stop stop-color="#616161"/>
<stop offset="0.546875" stop-color="#F1F3B8" stop-opacity="0.28"/>
<stop offset="0.671875" stop-color="#181818"/>
<stop offset="0.998511" stop-color="#ADADAD"/>
</linearGradient>
<radialGradient id="paint1_radial_0_7" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(36.0756 53.7731) rotate(19.8708) scale(163.209)">
<stop/>
<stop offset="0.484375"/>
<stop offset="0.671875" stop-color="#FB3D6A" stop-opacity="0.02"/>
<stop offset="0.833333" stop-color="#222222"/>
</radialGradient>
<linearGradient id="paint2_linear_0_7" x1="119.787" y1="107.206" x2="69.417" y2="105.845" gradientUnits="userSpaceOnUse">
<stop stop-color="#FB3D6A"/>
<stop offset="0.448629" stop-color="#FFA25F"/>
<stop offset="1" stop-color="#96EAB7"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

+12
View File
@@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="35.0481" height="18.8275" viewBox="0 0 35.0481 18.8275" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 66">
<circle id="Ellipse 68" cx="9.29809" cy="9.52931" r="6.80672" transform="rotate(30 9.29809 9.52931)" fill="url(#paint0_linear_0_4)"/>
<rect id="Rectangle 41" x="11.34" y="5.97475" width="23.0852" height="5.44538" rx="2.72269" transform="rotate(-15 11.34 5.97475)" fill="#D9D9D9"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_4" x1="21.8905" y1="6.12595" x2="5.21405" y2="13.6133" gradientUnits="userSpaceOnUse">
<stop offset="0.713542" stop-color="#D9D9D9"/>
<stop offset="1" stop-color="#96EAB7"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 740 B

+12
View File
@@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="35.0481" height="18.8275" viewBox="0 0 35.0481 18.8275" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 66">
<circle id="Ellipse 68" cx="9.29816" cy="9.52938" r="6.80672" transform="rotate(30 9.29816 9.52938)" fill="url(#paint0_linear_0_4)"/>
<rect id="Rectangle 41" x="11.3401" y="5.9749" width="23.0852" height="5.44538" rx="2.72269" transform="rotate(-15 11.3401 5.9749)" fill="#D9D9D9"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_4" x1="21.8906" y1="6.12602" x2="5.21413" y2="13.6134" gradientUnits="userSpaceOnUse">
<stop offset="0.713542" stop-color="#D9D9D9"/>
<stop offset="1" stop-color="#96EAB7"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 742 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="178.5" height="22.0919" viewBox="0 0 178.5 22.0919" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Arrow 1" d="M0 11.0459V12.5459H177V11.0459V9.54594H0V11.0459ZM178.061 12.1066C178.646 11.5208 178.646 10.5711 178.061 9.98528L168.515 0.439341C167.929 -0.146446 166.979 -0.146446 166.393 0.439341C165.808 1.02513 165.808 1.97487 166.393 2.56066L174.879 11.0459L166.393 19.5312C165.808 20.117 165.808 21.0668 166.393 21.6525C166.979 22.2383 167.929 22.2383 168.515 21.6525L178.061 12.1066Z" fill="#FC003C"/>
</svg>

After

Width:  |  Height:  |  Size: 605 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="178.5" height="22.0919" viewBox="0 0 178.5 22.0919" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Arrow 2" d="M0 11.0459V12.5459H177V11.0459V9.54594H0V11.0459ZM178.061 12.1066C178.646 11.5208 178.646 10.5711 178.061 9.98528L168.515 0.439341C167.929 -0.146446 166.979 -0.146446 166.393 0.439341C165.808 1.02513 165.808 1.97487 166.393 2.56066L174.879 11.0459L166.393 19.5312C165.808 20.117 165.808 21.0668 166.393 21.6525C166.979 22.2383 167.929 22.2383 168.515 21.6525L178.061 12.1066Z" fill="#96EAB7"/>
</svg>

After

Width:  |  Height:  |  Size: 605 B

+12
View File
@@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="261.422" height="262.035" viewBox="0 0 261.422 262.035" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Ellipse 3" d="M260.527 0C191.786 1.52805 126.296 29.5655 77.744 78.2522C29.1923 126.939 1.33702 192.507 0 261.252L40.2466 262.035C41.3816 203.674 65.0295 148.009 106.248 106.677C147.466 65.3439 203.064 41.5415 261.422 40.2442L260.527 0Z" fill="url(#paint0_linear_0_5)"/>
<defs>
<linearGradient id="paint0_linear_0_5" x1="80.4496" y1="236.934" x2="266.95" y2="33.9342" gradientUnits="userSpaceOnUse">
<stop stop-color="#FC003C" stop-opacity="0.8"/>
<stop offset="0.291667" stop-color="#F1F3B8" stop-opacity="0.1"/>
<stop offset="0.489583" stop-color="#181818" stop-opacity="0.13"/>
<stop offset="0.682292" stop-color="#F1F3B8" stop-opacity="0.1"/>
<stop offset="1" stop-color="#96EAB7" stop-opacity="0.8"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 935 B

+11
View File
@@ -0,0 +1,11 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="325" height="325" viewBox="0 0 325 325" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Ellipse 2" d="M325 162.5C325 252.246 252.246 325 162.5 325C72.7537 325 0 252.246 0 162.5C0 72.7537 72.7537 0 162.5 0C252.246 0 325 72.7537 325 162.5ZM36.5981 162.5C36.5981 232.034 92.9663 288.402 162.5 288.402C232.034 288.402 288.402 232.034 288.402 162.5C288.402 92.9663 232.034 36.5981 162.5 36.5981C92.9663 36.5981 36.5981 92.9663 36.5981 162.5Z" fill="url(#paint0_linear_0_6)"/>
<defs>
<linearGradient id="paint0_linear_0_6" x1="-26.5" y1="-207" x2="162.5" y2="325" gradientUnits="userSpaceOnUse">
<stop stop-color="#616161"/>
<stop offset="0.546875" stop-color="#F1F3B8" stop-opacity="0.28"/>
<stop offset="0.671875" stop-color="#181818"/>
<stop offset="0.998511" stop-color="#ADADAD"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 905 B

+21
View File
@@ -0,0 +1,21 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="405" height="405" viewBox="0 0 405 405" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Ellipse 1" filter="url(#filter0_d_0_8)">
<circle cx="202.5" cy="202.5" r="162.5" fill="url(#paint0_radial_0_8)"/>
</g>
<defs>
<filter id="filter0_d_0_8" x="0" y="0" width="405" height="405" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="20"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.945098 0 0 0 0 0.952941 0 0 0 0 0.721569 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_8"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_8" result="shape"/>
</filter>
<radialGradient id="paint0_radial_0_8" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(108 99) rotate(70.4417) scale(282.288)">
<stop stop-color="#343434"/>
<stop offset="0.998511" stop-color="#3D3D3D"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+20
View File
@@ -0,0 +1,20 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="110" height="98" viewBox="0 0 110 98" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 24">
<g id="Rectangle 8" opacity="0.95" filter="url(#filter0_d_0_4)">
<rect x="20" y="20" width="70" height="58" rx="8" fill="#222222"/>
</g>
<path id="Vector" opacity="0.7" d="M45 58.7164H69M65.4873 58.7273V53.8618M46.2 58.7164V41.2945C46.2 39.1018 47.2909 38 49.4618 38H56.2582C58.4291 38 59.5091 39.1018 59.5091 41.2945V58.7164M50.2364 43.7164H55.6364M50.2364 47.8073H55.6364M52.9091 58.7164V54.6255M65.5091 46.5964C64.1782 46.5964 63.1091 47.6655 63.1091 48.9964V51.4727C63.1091 52.8036 64.1782 53.8727 65.5091 53.8727C66.84 53.8727 67.9091 52.8036 67.9091 51.4727V48.9964C67.9091 47.6655 66.84 46.5964 65.5091 46.5964Z" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke="white"/>
</g>
<defs>
<filter id="filter0_d_0_4" x="0" y="0" width="110" height="98" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="10"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.945098 0 0 0 0 0.952941 0 0 0 0 0.721569 0 0 0 0.08 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_4"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_4" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="9.02083" height="10.1666" viewBox="0 0 9.02083 10.1666" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 48">
<path id="Vector" opacity="0.4" d="M8.52083 5.65623C8.52083 7.86998 6.72417 9.66665 4.51042 9.66665C2.29667 9.66665 0.5 7.86998 0.5 5.65623C0.5 3.44248 2.29667 1.64581 4.51042 1.64581C6.72417 1.64581 8.52083 3.44248 8.52083 5.65623Z" stroke-linecap="round" stroke-linejoin="round" stroke="white"/>
<path id="Vector_2" opacity="0.4" d="M4.5105 3.25V5.54167" stroke-linecap="round" stroke-linejoin="round" stroke="white"/>
<path id="Vector_3" opacity="0.4" d="M3.1355 0.5H5.8855" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 781 B

+12
View File
@@ -0,0 +1,12 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Linear/edit" clip-path="url(#clip0_0_11)">
<path id="Vector" d="M6.875 1.25H5.625C2.5 1.25 1.25 2.5 1.25 5.625V9.375C1.25 12.5 2.5 13.75 5.625 13.75H9.375C12.5 13.75 13.75 12.5 13.75 9.375V8.125" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
<path id="Vector_2" d="M10.025 1.8875L5.1 6.8125C4.9125 7 4.725 7.36875 4.6875 7.6375L4.41875 9.51875C4.31875 10.2 4.8 10.675 5.48125 10.5813L7.3625 10.3125C7.625 10.275 7.99375 10.0875 8.1875 9.9L13.1125 4.975C13.9625 4.125 14.3625 3.1375 13.1125 1.8875C11.8625 0.6375 10.875 1.0375 10.025 1.8875Z" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
<path id="Vector_3" d="M9.31875 2.59375C9.52599 3.32967 9.91873 4.00004 10.4593 4.54065C11 5.08127 11.6703 5.47401 12.4063 5.68125" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</g>
<defs>
<clipPath id="clip0_0_11">
<rect width="15" height="15" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+5
View File
@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Bold/flash">
<path id="Vector" d="M11.94 7.14667H9.88V2.34667C9.88 1.22667 9.27333 1 8.53333 1.84L8 2.44667L3.48667 7.58C2.86667 8.28 3.12667 8.85333 4.06 8.85333H6.12V13.6533C6.12 14.7733 6.72667 15 7.46667 14.16L8 13.5533L12.5133 8.42C13.1333 7.72 12.8733 7.14667 11.94 7.14667Z" fill="#7B99FA"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 492 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="19.5" height="21.5" viewBox="0 0 19.5 21.5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M18.75 5.75V15.75C18.75 18.75 17.25 20.75 13.75 20.75H5.75C2.25 20.75 0.75 18.75 0.75 15.75V5.75C0.75 2.75 2.25 0.75 5.75 0.75H13.75C17.25 0.75 18.75 2.75 18.75 5.75Z" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 478 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M7.25 0.75V2.75C7.25 3.85 8.15 4.75 9.25 4.75H11.25M0.75 9.25H4.75M0.75 13.25H8.75" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 386 B

+9
View File
@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="21.5" height="21.5" viewBox="0 0 21.5 21.5" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 32">
<path id="Vector" d="M20.75 7.75002V13.75C20.75 16.25 20.25 18 19.13 19.13L12.75 12.75L20.48 5.02002C20.66 5.81002 20.75 6.71002 20.75 7.75002Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
<path id="Vector_2" d="M20.48 5.02L5.02 20.48C2.01 19.79 0.75 17.71 0.75 13.75V7.75C0.75 2.75 2.75 0.75 7.75 0.75H13.75C17.71 0.75 19.79 2.01 20.48 5.02Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
<path id="Vector_3" d="M19.13 19.13C18 20.25 16.25 20.75 13.75 20.75H7.75C6.71 20.75 5.81 20.66 5.02 20.48L12.75 12.75L19.13 19.13Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
<path id="Vector_4" d="M4.99 6.72997C5.67 3.79997 10.07 3.79997 10.75 6.72997C11.14 8.44997 10.06 9.90997 9.11 10.81C8.77545 11.1279 8.33154 11.3052 7.87 11.3052C7.40846 11.3052 6.96456 11.1279 6.63 10.81C5.68 9.90997 4.59 8.44997 4.99 6.72997Z" stroke-width="1.5" stroke="#727272"/>
<path id="Vector_5" d="M7.845 7.45001H7.854" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="14.98" height="17.27" viewBox="0 0 14.98 17.27" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M7.61001 7.3C7.53032 7.29 7.44969 7.29 7.37001 7.3C6.52195 7.27146 5.71821 6.91438 5.12855 6.30421C4.5389 5.69403 4.20953 4.87854 4.21001 4.03001C4.21001 2.22001 5.67001 0.750005 7.49001 0.750005C8.34944 0.748513 9.17505 1.08482 9.78883 1.68641C10.4026 2.288 10.7554 3.1067 10.7711 3.96599C10.7869 4.82529 10.4643 5.65636 9.87299 6.28003C9.28166 6.9037 8.46892 7.27001 7.61001 7.3ZM14.23 13.9C12.3923 15.5891 9.98604 16.5244 7.49001 16.52C4.89001 16.52 2.53001 15.53 0.750006 13.9C0.850006 12.96 1.45001 12.04 2.52001 11.32C5.26001 9.5 9.74 9.5 12.46 11.32C13.53 12.04 14.13 12.96 14.23 13.9Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 885 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="21.5" height="21.5" viewBox="0 0 21.5 21.5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M10.75 20.75C16.273 20.75 20.75 16.273 20.75 10.75C20.75 5.227 16.273 0.75 10.75 0.75C5.227 0.75 0.75 5.227 0.75 10.75C0.75 16.273 5.227 20.75 10.75 20.75Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 444 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="21.5" height="13.5001" viewBox="0 0 21.5 13.5001" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M18.75 12.75C20.01 11.08 20.75 9.00004 20.75 6.75004C20.75 4.50004 20.01 2.42004 18.75 0.750042M2.75 0.750042C1.49 2.42004 0.75 4.50004 0.75 6.75004C0.75 9.00004 1.49 11.08 2.75 12.75M15.55 10.35C16.3 9.35004 16.75 8.10004 16.75 6.75004C16.75 5.40004 16.3 4.15004 15.55 3.15004M5.95 3.15004C5.2 4.15004 4.75 5.40004 4.75 6.75004C4.75 8.10004 5.2 9.35004 5.95 10.35M10.75 8.75004C11.2804 8.75004 11.7891 8.53933 12.1642 8.16426C12.5393 7.78918 12.75 7.28048 12.75 6.75004C12.75 6.21961 12.5393 5.7109 12.1642 5.33583C11.7891 4.96076 11.2804 4.75004 10.75 4.75004C10.2196 4.75004 9.71086 4.96076 9.33579 5.33583C8.96071 5.7109 8.75 6.21961 8.75 6.75004C8.75 7.28048 8.96071 7.78918 9.33579 8.16426C9.71086 8.53933 10.2196 8.75004 10.75 8.75004Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="12.2533" height="13.3345" viewBox="0 0 12.2533 13.3345" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M11.4933 5.755L8.38 4.415L7.68667 4.12167C7.62989 4.09021 7.58186 4.04508 7.54694 3.99036C7.51201 3.93565 7.49129 3.87308 7.48667 3.80833V1.76833C7.48667 1.12833 7.01333 0.368333 6.44 0.075C6.24 -0.025 6 -0.025 5.8 0.075C5.23333 0.368333 4.76 1.135 4.76 1.775V3.815C4.76 3.935 4.66667 4.075 4.56 4.12833L0.76 5.76167C0.34 5.935 0 6.46167 0 6.915V7.795C0 8.36167 0.426667 8.64167 0.953333 8.415L4.29333 6.975C4.55333 6.86167 4.76667 7.00167 4.76667 7.28833V9.22833C4.76667 9.38167 4.68 9.60167 4.57333 9.70833L3.02667 11.2617C2.86667 11.4217 2.79333 11.735 2.86667 11.9617L3.16667 12.8683C3.28667 13.2617 3.73333 13.4483 4.1 13.2617L5.68667 11.9283C5.92667 11.7217 6.32 11.7217 6.56 11.9283L8.14667 13.2617C8.51333 13.4417 8.96 13.2617 9.09333 12.8683L9.39333 11.9617C9.46667 11.7417 9.39333 11.4217 9.23333 11.2617L7.68667 9.70833C7.57333 9.60167 7.48667 9.38167 7.48667 9.22833V7.28833C7.48667 7.00167 7.69333 6.86833 7.96 6.975L11.3 8.415C11.8267 8.64167 12.2533 8.36167 12.2533 7.795V6.915C12.2533 6.46167 11.9133 5.935 11.4933 5.755Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="14.33" height="14.3318" viewBox="0 0 14.33 14.3318" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M13.8317 4.95847C13.8317 5.7518 13.705 6.48513 13.485 7.16513C12.4317 10.4985 9.185 12.4918 7.57833 13.0385C7.35167 13.1185 6.97833 13.1185 6.75167 13.0385C6.325 12.8918 5.785 12.6451 5.205 12.2985C4.83167 12.0785 4.77167 11.5585 5.07833 11.2518L12.5983 3.7318C12.9583 3.3718 13.5917 3.52513 13.7183 4.01847C13.7917 4.31847 13.8317 4.6318 13.8317 4.95847ZM14.185 0.145134C14.0909 0.0521475 13.964 0 13.8317 0C13.6994 0 13.5724 0.0521475 13.4783 0.145134L11.9183 1.70513C11.3917 1.40513 10.7783 1.2318 10.125 1.2318C8.91833 1.2318 7.83833 1.81847 7.165 2.71847C6.82109 2.25768 6.3745 1.88339 5.86069 1.62533C5.34688 1.36727 4.77998 1.23252 4.205 1.2318C2.15833 1.2318 0.498333 2.89847 0.498333 4.95847C0.498333 5.7518 0.625 6.48513 0.845 7.16513C1.27833 8.54513 2.09167 9.69847 3.01167 10.6118L0.145 13.4785C-0.0483333 13.6718 -0.0483333 13.9918 0.145 14.1851C0.245 14.2851 0.371667 14.3318 0.498333 14.3318C0.625 14.3318 0.751667 14.2851 0.851667 14.1851L14.185 0.851801C14.3783 0.658468 14.3783 0.338468 14.185 0.145134Z" fill="#FC003C"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="14.33" height="14.3318" viewBox="0 0 14.33 14.3318" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M13.8317 4.95847C13.8317 5.7518 13.705 6.48513 13.485 7.16513C12.4317 10.4985 9.185 12.4918 7.57833 13.0385C7.35167 13.1185 6.97833 13.1185 6.75167 13.0385C6.325 12.8918 5.785 12.6451 5.205 12.2985C4.83167 12.0785 4.77167 11.5585 5.07833 11.2518L12.5983 3.7318C12.9583 3.3718 13.5917 3.52513 13.7183 4.01847C13.7917 4.31847 13.8317 4.6318 13.8317 4.95847ZM14.185 0.145134C14.0909 0.0521475 13.964 0 13.8317 0C13.6994 0 13.5724 0.0521475 13.4783 0.145134L11.9183 1.70513C11.3917 1.40513 10.7783 1.2318 10.125 1.2318C8.91833 1.2318 7.83833 1.81847 7.165 2.71847C6.82109 2.25768 6.3745 1.88339 5.86069 1.62533C5.34688 1.36727 4.77998 1.23252 4.205 1.2318C2.15833 1.2318 0.498333 2.89847 0.498333 4.95847C0.498333 5.7518 0.625 6.48513 0.845 7.16513C1.27833 8.54513 2.09167 9.69847 3.01167 10.6118L0.145 13.4785C-0.0483333 13.6718 -0.0483333 13.9918 0.145 14.1851C0.245 14.2851 0.371667 14.3318 0.498333 14.3318C0.625 14.3318 0.751667 14.2851 0.851667 14.1851L14.185 0.851801C14.3783 0.658468 14.3783 0.338468 14.185 0.145134Z" fill="#FC003C" fill-opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="19.5" height="21.5" viewBox="0 0 19.5 21.5" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Vector" d="M0.75 20.75H18.75M3.35 7.13H1.75C1.2 7.13 0.75 7.58 0.75 8.13V16.75C0.75 17.3 1.2 17.75 1.75 17.75H3.35C3.9 17.75 4.35 17.3 4.35 16.75V8.13C4.35 7.58 3.9 7.13 3.35 7.13ZM10.55 3.94H8.95C8.4 3.94 7.95 4.39 7.95 4.94V16.75C7.95 17.3 8.4 17.75 8.95 17.75H10.55C11.1 17.75 11.55 17.3 11.55 16.75V4.94C11.55 4.39 11.1 3.94 10.55 3.94ZM17.75 0.75H16.15C15.6 0.75 15.15 1.2 15.15 1.75V16.75C15.15 17.3 15.6 17.75 16.15 17.75H17.75C18.3 17.75 18.75 17.3 18.75 16.75V1.75C18.75 1.2 18.3 0.75 17.75 0.75Z" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 783 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="31" height="26" viewBox="0 0 31 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<ellipse id="Ellipse 6" cx="15.5" cy="13" rx="15.5" ry="13" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 250 B

+17
View File
@@ -0,0 +1,17 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="51" height="53" viewBox="0 0 51 53" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Union" filter="url(#filter0_d_0_5)">
<path d="M40.0418 29.701C42.5209 26.8936 44 23.3509 44 19.5C44 10.3873 35.7173 3 25.5 3C15.2827 3 7 10.3873 7 19.5C7 23.3509 8.47912 26.8937 10.9583 29.7011C14.181 36.8139 25.5 42 25.5 42C25.5 42 36.8191 36.8139 40.0418 29.701Z" fill-rule="evenodd" clip-rule="evenodd" fill="white"/>
</g>
<defs>
<filter id="filter0_d_0_5" x="0" y="0" width="51" height="53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="3.5"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_5"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_5" result="shape"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="82.5" height="22.0919" viewBox="0 0 82.5 22.0919" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Arrow 8" d="M0 11.0459V12.5459H81V11.0459V9.54594H0V11.0459ZM82.0607 12.1066C82.6464 11.5208 82.6464 10.5711 82.0607 9.98528L72.5147 0.439341C71.9289 -0.146446 70.9792 -0.146446 70.3934 0.439341C69.8076 1.02513 69.8076 1.97487 70.3934 2.56066L78.8787 11.0459L70.3934 19.5312C69.8076 20.117 69.8076 21.0668 70.3934 21.6525C70.9792 22.2383 71.9289 22.2383 72.5147 21.6525L82.0607 12.1066Z" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 602 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="32.6667" height="21.3333" viewBox="0 0 32.6667 21.3333" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Line 7" d="M10.6667 10.6667V12.6667H32.6667V10.6667V8.66667H10.6667V10.6667ZM0 10.6667C0 16.5577 4.77563 21.3333 10.6667 21.3333C16.5577 21.3333 21.3333 16.5577 21.3333 10.6667C21.3333 4.77563 16.5577 0 10.6667 0C4.77563 0 0 4.77563 0 10.6667Z" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 465 B

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="96.5459" height="96.546" viewBox="0 0 96.5459 96.546" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 59">
<path id="Arrow 6" d="M85.5 85.5L87 85.5L87 1.5L85.5 1.5L84 1.5L84 85.5L85.5 85.5ZM86.5607 0.439339C85.9749 -0.146446 85.0251 -0.146446 84.4393 0.439339L74.8934 9.98528C74.3076 10.5711 74.3076 11.5208 74.8934 12.1066C75.4792 12.6924 76.4289 12.6924 77.0147 12.1066L85.5 3.62132L93.9853 12.1066C94.5711 12.6924 95.5208 12.6924 96.1066 12.1066C96.6924 11.5208 96.6924 10.5711 96.1066 9.98528L86.5607 0.439339Z" fill="white"/>
<path id="Arrow 7" d="M85.5 85.5L85.5 84L1.5 84L1.5 85.5L1.5 87L85.5 87L85.5 85.5ZM0.439339 84.4393C-0.146446 85.0251 -0.146446 85.9749 0.439339 86.5607L9.98528 96.1066C10.5711 96.6924 11.5208 96.6924 12.1066 96.1066C12.6924 95.5208 12.6924 94.5711 12.1066 93.9853L3.62132 85.5L12.1066 77.0147C12.6924 76.4289 12.6924 75.4792 12.1066 74.8934C11.5208 74.3076 10.5711 74.3076 9.98528 74.8934L0.439339 84.4393Z" fill="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="302" height="166" viewBox="0 0 302 166" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Ellipse 63" d="M302 83C302 128.84 234.395 166 151 166C67.605 166 0 128.84 0 83C0 37.1604 67.605 0 151 0C234.395 0 302 37.1604 302 83ZM22.05 83C22.05 122.146 79.7829 153.88 151 153.88C222.217 153.88 279.95 122.146 279.95 83C279.95 43.8542 222.217 12.1202 151 12.1202C79.7829 12.1202 22.05 43.8542 22.05 83Z" fill="url(#paint0_radial_0_16)" fill-opacity="0.4"/>
<defs>
<radialGradient id="paint0_radial_0_16" cx="0" cy="0" r="1" gradientTransform="matrix(155.5 97.2463 -176.918 434.146 97.5 32.2089)" gradientUnits="userSpaceOnUse">
<stop stop-color="#FA7B7B"/>
<stop offset="1" stop-color="#FF0000"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 813 B

+9
View File
@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="248" height="136" viewBox="0 0 248 136" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Ellipse 65" d="M248 68C248 105.555 192.483 136 124 136C55.5167 136 0 105.555 0 68C0 30.4446 55.5167 0 124 0C192.483 0 248 30.4446 248 68ZM97.4619 68C97.4619 76.0375 109.343 82.5531 124 82.5531C138.657 82.5531 150.538 76.0375 150.538 68C150.538 59.9625 138.657 53.4469 124 53.4469C109.343 53.4469 97.4619 59.9625 97.4619 68Z" fill="url(#paint0_radial_0_15)" fill-opacity="0.4"/>
<defs>
<radialGradient id="paint0_radial_0_15" cx="0" cy="0" r="1" gradientTransform="matrix(3.25928e-06 68 -171.081 29.375 124 68)" gradientUnits="userSpaceOnUse">
<stop stop-color="#FA7B7B" stop-opacity="0"/>
<stop offset="1" stop-color="#FF0000"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 842 B

+5
View File
@@ -0,0 +1,5 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="326" height="180" viewBox="0 0 326 180" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Ellipse 64" style="mix-blend-mode:screen">
<path d="M300.442 138.384C278.4 157.473 244.139 171.274 204.488 177.036C164.837 182.798 122.71 180.098 86.5044 169.474C50.2988 158.849 22.6747 141.081 9.13881 119.712C-4.39705 98.3428 -2.85023 74.9417 13.4709 54.1741C29.792 33.4064 59.6885 16.7977 97.2004 7.65895C134.712 -1.47977 177.084 -2.47719 215.868 4.86555C254.653 12.2083 287.001 27.3518 306.464 47.2771C325.927 67.2024 331.076 90.4459 320.883 112.374L315.811 111.655C325.676 90.4316 320.693 67.9348 301.855 48.6496C283.017 29.3644 251.708 14.7075 214.17 7.60062C176.631 0.493779 135.621 1.45915 99.3143 10.3043C63.0076 19.1494 34.0715 35.2245 18.2747 55.325C2.47794 75.4255 0.980817 98.0748 14.0818 118.758C27.1828 139.44 53.9195 156.637 88.9619 166.92C124.004 177.203 164.778 179.817 203.155 174.24C241.532 168.663 274.693 155.305 296.026 136.829L300.442 138.384Z" fill="#F1F3B8"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="46.6667" height="21.3333" viewBox="0 0 46.6667 21.3333" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Line 6" d="M10.6667 10.6667V12.6667H46.6667V10.6667V8.66667H10.6667V10.6667ZM0 10.6667C0 16.5577 4.77563 21.3333 10.6667 21.3333C16.5577 21.3333 21.3333 16.5577 21.3333 10.6667C21.3333 4.77563 16.5577 0 10.6667 0C4.77563 0 0 4.77563 0 10.6667Z" fill="#FFBE5C"/>
</svg>

After

Width:  |  Height:  |  Size: 465 B

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="29.2737" height="29" viewBox="0 0 29.2737 29" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 54">
<path id="Vector" d="M24.5111 10.3758C24.5111 12.4215 23.9044 14.2979 22.8604 15.8639C22.0954 17.0049 21.1003 17.9733 19.9389 18.7071C18.7776 19.4408 17.4756 19.9237 16.1167 20.1246C15.637 20.2092 15.1432 20.2516 14.6353 20.2516C14.1274 20.2516 13.6336 20.2092 13.1539 20.1246C11.795 19.9237 10.4931 19.4408 9.3317 18.7071C8.17034 17.9733 7.17522 17.0049 6.4102 15.8639C5.32712 14.2391 4.75248 12.3285 4.75954 10.3758C4.75954 4.91588 9.17542 0.5 14.6353 0.5C20.0952 0.5 24.5111 4.91588 24.5111 10.3758Z" stroke-linecap="round" stroke-linejoin="round" stroke="#96EAB7"/>
<path id="Vector_2" d="M27.6855 23.7335L25.3576 24.2837C24.8356 24.4107 24.4265 24.8057 24.3136 25.3277L23.8198 27.4016C23.7592 27.6562 23.6291 27.8889 23.4438 28.0738C23.2586 28.2586 23.0256 28.3883 22.7709 28.4483C22.5162 28.5083 22.2498 28.4963 22.0015 28.4136C21.7532 28.3309 21.5328 28.1808 21.365 27.9801L14.6353 20.2487L7.90571 27.9942C7.73785 28.1949 7.51746 28.345 7.26918 28.4277C7.0209 28.5104 6.75452 28.5224 6.49981 28.4624C6.2451 28.4024 6.0121 28.2727 5.82686 28.0879C5.64162 27.903 5.51144 27.6703 5.45087 27.4157L4.95708 25.3418C4.89706 25.0881 4.76762 24.856 4.58325 24.6716C4.39887 24.4873 4.16682 24.3578 3.91307 24.2978L1.58521 23.7476C1.34132 23.6891 1.11734 23.5669 0.936222 23.3934C0.755103 23.2199 0.623347 23.0014 0.554446 22.7603C0.485545 22.5191 0.481975 22.264 0.544102 22.021C0.606229 21.778 0.73182 21.5559 0.908015 21.3774L6.41023 15.8752C7.17531 17.0161 8.17045 17.9845 9.3318 18.7183C10.4931 19.452 11.795 19.9349 13.154 20.1359C13.6337 20.2205 14.1274 20.2628 14.6353 20.2628C15.1432 20.2628 15.637 20.2205 16.1167 20.1359C18.9243 19.7267 21.3368 18.1325 22.8605 15.8752L28.3627 21.3774C29.1386 22.1392 28.7577 23.4795 27.6855 23.7335ZM15.4536 6.11509L16.286 7.77987C16.3989 8.0056 16.6951 8.23133 16.9632 8.27366L18.4728 8.5276C19.4322 8.68279 19.6579 9.38821 18.9666 10.0795L17.7956 11.2505C17.5981 11.448 17.4852 11.8289 17.5558 12.1111L17.8944 13.5642C18.1624 14.707 17.5558 15.1585 16.54 14.5518L15.1291 13.7194C14.9859 13.643 14.826 13.603 14.6636 13.603C14.5012 13.603 14.3413 13.643 14.198 13.7194L12.7872 14.5518C11.7714 15.1444 11.1647 14.707 11.4328 13.5642L11.7714 12.1111C11.8278 11.843 11.729 11.448 11.5315 11.2505L10.3605 10.0795C9.66924 9.38821 9.89497 8.6969 10.8543 8.5276L12.3639 8.27366C12.6179 8.23133 12.9141 8.0056 13.027 7.77987L13.8594 6.11509C14.2685 5.21216 15.0022 5.21216 15.4536 6.11509Z" stroke-linecap="round" stroke-linejoin="round" stroke="#96EAB7"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="157" height="3" viewBox="0 0 157 3" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Line 8" d="M1.5 1.5H155.5" stroke-width="3" stroke-linecap="round" stroke="#727272"/>
</svg>

After

Width:  |  Height:  |  Size: 269 B

+3
View File
@@ -0,0 +1,3 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="234" height="1" viewBox="0 0 234 1" fill="none" xmlns="http://www.w3.org/2000/svg">
<path id="Line 5" d="M0 0.5H234" stroke="#373737" stroke-opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 246 B

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Bulk/airplanesquare">
<path id="Vector" opacity="0.4" d="M26.3088 3.25H12.6913C6.77625 3.25 3.25 6.77625 3.25 12.6912V26.2925C3.25 32.2238 6.77625 35.75 12.6913 35.75H26.2925C32.2075 35.75 35.7338 32.2238 35.7338 26.3088V12.6912C35.75 6.77625 32.2238 3.25 26.3088 3.25Z" fill="#727272"/>
<path id="Vector_2" d="M16.0225 30.8717L18.7525 28.5642C19.1588 28.223 19.8413 28.223 20.2638 28.5642L22.9775 30.8717C23.6113 31.1967 24.3912 30.8717 24.6187 30.1892L25.1388 28.6292C25.2688 28.2555 25.1388 27.703 24.8625 27.4268L22.1975 24.7455C21.9923 24.5164 21.8718 24.2239 21.8562 23.9167V20.9105C21.8562 20.228 22.36 19.903 22.9937 20.163L28.4375 22.503C29.3313 22.893 30.0787 22.4055 30.0787 21.4305V19.9193C30.0787 19.1393 29.4938 18.2292 28.7625 17.9205L22.36 15.158C22.2187 15.0892 22.0987 14.9834 22.0128 14.8517C21.9269 14.7201 21.8784 14.5676 21.8725 14.4105V11.0467C21.8725 9.94175 21.06 8.64175 20.085 8.138C19.9112 8.04992 19.7192 8.00401 19.5244 8.00401C19.3296 8.00401 19.1375 8.04992 18.9638 8.138C17.9725 8.6255 17.1762 9.94175 17.1762 11.0467V14.4105C17.1762 14.703 16.9488 15.0443 16.6888 15.158L10.2863 17.9205C9.57125 18.2292 8.97 19.1393 8.97 19.9193V21.4305C8.97 22.4055 9.70125 22.893 10.6113 22.503L16.055 20.163C16.6725 19.8868 17.1925 20.228 17.1925 20.9105V23.9167C17.1925 24.193 17.03 24.5667 16.8513 24.7455L14.1375 27.4105C13.8612 27.6868 13.7312 28.2393 13.8612 28.613L14.3813 30.173C14.6088 30.8718 15.3725 31.1967 16.0225 30.8717Z" fill="#727272"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="36.59" height="36.5901" viewBox="0 0 36.59 36.5901" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 82">
<path id="Vector" d="M31.1015 10.977C32.5571 10.977 33.9531 10.3988 34.9824 9.36947C36.0117 8.34018 36.59 6.94415 36.59 5.48851C36.59 4.03287 36.0117 2.63684 34.9824 1.60755C33.9531 0.578252 32.5571 0 31.1015 0C29.6458 0 28.2498 0.578252 27.2205 1.60755C26.1912 2.63684 25.613 4.03287 25.613 5.48851C25.613 6.94415 26.1912 8.34018 27.2205 9.36947C28.2498 10.3988 29.6458 10.977 31.1015 10.977Z" fill="black"/>
<path id="Vector_2" opacity="0.4" d="M31.1016 13.7213C26.5644 13.7213 22.8688 10.0257 22.8688 5.48852C22.8688 4.17128 23.2164 2.94551 23.7652 1.82951H10.0989C3.78707 1.82951 0 5.59829 0 11.9284V26.4729C0 32.8213 3.78707 36.5901 10.0989 36.5901H24.6434C30.9735 36.5901 34.7423 32.8213 34.7423 26.4912V12.8248C33.6446 13.3737 32.4188 13.7213 31.1016 13.7213Z" fill="black"/>
<path id="Vector_3" d="M17.8377 21.954H8.69014C7.94004 21.954 7.31801 21.332 7.31801 20.5819C7.31801 19.8318 7.94004 19.2098 8.69014 19.2098H17.8377C18.5877 19.2098 19.2098 19.8318 19.2098 20.5819C19.2098 21.332 18.5877 21.954 17.8377 21.954ZM25.1557 29.272H8.69014C7.94004 29.272 7.31801 28.65 7.31801 27.8999C7.31801 27.1498 7.94004 26.5278 8.69014 26.5278H25.1557C25.9058 26.5278 26.5278 27.1498 26.5278 27.8999C26.5278 28.65 25.9058 29.272 25.1557 29.272Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="34.7605" height="36.59" viewBox="0 0 34.7605 36.59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="docs">
<path id="Vector" opacity="0.4" d="M32.931 14.9836H27.6437C23.3078 14.9836 19.7769 11.4527 19.7769 7.11675V1.8295C19.7769 0.823275 18.9536 0 17.9474 0H10.1903C4.55545 0 0 3.659 0 10.1903V26.3997C0 32.931 4.55545 36.59 10.1903 36.59H24.5702C30.205 36.59 34.7605 32.931 34.7605 26.3997V16.8131C34.7605 15.8069 33.9372 14.9836 32.931 14.9836Z" fill="black"/>
<path id="Vector_2" d="M24.3324 0.384182C23.5823 -0.365913 22.2833 0.146347 22.2833 1.18916V7.57412C22.2833 10.2452 24.5519 12.4589 27.3144 12.4589C29.0525 12.4772 31.4674 12.4772 33.5347 12.4772C34.5776 12.4772 35.1264 11.2514 34.3946 10.5196C31.7601 7.86684 27.04 3.09184 24.3324 0.384182ZM20.1245 21.4966H9.1475C8.3974 21.4966 7.77537 20.8746 7.77537 20.1245C7.77537 19.3744 8.3974 18.7524 9.1475 18.7524H20.1245C20.8746 18.7524 21.4966 19.3744 21.4966 20.1245C21.4966 20.8746 20.8746 21.4966 20.1245 21.4966ZM16.4655 28.8146H9.1475C8.3974 28.8146 7.77537 28.1926 7.77537 27.4425C7.77537 26.6924 8.3974 26.0704 9.1475 26.0704H16.4655C17.2156 26.0704 17.8376 26.6924 17.8376 27.4425C17.8376 28.1926 17.2156 28.8146 16.4655 28.8146Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="36.6648" height="36.6648" viewBox="0 0 36.6648 36.6648" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 81">
<path id="Vector" opacity="0.4" d="M32.7836 34.7215C31.042 36.0048 28.7503 36.6648 26.0186 36.6648H10.6553C10.2153 36.6648 9.7753 36.6465 9.35364 36.5915L22.0036 23.9415L32.7836 34.7215ZM36.6648 10.6553V26.0187C36.6648 28.7503 36.0048 31.042 34.7215 32.7837L23.9415 22.0037L36.5915 9.35367C36.6465 9.77533 36.6648 10.2153 36.6648 10.6553Z" fill="#222222"/>
<path id="Vector_2" opacity="0.4" d="M23.9433 22L34.7233 32.78C34.1917 33.55 33.55 34.1917 32.78 34.7233L22 23.9433L9.35 36.5933C8.17667 36.52 7.11333 36.2817 6.14167 35.915C2.21833 34.485 0 31.0017 0 26.015V10.6517C0 3.97833 3.97833 0 10.6517 0H26.015C31.0017 0 34.485 2.21833 35.915 6.14167C36.2817 7.11333 36.52 8.17667 36.5933 9.35L23.9433 22Z" fill="#222222"/>
<path id="Vector_3" d="M23.947 22.0037L34.727 32.7837C34.1953 33.5537 33.5537 34.1953 32.7837 34.727L22.0037 23.947L9.35366 36.597C8.18032 36.5237 7.11699 36.2853 6.14532 35.9187L6.86032 35.2037L35.9187 6.14532C36.2853 7.11699 36.5237 8.18032 36.597 9.35366L23.947 22.0037ZM18.7733 10.8735C18.0767 7.84849 15.4 6.49182 13.0533 6.47349C10.7067 6.47349 8.02999 7.83016 7.33332 10.8552C6.56332 14.2102 8.61666 17.0152 10.4683 18.7752C11.2017 19.4718 12.1183 19.8018 13.0533 19.8018C13.9883 19.8018 14.905 19.4535 15.6383 18.7752C17.49 17.0152 19.5433 14.2102 18.7733 10.8735ZM13.1083 13.7335C12.1 13.7335 11.275 12.9085 11.275 11.9002C11.275 10.8918 12.0817 10.0668 13.1083 10.0668H13.1267C14.135 10.0668 14.96 10.8918 14.96 11.9002C14.96 12.9085 14.1167 13.7335 13.1083 13.7335Z" fill="#222222"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="36.59" height="36.59" viewBox="0 0 36.59 36.59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Bulk/messageadd">
<path id="Vector" opacity="0.4" d="M33.5408 11.3277V20.4752C33.5408 22.762 32.7785 24.6678 31.4369 26.0094C30.1105 27.3358 28.2048 28.0981 25.9179 28.0981V31.3454C25.9179 32.5651 24.561 33.2969 23.5548 32.6261L16.7704 28.0981H13.5383C13.6603 27.6407 13.7212 27.1681 13.7212 26.6802C13.7212 25.1251 13.1267 23.692 12.1509 22.6096C11.5839 21.9689 10.8866 21.4566 10.1058 21.1069C9.32495 20.7573 8.47848 20.5783 7.62292 20.5819C5.91538 20.5819 4.36031 21.2832 3.24736 22.4266C3.11015 21.8168 3.04917 21.1612 3.04917 20.4752V11.3277C3.04917 6.7539 6.09833 3.70474 10.6721 3.70474H25.9179C30.4917 3.70474 33.5408 6.7539 33.5408 11.3277Z" fill="#727272"/>
<path id="Vector_2" d="M23.631 17.1516H12.959C12.3339 17.1516 11.8155 16.6332 11.8155 16.0081C11.8155 15.383 12.3339 14.8647 12.959 14.8647H23.631C24.2561 14.8647 24.7745 15.383 24.7745 16.0081C24.7745 16.6332 24.2561 17.1516 23.631 17.1516ZM7.94308 20.6002C6.28128 20.4934 4.57375 21.1033 3.30835 22.3687C2.1662 23.5141 1.52483 25.0657 1.52483 26.6833C1.52483 28.3008 2.1662 29.8524 3.30835 30.9978C4.11638 31.8059 5.10735 32.3395 6.15932 32.5986C6.73866 32.7511 7.34849 32.7968 7.95832 32.7663C9.40668 32.7054 10.8245 32.126 11.9375 31.0131C12.6819 30.2711 13.2208 29.3484 13.5014 28.3355C13.7821 27.3226 13.7948 26.2542 13.5383 25.2349C13.2944 24.1829 12.7455 23.192 11.9375 22.3839C10.8765 21.3099 9.451 20.6733 7.94308 20.6002ZM11.038 26.6528C11.038 26.9729 10.916 27.2474 10.7026 27.4608C10.4891 27.6742 10.2147 27.7962 9.89455 27.7962H8.76635V28.9854C8.76635 29.3055 8.64439 29.58 8.43095 29.7934C8.2175 30.0068 7.94308 30.1288 7.62292 30.1288C6.99784 30.1288 6.47948 29.6105 6.47948 28.9854V27.7962H5.33604C4.71096 27.7962 4.1926 27.2778 4.1926 26.6528C4.1926 26.0277 4.71096 25.5093 5.33604 25.5093H6.47948V24.4269C6.47948 23.8018 6.99784 23.2834 7.62292 23.2834C8.248 23.2834 8.76635 23.8018 8.76635 24.4269V25.5093H9.89455C10.5349 25.5093 11.038 26.0277 11.038 26.6528Z" fill="#727272"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="36.59" height="36.59" viewBox="0 0 36.59 36.59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Bulk/profilecircle">
<path id="Vector" opacity="0.4" d="M18.295 33.5591C26.7153 33.5591 33.5408 26.7336 33.5408 18.3133C33.5408 9.89302 26.7153 3.06746 18.295 3.06746C9.87473 3.06746 3.04917 9.89302 3.04917 18.3133C3.04917 26.7336 9.87473 33.5591 18.295 33.5591Z" fill="black"/>
<path id="Vector_2" d="M18.295 10.5821C15.1391 10.5821 12.5778 13.1434 12.5778 16.2993C12.5778 19.3942 15.0019 21.9098 18.2188 22.0013H18.4932C19.9731 21.9526 21.3762 21.3306 22.406 20.2666C23.4359 19.2027 24.0118 17.7801 24.0122 16.2993C24.0122 13.1434 21.4509 10.5821 18.295 10.5821ZM28.6301 29.5129C25.8165 32.1135 22.1249 33.5564 18.2935 33.553C14.2991 33.553 10.6706 32.0132 7.9568 29.5129C8.3227 28.1255 9.31368 26.8601 10.762 25.8844C14.9241 23.1096 21.6933 23.1096 25.8249 25.8844C27.2885 26.8601 28.2642 28.1255 28.6301 29.5129Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="36.59" height="36.59" viewBox="0 0 36.59 36.59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 83">
<path id="Vector" opacity="0.4" d="M18.295 36.59C28.3993 36.59 36.59 28.3993 36.59 18.295C36.59 8.19067 28.3993 0 18.295 0C8.19067 0 0 8.19067 0 18.295C0 28.3993 8.19067 36.59 18.295 36.59Z" fill="black"/>
<path id="Vector_2" d="M18.295 32.4736C10.483 32.4736 4.11637 26.107 4.11637 18.295C4.11637 15.8069 4.775 13.3736 6.00076 11.2331C6.38496 10.5745 7.22653 10.355 7.86685 10.7209L18.9719 17.1058C19.6305 17.49 19.8501 18.3133 19.4842 18.9719C19.1 19.6305 18.2767 19.8501 17.6181 19.4842L7.77537 13.831C7.18993 15.2397 6.87892 16.7582 6.87892 18.295C6.87892 24.6068 12.0015 29.7294 18.3133 29.7294C24.6251 29.7294 29.7477 24.6068 29.7477 18.295C29.7463 16.1721 29.1542 14.0914 28.0375 12.2859C26.9208 10.4804 25.3237 9.02123 23.4249 8.07183C21.5261 7.12242 19.4005 6.7202 17.2861 6.91017C15.1717 7.10015 13.1518 7.87483 11.4527 9.1475C11.3085 9.25562 11.1445 9.33428 10.9699 9.379C10.7954 9.42372 10.6137 9.43362 10.4353 9.40814C10.257 9.38265 10.0854 9.32229 9.93031 9.23048C9.77526 9.13867 9.63981 9.01723 9.53169 8.87308C9.42358 8.72892 9.34492 8.56489 9.3002 8.39034C9.25548 8.21579 9.24558 8.03413 9.27106 7.85575C9.32253 7.4955 9.51499 7.17045 9.80612 6.9521C12.2582 5.10724 15.2447 4.11174 18.3133 4.11638C26.1253 4.11638 32.4919 10.483 32.4919 18.295C32.4919 26.107 26.107 32.4736 18.295 32.4736Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+7
View File
@@ -0,0 +1,7 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="36.59" height="36.59" viewBox="0 0 36.59 36.59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Bulk/documentfilter">
<path id="Vector" d="M4.9244 1.52458H17.3193C18.356 1.52458 19.1945 2.37835 19.1945 3.43031V5.51899C19.1945 6.28128 18.7219 7.22653 18.2493 7.69915L14.2091 11.3124C13.645 11.785 13.2639 12.7455 13.2639 13.4926V17.5784C13.2639 18.1425 12.8827 18.9048 12.4254 19.1945L11.1142 20.0483C9.89455 20.8106 8.20226 19.9568 8.20226 18.4322V13.3858C8.20226 12.715 7.82111 11.8613 7.45521 11.3886L3.88769 7.57718C3.41507 7.10456 3.04917 6.25079 3.04917 5.67145V3.4913C3.04917 2.37835 3.88769 1.52458 4.9244 1.52458Z" fill="#727272"/>
<path id="Vector_2" opacity="0.4" d="M25.9179 3.04917H22.2589C21.832 3.04917 21.4966 3.38458 21.4966 3.81146V5.51899C21.4966 7.02833 20.6886 8.50718 19.8958 9.3152L15.7489 13.0199C15.7032 13.1267 15.627 13.2791 15.5812 13.4011V17.5937C15.5812 18.9811 14.758 20.4904 13.6298 21.1765L12.3796 21.9845C11.6783 22.4266 10.9008 22.6401 10.1232 22.6401C9.42192 22.6401 8.72062 22.4571 8.08029 22.1065C7.08931 21.5576 6.40325 20.6581 6.09833 19.6214V15.566C6.09955 15.466 6.07983 15.3669 6.04045 15.275C6.00106 15.1831 5.94288 15.1005 5.86965 15.0324L4.34506 13.5078C3.8572 13.0352 3.04917 13.3706 3.04917 14.0414V25.9179C3.04917 30.1258 6.46423 33.5408 10.6721 33.5408H25.9179C30.1258 33.5408 33.5408 30.1258 33.5408 25.9179V10.6721C33.5408 6.46423 30.1258 3.04917 25.9179 3.04917Z" fill="#727272"/>
<path id="Vector_3" d="M27.4425 20.963H19.8196C19.1945 20.963 18.6761 20.4447 18.6761 19.8196C18.6761 19.1945 19.1945 18.6761 19.8196 18.6761H27.4425C28.0676 18.6761 28.5859 19.1945 28.5859 19.8196C28.5859 20.4447 28.0676 20.963 27.4425 20.963ZM27.4425 27.0614H16.7704C16.1453 27.0614 15.627 26.543 15.627 25.9179C15.627 25.2928 16.1453 24.7745 16.7704 24.7745H27.4425C28.0676 24.7745 28.5859 25.2928 28.5859 25.9179C28.5859 26.543 28.0676 27.0614 27.4425 27.0614Z" fill="#727272"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+6
View File
@@ -0,0 +1,6 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Iconsax/Bulk/statusup">
<path id="Vector" opacity="0.4" d="M26.3088 3.25H12.6913C6.77625 3.25 3.25 6.77625 3.25 12.6912V26.2925C3.25 32.2238 6.77625 35.75 12.6913 35.75H26.2925C32.2075 35.75 35.7338 32.2238 35.7338 26.3088V12.6912C35.75 6.77625 32.2238 3.25 26.3088 3.25Z" fill="black"/>
<path id="Vector_2" d="M11.18 30.7093C10.5138 30.7093 9.96125 30.1568 9.96125 29.4905V26.1267C9.96125 25.4605 10.5138 24.908 11.18 24.908C11.8463 24.908 12.3988 25.4605 12.3988 26.1267V29.4905C12.3988 30.173 11.8463 30.7093 11.18 30.7093ZM19.5 30.7125C18.8337 30.7125 18.2812 30.16 18.2812 29.4937V22.75C18.2812 22.0837 18.8337 21.5312 19.5 21.5312C20.1663 21.5312 20.7188 22.0837 20.7188 22.75V29.4937C20.7188 30.1762 20.1663 30.7125 19.5 30.7125ZM27.82 30.7125C27.1538 30.7125 26.6013 30.16 26.6013 29.4937V19.3863C26.6013 18.72 27.1538 18.1675 27.82 18.1675C28.4863 18.1675 29.0388 18.72 29.0388 19.3863V29.4937C29.0388 30.1762 28.5025 30.7125 27.82 30.7125ZM29.0404 9.46075C29.0404 9.3795 29.0079 9.282 28.9916 9.20075L28.9429 8.9895C28.9104 8.9245 28.8616 8.87575 28.8291 8.81075C28.7804 8.74575 28.7316 8.6645 28.6666 8.61575C28.6504 8.5995 28.6504 8.58325 28.6341 8.58325C28.5854 8.55075 28.5366 8.5345 28.4879 8.502C28.4178 8.44922 28.3414 8.40554 28.2604 8.372C28.1791 8.3395 28.0979 8.3395 28.0166 8.32325C27.9516 8.307 27.9029 8.29075 27.8379 8.29075H23.0766C22.4104 8.29075 21.8579 8.84325 21.8579 9.5095C21.8579 10.1758 22.4104 10.7283 23.0766 10.7283H25.1079C21.2404 14.7908 16.3654 17.6508 10.8891 19.032C10.2391 19.1945 9.83288 19.8607 9.99538 20.5107C10.1254 21.0632 10.6291 21.437 11.1816 21.437C11.2791 21.437 11.3766 21.4207 11.4741 21.4045C17.2754 19.9583 22.4591 16.952 26.6029 12.6945V14.2707C26.6029 14.937 27.1554 15.4895 27.8216 15.4895C28.4879 15.4895 29.0404 14.937 29.0404 14.2707V9.46075Z" fill="black"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="83.9801" height="24" viewBox="0 0 83.9801 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Frame 4">
<path id="Vector" d="M14.19 2H5.81C2.17 2 0 4.17 0 7.81V16.18C0 19.83 2.17 22 5.81 22H14.18C17.82 22 19.99 19.83 19.99 16.19V7.81C20 4.17 17.83 2 14.19 2ZM15 17.25H5C4.59 17.25 4.25 16.91 4.25 16.5C4.25 16.09 4.59 15.75 5 15.75H15C15.41 15.75 15.75 16.09 15.75 16.5C15.75 16.91 15.41 17.25 15 17.25ZM15 12.75H5C4.59 12.75 4.25 12.41 4.25 12C4.25 11.59 4.59 11.25 5 11.25H15C15.41 11.25 15.75 11.59 15.75 12C15.75 12.41 15.41 12.75 15 12.75ZM15 8.25H5C4.59 8.25 4.25 7.91 4.25 7.5C4.25 7.09 4.59 6.75 5 6.75H15C15.41 6.75 15.75 7.09 15.75 7.5C15.75 7.91 15.41 8.25 15 8.25Z" fill="#727272"/>
<path id="Vector_2" d="M44.18 2H35.8C32.16 2 29.99 4.17 29.99 7.81V16.18C29.99 19.83 32.16 22 35.8 22H44.17C47.81 22 49.98 19.83 49.98 16.19V7.81C49.99 4.17 47.82 2 44.18 2ZM35.66 5.5C35.66 5.09 36 4.75 36.41 4.75C36.82 4.75 37.16 5.09 37.16 5.5V9.4C37.16 9.81 36.82 10.15 36.41 10.15C36 10.15 35.66 9.81 35.66 9.4V5.5ZM37.513 16.431C37.4117 16.4721 37.3244 16.5416 37.2618 16.6313C37.1992 16.7209 37.1638 16.8267 37.16 16.936V18.5C37.16 18.91 36.82 19.25 36.41 19.25C36 19.25 35.66 18.91 35.66 18.5V16.936C35.6561 16.8268 35.6207 16.721 35.5581 16.6314C35.4955 16.5418 35.4083 16.4722 35.307 16.431C34.8261 16.2186 34.4172 15.871 34.1302 15.4306C33.8431 14.9901 33.6902 14.4757 33.69 13.95C33.69 12.45 34.91 11.22 36.41 11.22C37.91 11.22 39.14 12.44 39.14 13.95C39.14 15.058 38.47 16.007 37.513 16.431ZM44.32 18.5C44.32 18.91 43.98 19.25 43.57 19.25C43.16 19.25 42.82 18.91 42.82 18.5V14.6C42.82 14.19 43.16 13.85 43.57 13.85C43.98 13.85 44.32 14.19 44.32 14.6V18.5ZM43.57 12.77C42.07 12.77 40.84 11.55 40.84 10.04C40.84 8.932 41.51 7.983 42.467 7.559C42.5684 7.51792 42.6556 7.44836 42.7183 7.35874C42.7809 7.26912 42.8163 7.16328 42.82 7.054V5.5C42.82 5.09 43.16 4.75 43.57 4.75C43.98 4.75 44.32 5.09 44.32 5.5V7.064C44.32 7.287 44.47 7.478 44.673 7.569C45.154 7.78139 45.5628 8.12895 45.8499 8.56941C46.137 9.00987 46.2899 9.52425 46.29 10.05C46.29 11.55 45.07 12.77 43.57 12.77Z" fill="#727272"/>
<g id="Iconsax/Bold/more">
<path id="Vector_3" d="M76.1701 2H67.7901C64.1501 2 61.9801 4.17 61.9801 7.81V16.18C61.9801 19.83 64.1501 22 67.7901 22H76.1601C79.8001 22 81.9701 19.83 81.9701 16.19V7.81C81.9801 4.17 79.8101 2 76.1701 2ZM66.9801 13.31C66.2601 13.31 65.6701 12.72 65.6701 12C65.6701 11.28 66.2601 10.69 66.9801 10.69C67.7001 10.69 68.2901 11.28 68.2901 12C68.2901 12.72 67.7001 13.31 66.9801 13.31ZM71.9801 13.31C71.2601 13.31 70.6701 12.72 70.6701 12C70.6701 11.28 71.2601 10.69 71.9801 10.69C72.7001 10.69 73.2901 11.28 73.2901 12C73.2901 12.72 72.7001 13.31 71.9801 13.31ZM76.9801 13.31C76.2601 13.31 75.6701 12.72 75.6701 12C75.6701 11.28 76.2601 10.69 76.9801 10.69C77.7001 10.69 78.2901 11.28 78.2901 12C78.2901 12.72 77.7001 13.31 76.9801 13.31Z" fill="#727272"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

+148
View File
@@ -0,0 +1,148 @@
// Ассеты, выгруженные из Figma (Government Dashboards)
import eventCrash from './figma/event-crash.jpg'
import eventHouse from './figma/event-house.jpg'
import eventPlane from './figma/event-plane.jpg'
import eventExplosion from './figma/event-explosion.jpg'
import city1 from './figma/city-1.jpg'
import city2 from './figma/city-2.jpg'
import city3 from './figma/city-3.jpg'
import city4 from './figma/city-4.jpg'
import city5 from './figma/city-5.jpg'
import city6 from './figma/city-6.jpg'
import avatar1 from './figma/avatar-1.png'
import avatar2 from './figma/avatar-2.png'
import avatar3 from './figma/avatar-3.png'
import avatar4 from './figma/avatar-4.png'
import avatarPlaceholder from './figma/avatar-placeholder.svg'
import avatarBadge from './figma/avatar-badge.svg'
import earth from './figma/earth.png'
import radarMap from './figma/radar-map.jpg'
import notifyEmblem from './figma/notify-emblem.png'
import statProgress from './figma/stat-progress.png'
import btnCamera from './figma/btn-camera.svg'
import btnAmbulance from './figma/btn-ambulance.svg'
import btnPolice from './figma/btn-police.svg'
import btnUtility from './figma/btn-utility.svg'
import btnMchs from './figma/btn-mchs.svg'
import tileMap from './figma/tile-map.svg'
import tileEvents from './figma/tile-events.svg'
import tileAviation from './figma/tile-aviation.svg'
import tileRadar from './figma/tile-radar.svg'
import tileJournal from './figma/tile-journal.svg'
import tileMessages from './figma/tile-messages.svg'
import tileSchedule from './figma/tile-schedule.svg'
import tileStats from './figma/tile-stats.svg'
import tileProfile from './figma/tile-profile.svg'
import iconMap from './figma/icon-map.svg'
import iconRadar from './figma/icon-radar.svg'
import iconStats from './figma/icon-stats.svg'
import iconJournalA from './figma/icon-journal-a.svg'
import iconJournalB from './figma/icon-journal-b.svg'
import iconProfileA from './figma/icon-profile-a.svg'
import iconProfileB from './figma/icon-profile-b.svg'
import iconEdit from './figma/icon-edit.svg'
import iconBuildings from './figma/icon-buildings.svg'
import iconFlash from './figma/icon-flash.svg'
import iconStatA from './figma/icon-stat-a.svg'
import iconStatB from './figma/icon-stat-b.svg'
import iconStatC from './figma/icon-stat-c.svg'
import iconClockSmall from './figma/icon-clock-small.svg'
import camBadge from './figma/cam-badge.svg'
import widgetSettings from './figma/widget-settings.svg'
import statIcon1 from './figma/stat-icon-1.svg'
import statTrack from './figma/stat-track.svg'
import statUnderline from './figma/stat-underline.svg'
import gaugeDial from './figma/gauge-dial.svg'
import gaugeDial2 from './figma/gauge-dial-2.svg'
import gaugeNeedle from './figma/gauge-needle.svg'
import gaugeNeedle2 from './figma/gauge-needle-2.svg'
import globeRingInner from './figma/globe-ring-inner.svg'
import globeRingEdge from './figma/globe-ring-edge.svg'
import globeRingArc from './figma/globe-ring-arc.svg'
import globeArrowLeft from './figma/globe-arrow-left.svg'
import globeArrowUp from './figma/globe-arrow-up.svg'
import radarEllipse1 from './figma/radar-ellipse-1.svg'
import radarEllipse2 from './figma/radar-ellipse-2.svg'
import radarEllipse3 from './figma/radar-ellipse-3.svg'
import radarPinLine from './figma/radar-pin-line.svg'
import radarCorner from './figma/radar-corner.svg'
import radarCaptionLine from './figma/radar-caption-line.svg'
import radarArrow from './figma/radar-arrow.svg'
import markerPin from './figma/marker-pin.svg'
import markerDot from './figma/marker-dot.svg'
export const img = {
eventCrash,
eventHouse,
eventPlane,
eventExplosion,
cities: [city1, city2, city3, city4, city5, city6],
avatars: [avatar1, avatar2, avatar3, avatar4],
avatarPlaceholder,
avatarBadge,
earth,
radarMap,
notifyEmblem,
statProgress,
}
export const icons = {
btnCamera,
btnAmbulance,
btnPolice,
btnUtility,
btnMchs,
tileMap,
tileEvents,
tileAviation,
tileRadar,
tileJournal,
tileMessages,
tileSchedule,
tileStats,
tileProfile,
iconMap,
iconRadar,
iconStats,
iconJournalA,
iconJournalB,
iconProfileA,
iconProfileB,
iconEdit,
iconBuildings,
iconFlash,
iconStatA,
iconStatB,
iconStatC,
iconClockSmall,
camBadge,
widgetSettings,
statIcon1,
statTrack,
statUnderline,
gaugeDial,
gaugeDial2,
gaugeNeedle,
gaugeNeedle2,
globeRingInner,
globeRingEdge,
globeRingArc,
globeArrowLeft,
globeArrowUp,
radarEllipse1,
radarEllipse2,
radarEllipse3,
radarPinLine,
radarCorner,
radarCaptionLine,
radarArrow,
markerPin,
markerDot,
}
+57
View File
@@ -0,0 +1,57 @@
import { icons } from '../assets'
import { AGENCY_LABEL, employeeById } from '../data/people'
import { useStore } from '../store/useStore'
import type { DispatchKey, Incident } from '../types'
import { MaskIcon } from './Icon'
const ICON: Record<DispatchKey, string> = {
camera: icons.btnCamera,
ambulance: icons.btnAmbulance,
police: icons.btnPolice,
utility: icons.btnUtility,
mchs: icons.btnMchs,
gibdd: icons.btnPolice,
}
export function DispatchButtons({ inc, withCamera = true, compact }: { inc: Incident; withCamera?: boolean; compact?: boolean }) {
const dispatch = useStore((s) => s.dispatch)
const openCamera = useStore((s) => s.openCamera)
const keys: DispatchKey[] = [...(withCamera ? (['camera'] as const) : []), ...inc.required]
// ведомства, уже выехавшие сверх обязательных (например, ГИБДД на месте)
for (const a of Object.keys(inc.dispatched) as DispatchKey[]) if (!keys.includes(a)) keys.push(a)
return (
<div className={`dispatch${compact ? ' dispatch--compact' : ''}`}>
{keys.map((k) => {
const d = k === 'camera' ? undefined : inc.dispatched[k]
const on = k === 'camera' ? !!inc.cameraOpen : !!d
const emp = d?.employeeId ? employeeById(d.employeeId) : undefined
const label = k === 'camera' ? 'Камера' : AGENCY_LABEL[k]
const title =
k === 'camera'
? 'Переключиться на камеру дрона'
: d
? `${label}: ${emp?.name ?? 'выехали'} · назначил ${d.by === 'ai' ? 'ИИ' : 'оператор'}`
: `Вызвать: ${label}`
return (
<button
key={k}
className={`btn tone-${k}${on ? ' is-on' : ''}${k === 'ambulance' ? ' btn--light-text' : ''}`}
aria-pressed={on}
title={title}
disabled={k !== 'camera' && (on || inc.status === 'resolved')}
onClick={(e) => {
e.stopPropagation()
if (k === 'camera') openCamera(inc.id)
else dispatch(inc.id, k)
}}
>
<MaskIcon src={ICON[k]} width="0.8em" height="0.75em" />
{label}
{d?.by === 'ai' && <span className="dispatch-ai">ИИ</span>}
</button>
)
})}
</div>
)
}
+154
View File
@@ -0,0 +1,154 @@
.fab {
--fab: 4.8rem;
position: relative;
width: calc(var(--fab) * 1.75);
height: calc(var(--fab) * 1.45);
}
.fab-main {
position: absolute;
left: 0;
top: 0;
width: var(--fab);
height: var(--fab);
border-radius: 50%;
display: grid;
place-items: center;
color: #fff;
background: radial-gradient(circle at 35% 30%, #a9bcff 0%, var(--c-blue) 55%, #5b78e0 100%);
box-shadow:
0 0 0 calc(var(--fab) * 0.06) color-mix(in srgb, var(--c-lavender) 35%, transparent),
0 0 calc(var(--fab) * 0.33) color-mix(in srgb, var(--c-blue) 80%, transparent);
transition: transform 0.15s;
}
.fab-main:hover {
transform: scale(1.04);
}
.fab-main:active {
transform: scale(0.97);
}
.fab-sat {
position: absolute;
width: calc(var(--fab) * 0.346);
height: calc(var(--fab) * 0.346);
border-radius: 50%;
display: grid;
place-items: center;
color: #fff;
background: #222;
border: var(--stroke) solid var(--border);
box-shadow: var(--shadow);
}
.fab-sat:hover {
border-color: var(--c-blue);
box-shadow: 0 0 10px color-mix(in srgb, var(--c-blue) 50%, transparent);
}
.fab-sat.is-on {
background: var(--c-green);
color: #222;
}
/* позиции спутников — по макету относительно центра главной кнопки */
.fab-sat--call {
left: calc(var(--fab) * 0.5 + var(--fab) * 0.64 - var(--fab) * 0.173);
top: calc(var(--fab) * 0.5 - var(--fab) * 0.3 - var(--fab) * 0.173);
}
.fab-sat--msg {
left: calc(var(--fab) * 0.5 + var(--fab) * 0.67 - var(--fab) * 0.173);
top: calc(var(--fab) * 0.5 + var(--fab) * 0.3 - var(--fab) * 0.173);
}
.fab-sat--audio {
left: calc(var(--fab) * 0.5 + var(--fab) * 0.21 - var(--fab) * 0.173);
top: calc(var(--fab) * 0.5 + var(--fab) * 0.66 - var(--fab) * 0.173);
}
.fab-menu {
position: absolute;
left: 0;
bottom: calc(100% + 0.5rem);
z-index: 70;
width: 13rem;
padding: 0.5rem;
border-radius: var(--radius-md);
border: var(--stroke) solid var(--border);
background: var(--surface);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
animation: fade-in 0.15s ease-out;
}
.fab-menu-title {
padding: 0.2rem 0.5rem 0.4rem;
font-size: var(--fs-xs);
color: var(--text-2);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.fab-menu-item {
width: 100%;
display: flex;
justify-content: space-between;
padding: 0.5rem;
border-radius: var(--radius-sm);
font-weight: var(--w-semibold);
}
.fab-menu-item:hover {
background: var(--surface-2);
}
.fab-menu-phone {
color: var(--c-red);
}
.call {
position: fixed;
left: 50%;
bottom: 1.5rem;
transform: translateX(-50%);
z-index: 80;
display: flex;
align-items: center;
gap: 0.8rem;
padding: 0.6rem 0.7rem 0.6rem 0.8rem;
border-radius: 999px;
background: var(--surface);
border: var(--stroke) solid var(--c-green);
box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
animation: fade-in 0.2s ease-out;
}
.call-icon {
width: 2.2rem;
height: 2.2rem;
border-radius: 50%;
display: grid;
place-items: center;
background: var(--c-green);
color: #222;
}
.call-icon.is-ringing {
animation: ring 0.9s ease-in-out infinite;
}
.call-text {
display: flex;
flex-direction: column;
gap: 0.1rem;
font-size: var(--fs-sm);
}
.call-end {
margin-left: 0.4rem;
padding: 0.5rem 0.9rem;
border-radius: 999px;
background: var(--c-red);
color: #fff;
font-weight: var(--w-semibold);
}
@keyframes ring {
0%,
100% {
transform: rotate(0);
}
25% {
transform: rotate(-14deg);
}
75% {
transform: rotate(14deg);
}
}
+115
View File
@@ -0,0 +1,115 @@
import { useEffect, useRef, useState } from 'react'
import { AudioSquare, CallAdd, CallCalling, MessageNotif } from 'iconsax-react'
import { useStore } from '../store/useStore'
import { dialLabel, dialPhone } from '../data/people'
import type { Agency } from '../types'
import { Icon } from './Icon'
import { fmtDuration, useNow } from '../hooks/useNow'
import './EmergencyCall.css'
const DIAL: (Agency | 'unified')[] = ['unified', 'mchs', 'police', 'ambulance', 'utility']
export function EmergencyCall() {
const [open, setOpen] = useState(false)
const [radio, setRadio] = useState(false)
const startCall = useStore((s) => s.startCall)
const setDrawer = useStore((s) => s.setDrawer)
const pushToast = useStore((s) => s.pushToast)
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (!open) return
const close = (e: MouseEvent) => !ref.current?.contains(e.target as Node) && setOpen(false)
const esc = (e: KeyboardEvent) => e.key === 'Escape' && setOpen(false)
document.addEventListener('mousedown', close)
document.addEventListener('keydown', esc)
return () => {
document.removeEventListener('mousedown', close)
document.removeEventListener('keydown', esc)
}
}, [open])
return (
<div className="fab" ref={ref}>
<button
className="fab-main"
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
aria-haspopup="menu"
aria-label="Экстренный вызов ведомства"
>
<Icon icon={CallAdd} variant="Bold" size="42%" />
</button>
<button className="fab-sat fab-sat--call" onClick={() => setOpen(true)} aria-label="Новый вызов">
<Icon icon={CallAdd} variant="Bold" size="52%" />
</button>
<button className="fab-sat fab-sat--msg" onClick={() => setDrawer('messages')} aria-label="Сообщения">
<Icon icon={MessageNotif} variant="Outline" size="46%" />
</button>
<button
className={`fab-sat fab-sat--audio${radio ? ' is-on' : ''}`}
aria-pressed={radio}
aria-label="Радиоканал"
onClick={() => {
setRadio((v) => !v)
pushToast(radio ? 'Радиоканал отключён' : 'Радиоканал открыт: вас слышат все дежурные', 'info')
}}
>
<Icon icon={AudioSquare} variant="Outline" size="46%" />
</button>
{open && (
<div className="fab-menu" role="menu" aria-label="Вызов ведомства в один клик">
<p className="fab-menu-title">Вызов в 1 клик</p>
{DIAL.map((a) => (
<button
key={a}
role="menuitem"
className="fab-menu-item"
onClick={() => {
startCall(a)
setOpen(false)
}}
>
<span>{dialLabel(a)}</span>
<span className="fab-menu-phone mono">{dialPhone(a)}</span>
</button>
))}
</div>
)}
</div>
)
}
export function CallOverlay() {
const call = useStore((s) => s.call)
const endCall = useStore((s) => s.endCall)
const pushToast = useStore((s) => s.pushToast)
const now = useNow(1000)
if (!call) return null
const sec = Math.max(0, Math.floor((now - call.startedAt) / 1000))
const connected = sec >= 2
return (
<div className="call" role="dialog" aria-live="polite" aria-label="Вызов">
<span className={`call-icon${connected ? '' : ' is-ringing'}`}>
<Icon icon={CallCalling} variant="Bold" size="1.3rem" />
</span>
<div className="call-text">
<strong>
{dialLabel(call.agency)} · {dialPhone(call.agency)}
</strong>
<span className="muted mono">{connected ? `Соединено ${fmtDuration(sec - 2)}` : 'Соединение…'}</span>
</div>
<button
className="call-end"
onClick={() => {
endCall()
pushToast(`Вызов «${dialLabel(call.agency)}» завершён`, 'ok')
}}
>
Завершить
</button>
</div>
)
}
+232
View File
@@ -0,0 +1,232 @@
.ev-body {
padding: 0 0.35rem 0.6rem 0.5rem;
}
.ev-list {
flex: 1;
min-height: 0;
padding: 0.1rem 0.45rem 0.2rem 0;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.ev {
position: relative;
display: grid;
grid-template-columns: 3.05rem minmax(0, 1fr);
gap: 0.75rem;
padding: 0.55rem 0.5rem;
border-radius: var(--radius-md);
transition: background-color 0.2s;
animation: fade-in 0.25s ease-out;
}
.ev + .ev::before {
content: '';
position: absolute;
left: 0.5rem;
right: 0.5rem;
top: -0.2rem;
height: 1px;
background: var(--divider);
}
.ev.is-selected::before,
.ev.is-selected + .ev::before {
display: none;
}
.ev:hover {
background: color-mix(in srgb, var(--text) 4%, transparent);
}
.ev-hit {
position: absolute;
inset: 0;
border-radius: inherit;
}
.ev-photo {
position: relative;
width: 3.05rem;
height: 3.95rem;
object-fit: cover;
border-radius: var(--radius-xs);
box-shadow: var(--shadow);
pointer-events: none;
}
.ev-main {
position: relative;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.2rem;
pointer-events: none;
}
.ev-main .dispatch,
.ev-main .ev-flag {
pointer-events: auto;
}
.ev-summary {
padding: 0 0.6rem 0.35rem;
font-size: var(--fs-2xs);
color: var(--text-3);
}
.ev-summary b {
color: var(--text);
}
.ev-summary b.c-red {
color: var(--c-red);
}
.ev-title {
font-size: var(--fs-md);
font-weight: var(--w-medium);
line-height: 1.2;
}
.ev-meta {
display: flex;
align-items: center;
gap: 0.4rem;
min-height: 1.1rem;
font-size: var(--fs-2xs);
}
.ev-flag-slot {
margin-left: auto;
}
.ev-addr {
font-size: var(--fs-2xs);
color: var(--text-3);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.ev-time {
display: inline-flex;
align-items: center;
gap: 0.25rem;
vertical-align: bottom;
color: var(--text);
opacity: 0.7;
}
.ev-flag {
display: inline-flex;
align-items: center;
gap: 0.2rem;
padding: 0.05rem 0.35rem;
border-radius: 999px;
font-size: var(--fs-2xs);
font-weight: var(--w-semibold);
white-space: nowrap;
}
.ev-cat {
flex: none;
padding: 0 0.3rem;
border-radius: 0.2rem;
border: 1px solid currentColor;
font-weight: var(--w-semibold);
}
.ev[data-sev='3'] .ev-cat {
color: var(--c-pink);
}
.ev-desc {
font-size: var(--fs-xs);
line-height: 1.3;
color: var(--text-2);
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.ev-flag--timer {
color: var(--c-orange);
border: 1px solid color-mix(in srgb, var(--c-orange) 60%, transparent);
}
.ev-flag--timer.is-hot {
color: #fff;
background: var(--c-red);
border-color: var(--c-red);
animation: hot 1s ease-in-out infinite;
}
.ev-flag--ai {
color: var(--c-green);
border: 1px solid color-mix(in srgb, var(--c-green) 60%, transparent);
}
.ev-flag--ok {
color: var(--text-3);
}
@keyframes hot {
50% {
box-shadow: 0 0 10px var(--c-red);
}
}
/* выбранное событие — зелёная плашка, как в макете */
.ev.is-selected {
background: var(--c-green);
color: #000;
}
.ev.is-selected .ev-desc,
.ev.is-selected .ev-time,
.ev.is-selected .ev-addr {
color: #222;
}
.ev.is-selected .ev-time {
opacity: 0.55;
}
.ev.is-selected .ev-cat {
color: #222;
}
.ev.is-selected .btn {
color: #222;
}
.ev.is-selected .btn.is-on.btn--light-text {
color: #fff;
}
.ev.is-selected .tone-mchs {
--tone: #fff;
}
.ev.is-selected .tone-mchs:not(.is-on) {
--tone: #222;
}
.ev.is-selected .tone-camera:not(.is-on) {
--tone: #222;
}
.ev.is-selected .ev-flag--timer {
color: #7a4a00;
border-color: #7a4a00;
}
.ev.is-selected .ev-flag--ai {
color: #0d5a2f;
border-color: #0d5a2f;
}
:root[data-contrast='true'] .ev.is-selected {
background: #fff35c;
}
.ev.is-resolved {
opacity: 0.5;
}
/* кнопки вызова ведомств */
.dispatch {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
}
.ev .dispatch {
margin-top: 0.25rem;
gap: 0.3rem;
}
.dispatch .btn {
justify-content: flex-start;
padding: 0.2rem 0.45rem;
}
.dispatch .btn:disabled {
cursor: default;
}
.dispatch--compact .btn {
min-width: 0;
}
.dispatch-ai {
margin-left: 0.15rem;
padding: 0 0.2rem;
border-radius: 0.2rem;
background: rgba(0, 0, 0, 0.25);
font-size: 0.5rem;
}
+115
View File
@@ -0,0 +1,115 @@
import { useEffect, useRef } from 'react'
import { Cpu, Timer1, TickCircle } from 'iconsax-react'
import { icons } from '../assets'
import { secondsToAi, useStore } from '../store/useStore'
import { CATEGORY_LABEL } from '../data/incidents'
import { fmtDate, fmtTime, useNow } from '../hooks/useNow'
import type { Incident } from '../types'
import { Panel, PanelIcon } from './Panel'
import { DispatchButtons } from './DispatchButtons'
import { Icon } from './Icon'
import './EventsFeed.css'
const SOURCE: Record<Incident['source'], string> = {
drone: 'дрон',
camera: 'камера',
call: 'вызов 112',
sensor: 'датчик',
}
function sortIncidents(list: Incident[]) {
return list.slice().sort((a, b) => {
const ra = a.status === 'resolved' ? 1 : 0
const rb = b.status === 'resolved' ? 1 : 0
if (ra !== rb) return ra - rb
if (a.severity !== b.severity) return b.severity - a.severity
return b.createdAt - a.createdAt
})
}
export function EventsFeed() {
const incidents = useStore((s) => s.incidents)
const selectedId = useStore((s) => s.selectedId)
const select = useStore((s) => s.select)
const mode = useStore((s) => s.settings.autopilot)
const now = useNow(1000)
const listRef = useRef<HTMLOListElement>(null)
const sorted = sortIncidents(incidents)
const open = incidents.filter((i) => i.status !== 'resolved').length
const waiting = incidents.filter((i) => i.status !== 'resolved' && i.required.some((a) => !i.dispatched[a])).length
useEffect(() => {
const el = listRef.current?.querySelector<HTMLElement>('.ev.is-selected')
el?.scrollIntoView({ block: 'nearest', behavior: 'smooth' })
}, [selectedId])
return (
<Panel
id="events"
title="Самые важные события"
icon={<PanelIcon src={icons.iconRadar} w="1.05em" h="0.66em" />}
bodyClassName="ev-body"
>
<p className="ev-summary">
Открыто <b>{open}</b> · ждут решения <b className="c-red">{waiting}</b>
</p>
<ol className="ev-list scroll" ref={listRef}>
{sorted.map((inc) => {
const left = secondsToAi(inc, mode, now)
const aiAssigned = Object.values(inc.dispatched).some((d) => d?.by === 'ai')
const selected = inc.id === selectedId
return (
<li
key={inc.id}
className={`ev${selected ? ' is-selected' : ''}${inc.status === 'resolved' ? ' is-resolved' : ''}`}
data-sev={inc.severity}
>
<button className="ev-hit" onClick={() => select(inc.id)} aria-pressed={selected} aria-label={`Показать на карте: ${inc.title}`} />
<img className="ev-photo" src={inc.photo} alt="" />
<div className="ev-main">
<h3 className="ev-title">{inc.title}</h3>
<div className="ev-meta">
<span className="ev-cat">{CATEGORY_LABEL[inc.category]}</span>
<span className="ev-flag-slot">{flag(inc, left, aiAssigned)}</span>
</div>
<p className="ev-addr">
<span className="ev-time">
<Icon icon={Timer1} variant="TwoTone" size="0.72rem" />
<span>{fmtTime(inc.createdAt)}</span>
<span className="thin">{fmtDate(inc.createdAt)}</span>
</span>{' '}
· {inc.address} · {SOURCE[inc.source]}
{inc.droneId ? ` ${inc.droneId}` : ''}
</p>
<p className="ev-desc">{inc.description}</p>
<DispatchButtons inc={inc} />
</div>
</li>
)
})}
</ol>
</Panel>
)
}
function flag(inc: Incident, left: number | null, aiAssigned: boolean) {
if (inc.status === 'resolved')
return (
<span className="ev-flag ev-flag--ok">
<Icon icon={TickCircle} variant="Bold" size="0.8rem" /> Решено
</span>
)
if (left !== null)
return (
<span className={`ev-flag ev-flag--timer${left <= 10 ? ' is-hot' : ''}`} title="Если оператор не отреагирует, ИИ назначит исполнителей сам">
<Icon icon={Cpu} variant="Bulk" size="0.8rem" /> ИИ через {left} с
</span>
)
if (aiAssigned)
return (
<span className="ev-flag ev-flag--ai">
<Icon icon={Cpu} variant="Bulk" size="0.8rem" /> Назначено ИИ
</span>
)
return null
}
+380
View File
@@ -0,0 +1,380 @@
/* --- бегущая строка --- */
.ticker {
display: flex;
align-items: center;
gap: 0.4rem;
height: 1rem;
flex: 0 1 28rem;
min-width: 0;
padding-left: 0.35rem;
border-radius: 0.25rem;
background: var(--surface);
font-size: var(--fs-2xs);
color: var(--text);
overflow: hidden;
}
.ticker-bell {
flex: none;
color: var(--c-orange);
}
.ticker-track {
position: relative;
flex: 1;
overflow: hidden;
-webkit-mask: linear-gradient(90deg, #000 85%, transparent);
mask: linear-gradient(90deg, #000 85%, transparent);
}
.ticker-run {
display: flex;
width: max-content;
animation: ticker 60s linear infinite;
}
.ticker-run > span {
padding-right: 4rem;
white-space: nowrap;
}
.ticker:hover .ticker-run {
animation-play-state: paused;
}
@keyframes ticker {
to {
transform: translateX(-50%);
}
}
/* --- плитки модулей --- */
.tiles {
--tile-accent: var(--c-cream);
container-type: inline-size;
display: grid;
grid-template-columns: repeat(10, minmax(0, 1fr));
gap: 0.625rem;
align-self: start;
}
.tiles[data-mode='3d'] {
--tile-accent: var(--c-green);
}
.tile {
position: relative;
aspect-ratio: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.45rem;
padding-top: 0.35rem;
min-height: 3.6rem;
border-radius: var(--radius-md);
background: var(--surface);
box-shadow: var(--shadow);
color: var(--text-3);
transition: background-color 0.2s, color 0.2s, transform 0.15s, box-shadow 0.2s;
}
/* узкая полоса плиток: только иконки, подпись — во всплывающей подсказке */
@container (max-width: 700px) {
.tile-label {
display: none;
}
.tile {
padding-top: 0;
}
}
.tile:hover {
color: var(--text);
transform: translateY(-1px);
}
.tile.is-on {
background: var(--tile-accent);
color: #222;
box-shadow: 0 0 20px var(--accent-glow);
}
.tile-label {
max-width: 100%;
padding: 0 0.15rem;
font-size: 0.53rem;
font-weight: var(--w-bold);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
:root[data-contrast='true'] .tile {
border: var(--stroke) solid var(--border);
}
/* --- уведомления от ведомств --- */
.notif {
position: relative;
min-height: 0;
height: 100%;
container-type: inline-size;
}
@container (max-width: 320px) {
.notif-emblem {
display: none;
}
.notif-card {
grid-template-columns: minmax(0, 1fr) auto;
padding: 0.45rem 0.6rem;
}
.notif-text p {
-webkit-line-clamp: 1;
}
.notif-actions .btn {
min-width: 0;
padding: 0.15rem 0.45rem;
}
}
.notif--empty {
display: grid;
place-items: center;
border: var(--stroke) dashed var(--border-soft);
border-radius: var(--radius-md);
font-size: var(--fs-sm);
}
.notif-card {
position: absolute;
inset: 0;
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 0.7rem;
padding: 0.55rem 0.8rem;
border-radius: var(--radius-md);
border: var(--stroke) solid rgba(255, 255, 255, 0.7);
background: color-mix(in srgb, #727272 80%, transparent);
backdrop-filter: blur(10px);
color: #fff;
animation: fade-in 0.25s ease-out;
}
.notif-card--back {
transform: translate(calc(var(--depth) * -0.16rem), calc(var(--depth) * -0.1rem));
opacity: calc(1 - var(--depth) * 0.2);
animation: none;
}
:root[data-night='false'] .notif-card {
background: color-mix(in srgb, #4d4d4d 88%, transparent);
}
:root[data-contrast='true'] .notif-card {
background: #000;
border-color: #fff;
}
.notif-emblem {
width: 2.55rem;
height: 2.65rem;
object-fit: contain;
}
.notif-emblem--icon {
display: grid;
place-items: center;
border-radius: 50%;
background: #222;
color: var(--c-cream);
}
.notif-text {
min-width: 0;
}
.notif-text h3 {
font-size: var(--fs-sm);
font-weight: var(--w-medium);
margin-bottom: 0.15rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.notif-text p {
font-size: var(--fs-2xs);
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.notif-actions {
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.notif-actions .btn {
min-width: 4.2rem;
}
.notif-close {
position: absolute;
top: -0.55rem;
right: -0.4rem;
width: 0.75rem;
height: 0.75rem;
display: grid;
place-items: center;
border-radius: 50%;
background: #222;
border: 1px solid #fff;
color: #fff;
font-size: 0.7rem;
line-height: 1;
}
.notif-close:hover {
background: var(--c-red);
}
.notif-clear {
position: absolute;
right: 0.9rem;
top: -0.95rem;
height: 0.75rem;
padding: 0 0.35rem;
border-radius: 0.15rem;
background: var(--surface-3);
font-size: var(--fs-2xs);
color: var(--text);
z-index: 2;
}
.notif-clear:hover {
background: var(--border);
}
.notif-count {
position: absolute;
left: 0.35rem;
top: 0.35rem;
min-width: 0.9rem;
height: 0.9rem;
padding: 0 0.2rem;
border-radius: 999px;
background: var(--c-red);
font-size: var(--fs-2xs);
font-weight: var(--w-bold);
display: grid;
place-items: center;
}
/* --- статус-бар --- */
.status {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 1.3rem;
height: 1.25rem;
font-size: var(--fs-2xs);
}
.status-item {
display: inline-flex;
align-items: center;
gap: 0.35rem;
color: var(--text);
}
.status-item svg {
color: var(--text-3);
}
button.status-item:hover svg {
color: var(--text);
}
.ai-mode {
position: relative;
flex: none;
}
.ai-pill {
display: inline-flex;
align-items: center;
gap: 0.35rem;
height: 1.1rem;
padding: 0 0.55rem;
border-radius: 999px;
white-space: nowrap;
border: var(--stroke) solid var(--border);
font-size: var(--fs-2xs);
color: var(--text);
}
.ai-pill b {
font-weight: var(--w-bold);
}
.ai-pill--auto {
border-color: var(--c-green);
color: var(--c-green);
box-shadow: 0 0 12px color-mix(in srgb, var(--c-green) 35%, transparent);
}
.ai-pill--semi {
border-color: var(--c-cream);
}
.ai-pill--semi svg {
color: var(--c-cream);
}
.ai-pill--manual svg {
color: var(--text-3);
}
.ai-menu {
position: absolute;
top: calc(100% + 0.4rem);
right: 0;
z-index: 50;
width: 15rem;
padding: 0.35rem;
border-radius: var(--radius-md);
border: var(--stroke) solid var(--border);
background: var(--surface);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
animation: fade-in 0.15s ease-out;
}
.ai-menu button {
width: 100%;
display: flex;
flex-direction: column;
gap: 0.1rem;
padding: 0.45rem 0.55rem;
border-radius: var(--radius-sm);
text-align: left;
font-size: var(--fs-sm);
}
.ai-menu button span {
font-size: var(--fs-xs);
color: var(--text-2);
}
.ai-menu button:hover,
.ai-menu button[aria-selected='true'] {
background: var(--surface-2);
}
.ai-menu button[aria-selected='true'] b {
color: var(--c-green);
}
/* --- тосты --- */
.toasts {
position: fixed;
right: 1.2rem;
bottom: 1.2rem;
z-index: 90;
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.5rem;
pointer-events: none;
}
.toast {
pointer-events: auto;
display: flex;
align-items: center;
gap: 0.5rem;
max-width: 24rem;
padding: 0.55rem 0.8rem;
border-radius: var(--radius-md);
border: var(--stroke) solid var(--border);
background: color-mix(in srgb, var(--surface) 94%, transparent);
backdrop-filter: blur(8px);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.4);
font-size: var(--fs-sm);
text-align: left;
animation: fade-in 0.2s ease-out;
}
.toast--ai {
border-color: var(--c-green);
}
.toast--ai svg {
color: var(--c-green);
}
.toast--warn {
border-color: var(--c-red);
}
.toast--warn svg {
color: var(--c-red);
}
.toast--ok {
border-color: var(--c-cream);
}
+233
View File
@@ -0,0 +1,233 @@
import { useEffect, useRef, useState } from 'react'
import { Clock, CloudNotif, Cpu, Danger, Health, LogoutCurve, MessageNotif, NotificationBing, Shield } from 'iconsax-react'
import { icons } from '../assets'
import { useStore, GRID_WIDGETS } from '../store/useStore'
import { WELCOME_TEXT } from '../data/misc'
import type { AutopilotMode, Notice, WidgetKey } from '../types'
import { Icon, MaskIcon } from './Icon'
import { fmtTime, useNow } from '../hooks/useNow'
import './Header.css'
export function Ticker() {
const incidents = useStore((s) => s.incidents)
const latest = incidents
.filter((i) => i.status !== 'resolved')
.slice(0, 3)
.map((i) => `${i.title} — ${i.address}`)
const text = [WELCOME_TEXT, ...latest].join(' • ')
return (
<div className="ticker" role="marquee" aria-label="Бегущая строка">
<Icon icon={NotificationBing} size="0.75rem" className="ticker-bell" />
<div className="ticker-track">
<div className="ticker-run">
<span>{text}</span>
<span aria-hidden>{text}</span>
</div>
</div>
</div>
)
}
const TILES: { key: WidgetKey; label: string; icon: string }[] = [
{ key: 'map', label: 'Карта', icon: icons.tileMap },
{ key: 'events', label: 'События', icon: icons.tileEvents },
{ key: 'aviation', label: 'Авиация', icon: icons.tileAviation },
{ key: 'radar', label: 'Радар', icon: icons.tileRadar },
{ key: 'journal', label: 'Журнал', icon: icons.tileJournal },
{ key: 'messages', label: 'Сообщения', icon: icons.tileMessages },
{ key: 'schedule', label: 'Расписания', icon: icons.tileSchedule },
{ key: 'tasks', label: 'Задачи', icon: icons.tileSchedule },
{ key: 'stats', label: 'Статистика', icon: icons.tileStats },
{ key: 'profile', label: 'Профиль', icon: icons.tileProfile },
]
export function ModuleTiles() {
const widgets = useStore((s) => s.widgets)
const drawer = useStore((s) => s.drawer)
const toggleWidget = useStore((s) => s.toggleWidget)
const mapMode = useStore((s) => s.mapMode)
return (
<div className="tiles" data-mode={mapMode} role="toolbar" aria-label="Модули">
{TILES.map((t) => {
const on = GRID_WIDGETS.includes(t.key) ? widgets[t.key] : drawer === t.key
return (
<button
key={t.key}
className={`tile${on ? ' is-on' : ''}`}
aria-pressed={on}
onClick={() => toggleWidget(t.key)}
title={on ? `Скрыть «${t.label}»` : `Показать «${t.label}»`}
>
<MaskIcon src={t.icon} width="1.35rem" height="1.35rem" />
<span className="tile-label">{t.label}</span>
</button>
)
})}
</div>
)
}
const NOTICE_ICON = { tax: Shield, health: Health, police: Shield, mchs: Danger }
export function NotificationStack() {
const notices = useStore((s) => s.notices)
const accept = useStore((s) => s.acceptNotice)
const decline = useStore((s) => s.declineNotice)
const clear = useStore((s) => s.clearNotices)
const stack = notices.slice(0, 4)
const top: Notice | undefined = stack[0]
if (!top) {
return (
<div className="notif notif--empty">
<p className="muted">Новых заданий от ведомств нет</p>
</div>
)
}
return (
<div className="notif" aria-live="polite">
{notices.length > 1 && (
<button className="notif-clear" onClick={clear}>
Закрыть всё
</button>
)}
{stack
.slice(1)
.reverse()
.map((n, i, arr) => (
<div key={n.id} className="notif-card notif-card--back" style={{ ['--depth' as string]: arr.length - i }} aria-hidden />
))}
<article className="notif-card" key={top.id}>
{top.emblem ? (
<img className="notif-emblem" src={top.emblem} alt="" />
) : (
<span className="notif-emblem notif-emblem--icon">
<Icon icon={NOTICE_ICON[top.icon]} variant="Bulk" size="60%" />
</span>
)}
<div className="notif-text">
<h3>{top.title}</h3>
<p>{top.text}</p>
</div>
<div className="notif-actions">
<button className="btn btn--fill-green" onClick={() => accept(top.id)}>
Принять
</button>
<button className="btn btn--outline-red" onClick={() => decline(top.id)}>
Отклонить
</button>
</div>
<button className="notif-close" onClick={() => decline(top.id)} aria-label="Закрыть уведомление">
<span aria-hidden>×</span>
</button>
{notices.length > 1 && <span className="notif-count">{notices.length}</span>}
</article>
</div>
)
}
const AI_MODES: { key: AutopilotMode; label: string; hint: string }[] = [
{ key: 'auto', label: 'Автопилот', hint: 'ИИ сразу назначает исполнителей' },
{ key: 'semi', label: 'Полуручной', hint: 'ИИ вмешивается, если оператор не успел' },
{ key: 'manual', label: 'Ручной', hint: 'ИИ только подсказывает' },
]
export function AiModeSwitch() {
const mode = useStore((s) => s.settings.autopilot)
const setSettings = useStore((s) => s.setSettings)
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)
const current = AI_MODES.find((m) => m.key === mode)!
useEffect(() => {
if (!open) return
const close = (e: MouseEvent) => !ref.current?.contains(e.target as Node) && setOpen(false)
const esc = (e: KeyboardEvent) => e.key === 'Escape' && setOpen(false)
document.addEventListener('mousedown', close)
document.addEventListener('keydown', esc)
return () => {
document.removeEventListener('mousedown', close)
document.removeEventListener('keydown', esc)
}
}, [open])
return (
<div className="ai-mode" ref={ref}>
<button
className={`ai-pill ai-pill--${mode}`}
onClick={() => setOpen((v) => !v)}
aria-haspopup="listbox"
aria-expanded={open}
title={current.hint}
>
<Icon icon={Cpu} variant="Bulk" size="0.9rem" />
<span>
ИИ-автопилот: <b>{current.label}</b>
</span>
</button>
{open && (
<ul className="ai-menu" role="listbox" aria-label="Режим ИИ-автопилота">
{AI_MODES.map((m) => (
<li key={m.key}>
<button
role="option"
aria-selected={m.key === mode}
onClick={() => {
setSettings({ autopilot: m.key })
setOpen(false)
}}
>
<b>{m.label}</b>
<span>{m.hint}</span>
</button>
</li>
))}
</ul>
)}
</div>
)
}
export function StatusBar() {
const now = useNow(1000)
const setDrawer = useStore((s) => s.setDrawer)
const setLoggedOut = useStore((s) => s.setLoggedOut)
return (
<div className="status">
<span className="status-item" title="Погода">
<Icon icon={CloudNotif} variant="Bulk" size="1.15rem" />
+22°C
</span>
<span className="status-item mono" title="Текущее время">
<Icon icon={Clock} variant="Bulk" size="1.15rem" />
{fmtTime(now)}
</span>
<button className="status-item" onClick={() => setDrawer('messages')}>
<Icon icon={MessageNotif} variant="Bulk" size="1.15rem" />
Сообщения
</button>
<button className="status-item" onClick={() => setLoggedOut(true)}>
<Icon icon={LogoutCurve} variant="Bulk" size="1.15rem" />
Выйти
</button>
</div>
)
}
export function Toasts() {
const toasts = useStore((s) => s.toasts)
const drop = useStore((s) => s.dropToast)
return (
<div className="toasts" aria-live="polite">
{toasts.map((t) => (
<button key={t.id} className={`toast toast--${t.tone}`} onClick={() => drop(t.id)}>
{t.tone === 'ai' && <Icon icon={Cpu} variant="Bulk" size="1rem" />}
{t.tone === 'warn' && <Icon icon={Danger} variant="Bulk" size="1rem" />}
<span>{t.text}</span>
</button>
))}
</div>
)
}
+39
View File
@@ -0,0 +1,39 @@
import type { CSSProperties } from 'react'
import type { Icon as IconsaxIcon, IconProps } from 'iconsax-react'
/**
* Обёртка над iconsax-react: в React 19 defaultProps у функциональных
* компонентов игнорируются, поэтому вариант, цвет и размер передаём явно.
*/
export function Icon({
icon: C,
size = '1.25em',
variant = 'Linear',
color = 'currentColor',
...rest
}: IconProps & { icon: IconsaxIcon }) {
return <C size={size} variant={variant} color={color} aria-hidden focusable="false" {...rest} />
}
/** SVG-ассет из Figma, перекрашиваемый через currentColor (mask-image) */
export function MaskIcon({
src,
width,
height,
className,
style,
}: {
src: string
width: string
height: string
className?: string
style?: CSSProperties
}) {
return (
<span
aria-hidden
className={`mask-icon${className ? ` ${className}` : ''}`}
style={{ width, height, ['--icon' as string]: `url("${src}")`, ...style }}
/>
)
}
+171
View File
@@ -0,0 +1,171 @@
.j-body {
padding: 0 0.6rem 0 1rem;
overflow: hidden;
}
.j-new {
padding: 0.05rem 0.4rem;
border-radius: 999px;
background: var(--c-green);
color: #222;
font-size: var(--fs-2xs);
font-weight: var(--w-bold);
}
.j-list {
flex: 1;
min-height: 0;
padding: 0.2rem 0.5rem 1.6rem 0;
-webkit-mask: linear-gradient(180deg, #000 82%, transparent);
mask: linear-gradient(180deg, #000 82%, transparent);
}
.jrow {
display: grid;
grid-template-columns: 1.85rem minmax(0, 1fr) auto;
gap: 0.7rem;
align-items: start;
padding: 0.55rem 0;
border-bottom: var(--stroke) solid var(--divider);
animation: fade-in 0.3s ease-out;
}
.jav {
position: relative;
width: 1.85rem;
height: 1.85rem;
margin-top: 0.15rem;
}
.jav > img:first-child,
.jav-ini {
width: 100%;
height: 100%;
border-radius: 50%;
object-fit: cover;
}
.jav-ini {
display: grid;
place-items: center;
background: var(--surface-3);
color: var(--text-2);
font-size: var(--fs-2xs);
font-weight: var(--w-bold);
}
.jav-badge {
position: absolute;
right: -0.65rem;
bottom: -0.65rem;
width: 1.55rem;
height: 1.55rem;
pointer-events: none;
}
.jmain {
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.jwho {
display: flex;
align-items: baseline;
gap: 0.3rem;
font-size: var(--fs-md);
font-weight: var(--w-medium);
white-space: nowrap;
overflow: hidden;
}
.jwho b {
font-weight: var(--w-medium);
}
.jsep,
.jrole {
opacity: 0.8;
}
.jdept {
color: var(--c-green);
opacity: 0.85;
overflow: hidden;
text-overflow: ellipsis;
}
.j-ai {
flex: none;
display: inline-flex;
align-items: center;
gap: 0.15rem;
padding: 0 0.3rem;
border-radius: 999px;
border: 1px solid var(--c-green);
color: var(--c-green);
font-size: var(--fs-2xs);
align-self: center;
}
.jtext {
font-size: var(--fs-xs);
color: var(--text-2);
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.jfoot {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 0.2rem 0.8rem;
font-size: var(--fs-2xs);
}
.javg {
display: inline-flex;
align-items: center;
gap: 0.25rem;
color: color-mix(in srgb, var(--text) 45%, transparent);
}
.javg img {
width: 0.5rem;
height: 0.55rem;
}
.jtime {
color: color-mix(in srgb, var(--text) 45%, transparent);
white-space: nowrap;
}
.jst--done {
color: var(--c-cyan);
}
.jst--done .thin {
color: var(--text);
}
.jst--work {
color: var(--c-cream);
}
.jst--fail {
color: var(--c-red);
}
:root[data-night='false'] .jst--work {
color: #8a7a00;
}
/* датчик-рейтинг */
.rbars {
--bar-dim: color-mix(in srgb, #d0d0d0 20%, transparent);
display: flex;
align-items: flex-end;
gap: 0.24rem;
height: 2.05rem;
margin-top: 0.1rem;
padding-bottom: 0.4rem;
}
.rbar {
position: relative;
width: 0.29rem;
height: calc(var(--h) * 1.35rem);
}
.rbar i {
position: absolute;
inset: 0;
border-radius: 0.3rem 0.3rem 0 0;
background: var(--c);
}
.rbar .rbar-ref {
top: 100%;
bottom: auto;
height: 28%;
border-radius: 0 0 0.3rem 0.3rem;
opacity: 0.12;
}
+112
View File
@@ -0,0 +1,112 @@
import { Cpu, DocumentText } from 'iconsax-react'
import { icons, img } from '../assets'
import { useStore } from '../store/useStore'
import { EMPLOYEES, rating } from '../data/people'
import { fmtDate, fmtTime } from '../hooks/useNow'
import type { Employee, JournalEntry } from '../types'
import { Panel } from './Panel'
import { Icon } from './Icon'
import './JournalPanel.css'
const BAR_COLORS = ['var(--c-orange)', 'var(--c-cream)', 'var(--c-green)', 'var(--c-cyan)']
/** «Датчик сигнала» из макета: пять столбиков с отражением */
export function RatingBars({ value }: { value: number }) {
const heights = [19.5, 25.2, 30.8, 37.3, 43]
return (
<span className="rbars" role="meter" aria-valuemin={0} aria-valuemax={4} aria-valuenow={value} aria-label={`Рейтинг ${value} из 4`}>
{heights.map((h, i) => {
const level = i // 0 — декоративный
const filled = level > 0 && level <= value
const color = level === 0 ? 'var(--bar-dim)' : filled ? (value === 1 ? 'var(--c-red)' : BAR_COLORS[level - 1]) : 'var(--border)'
return (
<span key={i} className="rbar" style={{ ['--h' as string]: h / 43, ['--c' as string]: color }}>
<i />
<i className="rbar-ref" />
</span>
)
})}
</span>
)
}
function Avatar({ e }: { e: Employee }) {
const initials = e.name
.split(/[\s.]+/)
.filter(Boolean)
.slice(0, 2)
.map((p) => p[0])
.join('')
return (
<span className="jav">
{e.avatar ? <img src={e.avatar} alt="" /> : <span className="jav-ini">{initials}</span>}
<img className="jav-badge" src={img.avatarBadge} alt="" />
</span>
)
}
function Status({ j }: { j: JournalEntry }) {
if (j.status === 'in_progress') return <span className="jst jst--work">В работе</span>
if (j.status === 'failed') return <span className="jst jst--fail">Провалил</span>
return (
<span className="jst jst--done mono">
{fmtTime(j.finishedAt!)} <span className="thin">{fmtDate(j.finishedAt!)}</span>
</span>
)
}
export function JournalPanel() {
const journal = useStore((s) => s.journal)
const unseen = useStore((s) => s.journalUnseen)
const markSeen = useStore((s) => s.markJournalSeen)
return (
<Panel
id="journal"
title="Журнал действий"
icon={<Icon icon={DocumentText} size="1em" />}
live={unseen > 0}
actions={unseen > 0 ? <span className="j-new">+{unseen}</span> : null}
bodyClassName="j-body"
>
<ol className="j-list scroll" onMouseEnter={markSeen} onFocus={markSeen}>
{journal.map((j) => {
const e = EMPLOYEES.find((x) => x.id === j.employeeId)
if (!e) return null
const avgTone = e.avgMinutes <= 50 ? 'var(--c-green)' : e.avgMinutes <= 70 ? 'var(--c-cyan)' : 'var(--c-orange)'
return (
<li key={j.id} className="jrow">
<Avatar e={e} />
<div className="jmain">
<p className="jwho">
<b>{e.name}</b>
<span className="jsep">|</span>
<span className="jrole">{e.role}</span>
<span className="jdept">{e.department}</span>
{j.by === 'ai' && (
<span className="j-ai" title="Назначение выполнил ИИ-автопилот">
<Icon icon={Cpu} variant="Bulk" size="0.7rem" /> ИИ
</span>
)}
</p>
<p className="jtext">{j.text}</p>
<p className="jfoot">
<span className="javg">
<img src={icons.iconClockSmall} alt="" />
Среднее время: <span style={{ color: avgTone }}>{e.avgMinutes} мин</span>
</span>
<span className="jtime mono">
{fmtTime(j.startedAt)} <span className="thin">{fmtDate(j.startedAt)}</span>
<span className="thin"> – </span>
<Status j={j} />
</span>
</p>
</div>
<RatingBars value={rating(e)} />
</li>
)
})}
</ol>
</Panel>
)
}
+80
View File
@@ -0,0 +1,80 @@
/* Логотип MAPPEX DASHBOARDS — векторы из Figma (точечная сфера + надпись) */
export function Logo({ className }: { className?: string }) {
return (
<svg className={className} viewBox="0 0 313 145" role="img" aria-label="MAPPEX Dashboards">
<g className="logo-dots" fill="var(--c-green)">
<g transform="translate(41.3 1.3)"><path d="M9.5 2.7C1.8 6.2 1.4 6.4 0.9 6.2C1.5 4.6 12.2 0.5 16.1 0.0C15.9 0.1 15.9 0.1 15.1 0.4C13.6 1.0 12.0 1.6 9.5 2.7Z"/></g>
<g transform="translate(49.3 0.0)"><path d="M9.1 3.7C3.2 7.3 0.0 7.5 0.3 6.4C0.9 4.5 9.1 1.3 12.5 1.0C12.6 1.0 12.7 1.0 12.8 1.0C12.8 1.1 12.8 1.1 12.8 1.1C12.5 1.6 9.3 3.6 9.1 3.7Z"/></g>
<g transform="translate(60.0 0.0)"><path d="M8.5 3.6C6.0 7.0 0.6 7.5 0.3 5.7C0.0 3.6 5.4 1.0 8.3 0.9C10.6 1.0 8.6 3.5 8.5 3.6Z"/></g>
<g transform="translate(70.7 0.0)"><path d="M8.5 3.8C9.0 6.5 4.8 7.7 2.4 6.2C-0.0 4.5 1.7 1.5 4.1 1.0C4.4 0.9 4.7 0.9 4.9 0.9C6.8 1.0 8.2 2.5 8.5 3.8Z"/></g>
<g transform="translate(81.3 0.0)"><path d="M7.9 4.2C9.8 5.9 9.2 7.2 7.5 7.3C3.4 7.5 -0.7 2.6 0.5 1.4C0.7 1.1 1.1 1.1 1.3 1.1C3.1 1.3 6.2 2.6 7.9 4.2Z"/></g>
<g transform="translate(88.0 1.3)"><path d="M9.7 3.4C12.5 5.0 13.3 6.3 12.4 6.5C11.7 6.7 10.0 6.4 7.3 4.9C5.0 3.7 0.6 0.6 0.6 0.2C0.7 0.2 0.7 0.2 0.9 0.2C2.5 0.4 6.7 1.7 9.7 3.4Z"/></g>
<g transform="translate(93.3 1.3)"><path d="M10.0 4.1C12.6 5.3 15.3 6.9 15.2 7.4C15.0 7.4 14.7 7.5 12.4 6.5C12.3 6.5 0.3 0.7 0.1 0.6L0.2 0.6C1.1 0.8 5.5 2.0 10.0 4.1Z"/></g>
<g transform="translate(22.7 9.3)"><path d="M7.9 6.3C3.2 10.4 0.5 12.3 0.0 12.0C-0.1 10.2 10.4 1.9 13.4 1.0L13.5 1.0C13.5 1.2 13.5 1.4 7.9 6.3Z"/></g>
<g transform="translate(29.3 9.3)"><path d="M11.0 5.6C6.4 10.4 1.1 12.4 1.1 10.2C1.0 7.2 9.4 0.8 13.3 0.3C16.1 0.3 11.0 5.5 11.0 5.6Z"/></g>
<g transform="translate(42.7 8.0)"><path d="M12.7 6.5C9.4 11.7 1.9 13.4 0.9 10.2C0.0 7.0 6.3 1.5 11.3 1.2C15.1 1.3 13.6 5.1 12.7 6.5Z"/></g>
<g transform="translate(60.0 8.0)"><path d="M12.6 6.6C11.5 12.1 3.3 13.3 1.0 9.5C-0.8 6.2 3.3 1.3 8.1 1.1C11.9 1.3 13.0 4.4 12.6 6.6Z"/></g>
<g transform="translate(77.3 9.3)"><path d="M12.5 5.7C13.6 10.3 7.9 12.1 3.9 9.6C-0.5 6.9 0.1 1.2 4.0 0.2C4.5 0.1 5.0 0.0 5.4 0.0C9.4 0.3 12.0 3.6 12.5 5.7Z"/></g>
<g transform="translate(93.3 9.3)"><path d="M12.0 6.5C14.2 9.9 12.5 12.3 8.6 11.3C2.8 9.9 -1.2 2.5 1.7 0.9C2.2 0.6 2.6 0.6 3.1 0.6C6.5 1.0 10.4 4.0 12.0 6.5Z"/></g>
<g transform="translate(106.7 10.7)"><path d="M10.7 6.3C13.4 9.3 13.8 11.5 11.5 11.3C6.8 10.9 -1.4 1.5 0.3 0.3C0.5 0.1 0.8 0.1 1.1 0.1C3.8 0.6 8.2 3.7 10.7 6.3Z"/></g>
<g transform="translate(113.3 10.7)"><path d="M10.0 7.5C12.2 9.5 14.5 11.9 14.3 12.6C13.0 13.4 1.2 1.3 1.2 1.2C1.3 1.2 1.3 1.1 1.4 1.1C2.5 1.5 6.4 4.1 10.0 7.5Z"/></g>
<g transform="translate(8.0 24.0)"><path d="M6.2 7.7C1.7 14.4 1.1 14.9 0.9 15.1L0.9 15.0C0.9 14.8 1.0 14.6 1.4 13.9L1.4 13.9C5.2 7.3 5.2 7.3 7.6 4.3L10.0 1.2C10.5 0.7 10.6 0.6 10.8 0.4L10.8 0.5C10.7 0.7 10.5 1.2 6.2 7.7Z"/></g>
<g transform="translate(13.3 22.7)"><path d="M9.7 7.9C6.4 13.3 1.7 16.7 1.0 14.3C0.1 11.1 7.2 1.4 11.1 0.6C13.4 0.6 11.4 5.1 9.7 7.9Z"/></g>
<g transform="translate(25.3 21.3)"><path d="M13.8 8.5C10.8 14.6 2.8 17.8 1.4 13.4C0.2 9.5 5.8 1.7 11.5 1.2C15.5 1.3 15.3 5.5 13.8 8.5Z"/></g>
<g transform="translate(45.3 21.3)"><path d="M15.1 8.3C13.3 14.8 3.6 17.5 0.7 12.3C-1.5 8.2 2.9 1.2 9.7 0.8C15.1 1.0 15.8 5.5 15.1 8.3Z"/></g>
<g transform="translate(66.7 21.3)"><path d="M16.1 8.7C15.9 14.9 7.3 17.6 2.7 12.9C-1.3 8.7 1.4 1.2 8.6 1.0C14.0 1.3 16.3 5.7 16.1 8.7Z"/></g>
<g transform="translate(89.3 22.7)"><path d="M14.7 8.2C15.8 13.7 9.9 16.6 4.5 13.1C-1.5 9.1 -0.6 1.2 4.5 0.3C4.9 0.2 5.4 0.2 5.8 0.2C11.0 0.7 14.2 5.2 14.7 8.2Z"/></g>
<g transform="translate(109.3 22.7)"><path d="M12.6 9.4C14.5 14.1 11.9 17.0 7.5 15.3C0.8 12.6 -2.1 2.9 1.9 1.4C2.4 1.2 2.9 1.2 3.3 1.2C7.7 1.8 11.5 6.4 12.6 9.4Z"/></g>
<g transform="translate(124.0 24.0)"><path d="M9.9 9.6C12.1 13.7 12.1 16.6 9.7 15.9C5.2 14.5 -1.8 2.3 1.1 1.3C1.3 1.2 1.5 1.2 1.7 1.2C4.5 1.9 8.2 6.5 9.9 9.6Z"/></g>
<g transform="translate(130.7 25.3)"><path d="M10.0 15.5C10.2 15.9 10.3 16.1 10.3 16.2L10.2 16.2C9.2 15.3 1.2 2.4 0.8 1.3L0.8 1.2C1.0 1.4 1.1 1.5 1.5 1.9L3.9 5.2C8.1 11.6 8.1 11.6 9.8 15.0L9.9 15.2C9.9 15.3 10.0 15.4 10.0 15.5Z"/></g>
<g transform="translate(2.7 40.0)"><path d="M7.0 9.2C5.0 15.1 2.2 19.1 1.4 17.1C0.2 14.2 4.4 1.6 7.5 0.5C9.3 0.4 8.1 5.8 7.0 9.2Z"/></g>
<g transform="translate(12.0 38.7)"><path d="M11.9 9.4C9.8 16.4 3.7 20.2 1.5 15.9C-0.5 11.4 3.5 1.4 9.0 0.6C12.8 0.7 13.0 5.8 11.9 9.4Z"/></g>
<g transform="translate(29.3 37.3)"><path d="M16.4 10.2C14.6 17.9 4.9 21.1 1.5 15.1C-1.2 10.1 2.9 1.8 10.3 1.3C16.3 1.5 17.2 6.9 16.4 10.2Z"/></g>
<g transform="translate(53.3 37.3)"><path d="M17.5 10.3C16.5 18.1 6.3 21.0 1.7 14.8C-1.9 9.8 1.6 1.5 9.6 1.1C15.9 1.5 18.0 6.7 17.5 10.3Z"/></g>
<g transform="translate(102.7 38.7)"><path d="M15.8 10.8C16.4 17.8 9.6 20.8 4.2 16.0C-1.4 10.8 -0.2 1.6 6.2 1.2C6.4 1.2 6.7 1.2 6.9 1.2C12.5 1.9 15.5 7.2 15.8 10.8Z"/></g>
<g transform="translate(0.0 61.3)"><path d="M2.4 10.4C2.4 13.7 2.0 19.3 1.3 19.3C1.1 19.1 0.8 18.4 0.6 15.0L0.5 10.4L0.9 4.8C1.2 1.1 1.5 0.7 1.7 0.5L1.8 0.5C2.5 1.2 2.5 7.0 2.4 10.4Z"/></g>
<g transform="translate(4.0 60.0)"><path d="M8.9 10.4C8.5 17.0 5.3 21.2 2.8 18.3C-0.5 14.5 0.3 1.5 5.0 0.4C8.1 0.5 9.1 6.3 8.9 10.4Z"/></g>
<g transform="translate(17.3 58.7)"><path d="M14.6 10.8C13.9 18.6 6.6 22.3 2.6 17.0C-1.3 11.7 1.0 1.4 7.7 0.7C13.1 0.9 15.0 6.7 14.6 10.8Z"/></g>
<g transform="translate(38.7 58.7)"><path d="M18.4 10.6C17.5 18.8 7.8 22.0 2.8 15.7C-1.4 10.1 1.6 0.7 9.9 0.3C16.9 0.6 18.8 6.8 18.4 10.6Z"/></g>
<g transform="translate(65.3 58.7)"><path d="M18.2 11.0C17.3 19.3 7.2 22.2 2.1 15.7C-2.3 10.1 0.8 0.7 9.4 0.4C16.6 1.0 18.7 7.2 18.2 11.0Z"/></g>
<g transform="translate(2.7 84.0)"><path d="M7.2 10.3C8.4 15.1 8.4 19.5 6.3 18.1C3.2 16.1 -1.0 2.3 2.0 1.0C3.9 1.0 6.2 6.4 7.2 10.3Z"/></g>
<g transform="translate(12.0 82.7)"><path d="M11.9 10.6C12.8 16.6 9.7 20.3 5.9 17.7C0.3 14.0 -1.1 2.4 3.7 1.2C3.9 1.1 4.1 1.1 4.2 1.1C8.5 1.2 11.3 6.7 11.9 10.6Z"/></g>
<g transform="translate(29.3 82.7)"><path d="M16.1 10.0C16.3 17.2 9.2 20.3 3.8 15.5C-1.1 10.9 -1.2 0.9 6.9 0.3C13.1 0.5 16.0 6.1 16.1 10.0Z"/></g>
<g transform="translate(52.0 82.7)"><path d="M18.2 10.1C17.4 18.1 7.8 20.5 2.9 14C-1.1 8.6 1.4 0.5 9.3 0.2C16.0 0.6 18.6 6.2 18.2 10.1Z"/></g>
<g transform="translate(8.0 105.3)"><path d="M7.3 8.9C9.9 13.0 11.1 15.3 10.9 15.6C9.4 15.7 0.2 2.1 1.0 0.9C2.0 0.8 6.4 7.5 7.3 8.9Z"/></g>
<g transform="translate(13.3 104.0)"><path d="M10.4 9.1C12.3 12.9 12.8 16.4 10.4 15.8C5.7 14.6 -1.0 3.2 1.6 1.1C1.7 1.0 2.0 0.9 2.2 0.9C4.8 0.9 8.4 5.1 10.4 9.1Z"/></g>
<g transform="translate(25.3 104.0)"><path d="M13.9 8.4C15.4 13.4 12.7 17.0 7.6 14.0C1.0 10.2 -1.3 1.0 3.9 0.0C4.0 0.0 4.3 0.0 4.5 0.0C9.3 0.1 12.9 5.0 13.9 8.4Z"/></g>
<g transform="translate(21.3 121.3)"><path d="M10.0 7.6C13.4 10.9 14.8 12.6 14.3 12.8C11.9 13.4 -0.3 2.5 1.1 1.2C1.1 1.2 1.2 1.2 1.2 1.1C3.0 1.1 7.9 5.7 10.0 7.6Z"/></g>
<g transform="translate(29.3 121.3)"><path d="M11.2 6.9C12.7 9.0 14.6 12.3 12.2 12.1C7.9 11.7 -1.4 3.1 0.8 0.6C1.1 0.3 1.5 0.3 1.8 0.2C4.8 0.3 8.8 3.7 11.2 6.9Z"/></g>
<g transform="translate(42.7 120.0)"><path d="M12.0 7.9C13.5 11.8 11.7 14.5 6.9 12.2C0.8 9.2 -2.2 2.4 2.0 1.1C2.3 1.1 2.7 1.0 3.1 1.0C7.8 1.2 11.0 5.2 12.0 7.9Z"/></g>
<g transform="translate(58.7 120.0)"><path d="M12.3 8.0C12.0 13.0 6.6 15.0 2.4 10.1C-0.7 6.3 0.1 1.1 5.4 0.9C9.9 1.2 12.4 4.7 12.3 8.0Z"/></g>
<g transform="translate(40.0 134.7)"><path d="M10.4 5.5C15.4 8.4 15.4 8.4 15.6 8.5C15.6 8.6 15.5 8.6 15.5 8.6C11.8 8.6 -0.9 2.0 0.6 1.0C0.7 1.0 0.7 1.0 0.8 1.0C2.4 1.0 6.1 3.1 10.4 5.5Z"/></g>
<g transform="translate(46.7 134.7)"><path d="M10.8 5.2C14.3 8.3 13.5 8.3 13.2 8.3C10.2 8.5 -0.3 2.5 1.3 0.7C1.5 0.5 1.8 0.5 2.1 0.5C5.3 0.6 9.6 4.1 10.8 5.2Z"/></g>
<g transform="translate(57.3 134.7)"><path d="M9.5 5.1C9.9 6.1 11.0 9.4 6.9 7.7C2.3 5.7 -0.4 1.6 1.9 0.5C2.3 0.3 2.8 0.3 3.1 0.2C6.2 0.4 8.6 2.9 9.5 5.1Z"/></g>
<g transform="translate(69.3 134.7)"><path d="M7.4 5.3C6.0 8.8 2.5 9.6 0.7 5.5C-0.2 3.1 0.8 0.5 4.1 0.3C7.2 0.6 8.2 3.0 7.4 5.3Z"/></g>
<g transform="translate(78.7 134.7)"><path d="M7.4 5.6C6.3 6.6 0.3 10.6 0.6 7.0C0.9 4.5 3.7 0.8 7.5 0.7C10.4 1.0 9.7 3.5 7.4 5.6Z"/></g>
<g transform="translate(85.3 136.0)"><path d="M8.6 4.8C5.5 6.5 0.5 8.1 0.7 7.2C0.8 6.4 7.9 0.0 12.1 0.0C14.1 0.3 12.5 2.2 11.0 3.3C10.3 3.8 9.5 4.3 8.6 4.8Z"/></g>
</g>
<g className="logo-word" fill="var(--text)">
<g transform="translate(99.5 68.7)"><path d="M0 0V30.3H6.2V10.1L12.6 26.0H15.9L22.3 10.1V30.3H28.5V0H22.3L14.3 18.7L6.2 0H0Z"/></g>
<g transform="translate(139.1 68.7)"><path d="M9.1 0L0 30.3H6.5L8.5 23.9H20.1L22.1 30.3H28.5L19.4 0H9.1ZM10.2 18.3L14.3 5.1L18.4 18.3H10.2Z"/></g>
<g transform="translate(178.7 68.7)"><path d="M0 0V30.3H6.2V21.6H19.4C21.9 21.6 23.8 19.7 23.8 17.3V4.3C23.8 1.9 21.9 0 19.4 0H0ZM6.2 16.0V5.6H16.3C17.0 5.6 17.5 6.0 17.5 6.7V14.9C17.5 15.5 17.0 16.0 16.3 16.0H6.2Z"/></g>
<g transform="translate(215.4 68.7)"><path d="M0 0V30.3H6.2V21.6H19.4C21.9 21.6 23.8 19.7 23.8 17.3V4.3C23.8 1.9 21.9 0 19.4 0H0ZM6.2 16.0V5.6H16.3C17.0 5.6 17.5 6.0 17.5 6.7V14.9C17.5 15.5 17.0 16.0 16.3 16.0H6.2Z"/></g>
<g transform="translate(252.2 68.7)"><path d="M0 0V30.3H21.8V24.7H6.2V17.9H17.5V12.3H6.2V5.6H21.8V0H0Z"/></g>
<g transform="translate(283.6 68.7)"><path d="M0 0L10.5 15.1L0 30.3H7.5L14.3 19.5L21.0 30.3H28.5L18.0 15.1L28.5 0H21.0L14.3 10.7L7.5 0H0Z"/></g>
</g>
<g className="logo-sub" fill="#737373">
<g transform="translate(106.6 111.4)"><path d="M12.4 7.6C12.4 10.2 11.7 12.2 10.3 13.5C8.9 14.9 6.9 15.6 4.3 15.6H0V0H4.7C7.2 0 9.1 0.6 10.4 2.0C11.8 3.3 12.4 5.2 12.4 7.6ZM10.5 7.7C10.5 5.6 10.0 4.1 9.0 3.1C7.9 2.0 6.4 1.5 4.4 1.5H1.8V14.0H4.0C6.2 14.0 7.8 13.5 8.9 12.4C10.0 11.3 10.5 9.8 10.5 7.7Z"/></g>
<g transform="translate(126.7 111.3)"><path d="M11.9 15.6L10.0 10.7H3.7L1.8 15.6H0L6.1 0H7.7L13.8 15.6H11.9ZM9.4 9.0L7.6 4.2C7.4 3.6 7.1 2.8 6.9 1.9C6.7 2.6 6.5 3.4 6.2 4.2L4.3 9.0H9.4Z"/></g>
<g transform="translate(147.9 111.2)"><path d="M9.8 11.6C9.8 13.0 9.3 14.1 8.3 14.9C7.3 15.6 6 16.0 4.2 16.0C2.4 16.0 1 15.8 0 15.3V13.6C0.6 13.8 1.3 14.0 2.1 14.2C2.8 14.4 3.6 14.4 4.3 14.4C5.5 14.4 6.4 14.2 7.0 13.7C7.6 13.3 8 12.6 8 11.8C8 11.3 7.8 10.8 7.6 10.5C7.4 10.1 7.0 9.8 6.5 9.5C6.0 9.2 5.3 8.9 4.2 8.5C2.8 8.0 1.7 7.4 1.1 6.7C0.5 6.0 0.2 5.0 0.2 3.9C0.2 2.7 0.6 1.7 1.5 1.0C2.4 0.3 3.6 0 5.1 0C6.7 0 8.1 0.2 9.4 0.8L8.8 2.4C7.5 1.8 6.3 1.6 5.1 1.6C4.1 1.6 3.3 1.8 2.8 2.2C2.3 2.6 2.0 3.2 2.0 3.9C2.0 4.5 2.1 4.9 2.3 5.2C2.5 5.6 2.8 5.9 3.3 6.2C3.8 6.5 4.5 6.8 5.5 7.2C7.1 7.7 8.3 8.4 8.9 9.0C9.5 9.7 9.8 10.6 9.8 11.6Z"/></g>
<g transform="translate(167.2 111.4)"><path d="M11.8 15.6H10.0V8.2H1.8V15.6H0V0H1.8V6.6H10.0V0H11.8V15.6Z"/></g>
<g transform="translate(189.6 111.4)"><path d="M0 0H4.4C6.4 0 7.9 0.3 8.9 0.9C9.8 1.5 10.3 2.5 10.3 3.8C10.3 4.7 10.0 5.5 9.5 6.1C9.0 6.7 8.2 7.1 7.2 7.3V7.4C9.6 7.8 10.8 9.0 10.8 11.1C10.8 12.5 10.3 13.6 9.4 14.4C8.4 15.2 7.1 15.6 5.4 15.6H0V0ZM1.8 6.6H4.8C6.0 6.6 7.0 6.4 7.5 6.0C8.1 5.6 8.4 5 8.4 4.0C8.4 3.1 8.1 2.5 7.4 2.1C6.8 1.7 5.8 1.5 4.5 1.5H1.8V6.6ZM1.8 8.2V14.0H5.0C6.3 14.0 7.2 13.8 7.9 13.3C8.5 12.8 8.8 12.0 8.8 11.0C8.8 10.0 8.5 9.3 7.9 8.9C7.2 8.4 6.2 8.2 4.9 8.2H1.8Z"/></g>
<g transform="translate(209.2 111.1)"><path d="M14.3 8.0C14.3 10.5 13.7 12.5 12.4 13.9C11.2 15.3 9.4 16.0 7.2 16.0C4.9 16.0 3.1 15.3 1.8 13.9C0.6 12.5 0 10.5 0 8.0C0 5.4 0.6 3.5 1.8 2.1C3.1 0.7 4.9 0 7.2 0C9.4 0 11.2 0.7 12.4 2.1C13.7 3.5 14.3 5.5 14.3 8.0ZM1.9 8.0C1.9 10.1 2.3 11.7 3.2 12.8C4.1 13.9 5.4 14.5 7.2 14.5C8.9 14.5 10.2 13.9 11.1 12.8C12.0 11.7 12.4 10.1 12.4 8.0C12.4 5.9 12.0 4.3 11.1 3.2C10.2 2.1 8.9 1.6 7.2 1.6C5.4 1.6 4.1 2.1 3.2 3.2C2.3 4.3 1.9 5.9 1.9 8.0Z"/></g>
<g transform="translate(231.2 111.3)"><path d="M11.9 15.6L10.0 10.7H3.7L1.8 15.6H0L6.1 0H7.7L13.8 15.6H11.9ZM9.4 9.0L7.6 4.2C7.4 3.6 7.1 2.8 6.9 1.9C6.7 2.6 6.5 3.4 6.2 4.2L4.3 9.0H9.4Z"/></g>
<g transform="translate(253.4 111.4)"><path d="M1.8 9.1V15.6H0V0H4.2C6.2 0 7.6 0.3 8.5 1.1C9.4 1.8 9.9 2.9 9.9 4.4C9.9 6.4 8.8 7.8 6.7 8.6L11.0 15.6H8.8L5.0 9.1H1.8ZM1.8 7.5H4.3C5.5 7.5 6.5 7.3 7.1 6.8C7.7 6.3 8.0 5.5 8.0 4.5C8.0 3.4 7.7 2.7 7.1 2.2C6.5 1.8 5.5 1.5 4.1 1.5H1.8V7.5Z"/></g>
<g transform="translate(273.2 111.4)"><path d="M12.4 7.6C12.4 10.2 11.7 12.2 10.3 13.5C8.9 14.9 6.9 15.6 4.3 15.6H0V0H4.7C7.2 0 9.1 0.6 10.4 2.0C11.8 3.3 12.4 5.2 12.4 7.6ZM10.5 7.7C10.5 5.6 10.0 4.1 9.0 3.1C7.9 2.0 6.4 1.5 4.4 1.5H1.8V14.0H4.0C6.2 14.0 7.8 13.5 8.9 12.4C10.0 11.3 10.5 9.8 10.5 7.7Z"/></g>
<g transform="translate(294.4 111.2)"><path d="M9.8 11.6C9.8 13.0 9.3 14.1 8.3 14.9C7.3 15.6 6 16.0 4.2 16.0C2.4 16.0 1 15.8 0 15.3V13.6C0.6 13.8 1.3 14.0 2.1 14.2C2.8 14.4 3.6 14.4 4.3 14.4C5.5 14.4 6.4 14.2 7.0 13.7C7.6 13.3 8 12.6 8 11.8C8 11.3 7.8 10.8 7.6 10.5C7.4 10.1 7.0 9.8 6.5 9.5C6.0 9.2 5.3 8.9 4.2 8.5C2.8 8.0 1.7 7.4 1.1 6.7C0.5 6.0 0.2 5.0 0.2 3.9C0.2 2.7 0.6 1.7 1.5 1.0C2.4 0.3 3.6 0 5.1 0C6.7 0 8.1 0.2 9.4 0.8L8.8 2.4C7.5 1.8 6.3 1.6 5.1 1.6C4.1 1.6 3.3 1.8 2.8 2.2C2.3 2.6 2.0 3.2 2.0 3.9C2.0 4.5 2.1 4.9 2.3 5.2C2.5 5.6 2.8 5.9 3.3 6.2C3.8 6.5 4.5 6.8 5.5 7.2C7.1 7.7 8.3 8.4 8.9 9.0C9.5 9.7 9.8 10.6 9.8 11.6Z"/></g>
</g>
</svg>
)
}
+120
View File
@@ -0,0 +1,120 @@
.drawer {
position: fixed;
top: 1rem;
right: 1rem;
bottom: 1rem;
z-index: 70;
width: min(25rem, calc(100vw - 2rem));
display: flex;
flex-direction: column;
border-radius: 0.75rem;
border: var(--stroke) solid var(--border);
background: var(--panel-to);
box-shadow: -20px 0 60px rgba(0, 0, 0, 0.5);
animation: drawer-in 0.22s ease-out;
}
@keyframes drawer-in {
from {
transform: translateX(30px);
opacity: 0;
}
}
.drawer-head {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.9rem 1rem 0.6rem;
}
.drawer-head h2 {
font-size: var(--fs-lg);
font-weight: var(--w-bold);
}
.drawer-head button {
color: var(--text-3);
}
.drawer-head button:hover {
color: var(--text);
}
.drawer-body {
flex: 1;
padding: 0 1rem 1rem;
}
.dl {
display: flex;
flex-direction: column;
}
.dl > li {
padding: 0.6rem 0;
border-bottom: var(--stroke) solid var(--divider);
font-size: var(--fs-sm);
}
.dl-row {
display: grid;
grid-template-columns: 5.5rem minmax(0, 1fr) auto;
gap: 0.6rem;
align-items: center;
}
.dl-msg p + p {
margin-top: 0.2rem;
color: var(--text-2);
}
.dl-ago {
float: right;
font-size: var(--fs-2xs);
}
.dl-task {
display: flex;
justify-content: space-between;
gap: 0.6rem;
align-items: center;
}
.dl-task .muted {
font-size: var(--fs-2xs);
margin-top: 0.15rem;
}
.pill {
display: inline-block;
padding: 0.15rem 0.5rem;
border-radius: 999px;
border: 1px solid currentColor;
font-size: var(--fs-2xs);
font-weight: var(--w-semibold);
white-space: nowrap;
background: transparent;
}
select.pill {
appearance: none;
cursor: pointer;
padding-right: 0.6rem;
}
select.pill option {
background: var(--surface);
color: var(--text);
}
.pill--red,
.pill--overdue {
color: var(--c-red);
}
.pill--green,
.pill--done {
color: var(--c-green);
}
.pill--orange,
.pill--in_progress {
color: var(--c-orange);
}
.pill--blue,
.pill--todo {
color: var(--c-blue);
}
.pill--muted {
color: var(--text-3);
}
.drawer-more {
margin-top: 0.8rem;
font-size: var(--fs-sm);
color: var(--c-lavender);
}
.drawer-more:hover {
text-decoration: underline;
}

Some files were not shown because too many files have changed in this diff Show More