Polish UI, add icon asset

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
sultan 2026-05-22 15:50:20 +05:00
parent 57af72f514
commit 17059591f6
4 changed files with 194 additions and 125 deletions

12
app.js
View File

@ -342,7 +342,7 @@ function renderWorkload(tasks) {
data: { data: {
labels: employees, labels: employees,
datasets: [ datasets: [
{ label: 'Новые', data: employees.map((e) => perAssignee[e].new), backgroundColor: '#1972C7' }, { label: 'Новые', data: employees.map((e) => perAssignee[e].new), backgroundColor: '#1F76BD' },
{ label: 'В работе', data: employees.map((e) => perAssignee[e].in_progress), backgroundColor: '#FF9500' }, { label: 'В работе', data: employees.map((e) => perAssignee[e].in_progress), backgroundColor: '#FF9500' },
{ label: 'Просрочено', data: employees.map((e) => perAssignee[e].overdue), backgroundColor: '#FF3B30' }, { label: 'Просрочено', data: employees.map((e) => perAssignee[e].overdue), backgroundColor: '#FF3B30' },
{ label: 'Выполнено', data: employees.map((e) => perAssignee[e].done), backgroundColor: '#34C759' }, { label: 'Выполнено', data: employees.map((e) => perAssignee[e].done), backgroundColor: '#34C759' },
@ -373,7 +373,7 @@ function renderWorkload(tasks) {
labels: Object.keys(dl), labels: Object.keys(dl),
datasets: [{ datasets: [{
data: Object.values(dl), data: Object.values(dl),
backgroundColor: ['#FF3B30', '#FF9500', '#FFCC00', '#4FB1F7', '#1972C7', '#0E4A82', '#D2D2D7'], backgroundColor: ['#FF3B30', '#FF9500', '#FFCC00', '#5BAEED', '#1F76BD', '#0F4D80', '#D2D2D7'],
borderWidth: 2, borderColor: '#fff', borderWidth: 2, borderColor: '#fff',
}], }],
}, },
@ -387,7 +387,7 @@ function renderWorkload(tasks) {
type: 'bar', type: 'bar',
data: { data: {
labels: dirEntries.map(([k]) => k), labels: dirEntries.map(([k]) => k),
datasets: [{ label: 'Активных задач', data: dirEntries.map(([, n]) => n), backgroundColor: '#1972C7', borderRadius: 6 }], datasets: [{ label: 'Активных задач', data: dirEntries.map(([, n]) => n), backgroundColor: '#1F76BD', borderRadius: 6 }],
}, },
options: { ...chartOpts(), indexAxis: 'y' }, options: { ...chartOpts(), indexAxis: 'y' },
}); });
@ -401,11 +401,11 @@ function renderWorkload(tasks) {
datasets: [{ datasets: [{
label: 'Дедлайнов в день', label: 'Дедлайнов в день',
data: tl.values, data: tl.values,
borderColor: '#1972C7', borderColor: '#1F76BD',
backgroundColor: 'rgba(25, 114, 199, 0.15)', backgroundColor: 'rgba(31, 118, 189, 0.15)',
fill: true, fill: true,
tension: 0.3, tension: 0.3,
pointBackgroundColor: '#1972C7', pointBackgroundColor: '#1F76BD',
pointRadius: 4, pointRadius: 4,
}], }],
}, },

BIN
icon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -11,10 +11,11 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.css">
<link rel="stylesheet" href="styles.css?v=22" /> <link rel="stylesheet" href="styles.css?v=27" />
</head> </head>
<body> <body>
<header class="topbar"> <header class="topbar">
<div class="topbar-left">
<div class="menu-host"> <div class="menu-host">
<button id="menuBtn" class="menu-btn" aria-label="Открыть меню" aria-haspopup="true" aria-expanded="false"> <button id="menuBtn" class="menu-btn" aria-label="Открыть меню" aria-haspopup="true" aria-expanded="false">
<span></span><span></span><span></span> <span></span><span></span><span></span>
@ -44,53 +45,14 @@
</div> </div>
</div> </div>
<a href="#/home" class="brand" id="brandHome" title="На главную"> <a href="#/home" class="brand" id="brandHome" title="На главную">
<svg class="logo" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> <img src="icon.jpg" alt="" class="logo" />
<defs> <span class="brand-mark">
<linearGradient id="kt-bg" x1="0" y1="0" x2="0" y2="1"> <span class="brand-mark-primary">GR</span>
<stop offset="0" stop-color="#4FB1F7"/> <span class="brand-mark-divider" aria-hidden="true"></span>
<stop offset="0.55" stop-color="#2D95E2"/> <span class="brand-mark-secondary">Department</span>
<stop offset="1" stop-color="#1972C7"/> </span>
</linearGradient>
<radialGradient id="kt-glow" cx="50%" cy="40%" r="60%">
<stop offset="0" stop-color="rgba(255,255,255,0.22)"/>
<stop offset="1" stop-color="rgba(255,255,255,0)"/>
</radialGradient>
<clipPath id="kt-left"><circle cx="38" cy="50" r="27"/></clipPath>
<clipPath id="kt-right"><circle cx="62" cy="50" r="27"/></clipPath>
</defs>
<rect width="100" height="100" rx="22" fill="url(#kt-bg)"/>
<rect width="100" height="100" rx="22" fill="url(#kt-glow)"/>
<!-- Левая сфера: горизонтальные полосы -->
<g clip-path="url(#kt-left)" fill="#fff">
<rect x="8" y="29" width="60" height="3.5" rx="1.75"/>
<rect x="8" y="38" width="60" height="3.5" rx="1.75"/>
<rect x="8" y="47" width="60" height="3.5" rx="1.75"/>
<rect x="8" y="56" width="60" height="3.5" rx="1.75"/>
<rect x="8" y="65" width="60" height="3.5" rx="1.75"/>
</g>
<!-- Правая сфера: меридианы + экватор -->
<g clip-path="url(#kt-right)" stroke="#fff" stroke-width="3.2" fill="none" stroke-linecap="round">
<path d="M62 23 C44 35 44 65 62 77"/>
<path d="M62 23 C54 35 54 65 62 77"/>
<path d="M62 23 C70 35 70 65 62 77"/>
<path d="M62 23 C78 35 78 65 62 77"/>
<path d="M35 56 Q62 62 90 56"/>
</g>
<!-- Лёгкая тень под сферами -->
<ellipse cx="50" cy="85" rx="34" ry="3" fill="rgba(0,0,0,0.10)"/>
<!-- Обводки сфер для контура -->
<circle cx="38" cy="50" r="27" fill="none" stroke="rgba(255,255,255,0.18)" stroke-width="0.8"/>
<circle cx="62" cy="50" r="27" fill="none" stroke="rgba(255,255,255,0.18)" stroke-width="0.8"/>
</svg>
<div class="brand-text">
<div class="brand-name">ДВГО</div>
<div class="brand-sub">Помощник руководителя · поручения</div>
</div>
</a> </a>
</div>
<div class="who"> <div class="who">
<label for="currentUser">Я работаю как</label> <label for="currentUser">Я работаю как</label>
<select id="currentUser"></select> <select id="currentUser"></select>
@ -241,6 +203,6 @@
<script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/flatpickr.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/l10n/ru.js"></script> <script src="https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/l10n/ru.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script src="app.js?v=23"></script> <script src="app.js?v=24"></script>
</body> </body>
</html> </html>

View File

@ -1,13 +1,13 @@
/* Қазақтелеком — Помощник руководителя. Apple-style. Палитра — синий. */ /* Қазақтелеком — Помощник руководителя. Apple-style. Палитра — синий. */
:root { :root {
/* Brand — извлечено из логотипа: sky #4FB1F7, mid #2D95E2, royal #1972C7 */ /* Brand — палитра выбрана из icon.jpg (sky → royal градиент) */
--kt-blue: #1972C7; --kt-blue: #1F76BD; /* основной — bottom royal logo */
--kt-blue-dark: #115C9F; --kt-blue-dark: #155F9C;
--kt-blue-darker: #0E4A82; --kt-blue-darker: #0F4D80;
--kt-blue-deep: #0A3A66; --kt-blue-deep: #0A3A66;
--kt-blue-light: #4FB1F7; --kt-blue-light: #5BAEED; /* sky — top of logo */
--kt-blue-mid: #2D95E2; --kt-blue-mid: #3389C9; /* mid градиент */
--kt-accent: #FFD23F; --kt-accent: #FFD23F;
/* Apple-ish neutrals */ /* Apple-ish neutrals */
@ -52,7 +52,7 @@ body {
background: var(--bg); background: var(--bg);
background-image: background-image:
radial-gradient(circle at 0% 0%, rgba(79, 177, 247, 0.08) 0%, transparent 40%), radial-gradient(circle at 0% 0%, rgba(79, 177, 247, 0.08) 0%, transparent 40%),
radial-gradient(circle at 100% 100%, rgba(25, 114, 199, 0.06) 0%, transparent 50%); radial-gradient(circle at 100% 100%, rgba(31, 118, 189, 0.06) 0%, transparent 50%);
background-attachment: fixed; background-attachment: fixed;
color: var(--ink); color: var(--ink);
font-size: 15px; font-size: 15px;
@ -74,14 +74,15 @@ body {
-webkit-backdrop-filter: saturate(180%) blur(20px); -webkit-backdrop-filter: saturate(180%) blur(20px);
backdrop-filter: saturate(180%) blur(20px); backdrop-filter: saturate(180%) blur(20px);
color: var(--ink); color: var(--ink);
border-bottom: 1px solid rgba(25, 114, 199, 0.18); border-bottom: 1px solid rgba(31, 118, 189, 0.18);
box-shadow: 0 1px 0 rgba(25, 114, 199, 0.06); box-shadow: 0 1px 0 rgba(31, 118, 189, 0.06);
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 10; z-index: 10;
gap: 16px; gap: 16px;
} }
.topbar-left { display: flex; align-items: center; gap: 14px; }
.brand { display: flex; align-items: center; gap: 10px; } .brand { display: flex; align-items: center; gap: 10px; }
/* ---------- Hamburger menu + popover ---------- */ /* ---------- Hamburger menu + popover ---------- */
@ -149,7 +150,7 @@ body {
transition: background 0.15s ease; transition: background 0.15s ease;
} }
.menu-item:hover { background: var(--surface-2); } .menu-item:hover { background: var(--surface-2); }
.menu-item.active { background: rgba(25, 114, 199, 0.10); } .menu-item.active { background: rgba(31, 118, 189, 0.10); }
.menu-item.active .menu-title { color: var(--kt-blue); } .menu-item.active .menu-title { color: var(--kt-blue); }
.menu-item.active .menu-icon { background: var(--kt-blue); color: #fff; } .menu-item.active .menu-icon { background: var(--kt-blue); color: #fff; }
@ -170,24 +171,44 @@ body {
.menu-sub { font-size: 12px; color: var(--muted); line-height: 1.3; } .menu-sub { font-size: 12px; color: var(--muted); line-height: 1.3; }
.logo { .logo {
width: 34px; width: 32px;
height: 34px; height: 32px;
filter: drop-shadow(0 2px 6px rgba(25, 114, 199, 0.30)); border-radius: 6px;
object-fit: cover;
filter: drop-shadow(0 2px 6px rgba(31, 118, 189, 0.30));
} }
.brand-name {
font-size: 15px; /* Enterprise wordmark — Oracle / IBM / Salesforce style */
font-weight: 600; .brand-mark {
letter-spacing: -0.01em; display: inline-flex;
line-height: 1.1; align-items: center;
gap: 10px;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
line-height: 1;
user-select: none;
}
.brand-mark-primary {
font-size: 22px;
font-weight: 800;
letter-spacing: 0.02em;
color: var(--kt-blue); color: var(--kt-blue);
text-transform: uppercase;
} }
.brand-sub { .brand-mark-divider {
font-size: 11px; width: 1px;
color: var(--muted); height: 20px;
font-weight: 400; background: rgba(31, 118, 189, 0.35);
margin-top: 1px; display: inline-block;
letter-spacing: 0;
} }
.brand-mark-secondary {
font-size: 13px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
color: var(--ink);
opacity: 0.78;
}
.brand:hover .brand-mark-secondary { opacity: 1; }
.who { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; } .who { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
body[data-view="home"] .who { display: none; } body[data-view="home"] .who { display: none; }
@ -223,10 +244,10 @@ main {
.card { .card {
background: var(--surface); background: var(--surface);
border: 1px solid rgba(25, 114, 199, 0.08); border: 1px solid rgba(31, 118, 189, 0.08);
border-radius: var(--r-xl); border-radius: var(--r-xl);
padding: 32px 36px; padding: 32px 36px;
box-shadow: 0 1px 3px rgba(25, 114, 199, 0.05), 0 4px 16px rgba(25, 114, 199, 0.04); box-shadow: 0 1px 3px rgba(31, 118, 189, 0.05), 0 4px 16px rgba(31, 118, 189, 0.04);
} }
.card h2 { .card h2 {
margin: 0 0 22px; margin: 0 0 22px;
@ -278,7 +299,7 @@ main {
outline: none; outline: none;
background: var(--surface); background: var(--surface);
border-color: var(--kt-blue); border-color: var(--kt-blue);
box-shadow: 0 0 0 4px rgba(25, 114, 199, 0.18); box-shadow: 0 0 0 4px rgba(31, 118, 189, 0.18);
} }
.grid select { .grid select {
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%2386868B' stroke-width='1.5'><path d='M3 5l3 3 3-3'/></svg>"); background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%2386868B' stroke-width='1.5'><path d='M3 5l3 3 3-3'/></svg>");
@ -313,7 +334,7 @@ main {
letter-spacing: -0.005em; letter-spacing: -0.005em;
} }
.btn:active { transform: scale(0.97); } .btn:active { transform: scale(0.97); }
.btn:focus-visible { outline: 4px solid rgba(25, 114, 199, 0.30); outline-offset: 2px; } .btn:focus-visible { outline: 4px solid rgba(31, 118, 189, 0.30); outline-offset: 2px; }
.btn-primary { .btn-primary {
background: var(--kt-blue); background: var(--kt-blue);
@ -402,7 +423,7 @@ main {
background: var(--kt-blue); background: var(--kt-blue);
color: #fff; color: #fff;
} }
.load .chip-btn:focus-visible { outline: 4px solid rgba(25, 114, 199, 0.30); outline-offset: 2px; } .load .chip-btn:focus-visible { outline: 4px solid rgba(31, 118, 189, 0.30); outline-offset: 2px; }
.load .chip-count { .load .chip-count {
background: rgba(0, 0, 0, 0.08); background: rgba(0, 0, 0, 0.08);
color: var(--ink-2); color: var(--ink-2);
@ -446,7 +467,7 @@ main {
background-size: 10px 10px; background-size: 10px 10px;
} }
.filters select:hover { background-color: var(--surface-2); } .filters select:hover { background-color: var(--surface-2); }
.filters select:focus { outline: none; border-color: var(--kt-blue); box-shadow: 0 0 0 4px rgba(25,114,199,0.18); } .filters select:focus { outline: none; border-color: var(--kt-blue); box-shadow: 0 0 0 4px rgba(31,118,189,0.18); }
/* ---------- Table (Apple-style минимализм) ---------- */ /* ---------- Table (Apple-style минимализм) ---------- */
@ -492,7 +513,7 @@ td.title { max-width: 380px; }
.badge.high { background: rgba(255, 59, 48, 0.12); color: var(--danger); } .badge.high { background: rgba(255, 59, 48, 0.12); color: var(--danger); }
.badge.medium { background: rgba(255, 149, 0, 0.14); color: var(--warn); } .badge.medium { background: rgba(255, 149, 0, 0.14); color: var(--warn); }
.badge.low { background: rgba(52, 199, 89, 0.14); color: var(--ok); } .badge.low { background: rgba(52, 199, 89, 0.14); color: var(--ok); }
.badge.status-new { background: rgba(25, 114, 199, 0.12); color: var(--kt-blue); } .badge.status-new { background: rgba(31, 118, 189, 0.12); color: var(--kt-blue); }
.badge.status-in_progress { background: rgba(255, 149, 0, 0.14); color: var(--warn); } .badge.status-in_progress { background: rgba(255, 149, 0, 0.14); color: var(--warn); }
.badge.status-done { background: rgba(52, 199, 89, 0.14); color: var(--ok); } .badge.status-done { background: rgba(52, 199, 89, 0.14); color: var(--ok); }
.badge.status-overdue { background: rgba(255, 59, 48, 0.12); color: var(--danger); } .badge.status-overdue { background: rgba(255, 59, 48, 0.12); color: var(--danger); }
@ -516,7 +537,7 @@ td.actions-cell { white-space: nowrap; display: flex; gap: 8px; flex-wrap: nowra
background-size: 9px 9px; background-size: 9px 9px;
} }
.prio-select:hover { background-color: var(--surface-2); } .prio-select:hover { background-color: var(--surface-2); }
.prio-select:focus { outline: none; border-color: var(--kt-blue); box-shadow: 0 0 0 3px rgba(25,114,199,0.15); } .prio-select:focus { outline: none; border-color: var(--kt-blue); box-shadow: 0 0 0 3px rgba(31,118,189,0.15); }
/* ---------- Flatpickr (большой брендированный календарь) ---------- */ /* ---------- Flatpickr (большой брендированный календарь) ---------- */
@ -651,7 +672,6 @@ input.flatpickr-input {
/* ---------- Home (Apple hero-style) ---------- */ /* ---------- Home (Apple hero-style) ---------- */
.brand { text-decoration: none; color: inherit; } .brand { text-decoration: none; color: inherit; }
.brand:hover .brand-name { opacity: 0.7; }
.home-grid { .home-grid {
display: grid; display: grid;
@ -813,9 +833,10 @@ input.flatpickr-input {
@media (max-width: 900px) { @media (max-width: 900px) {
.home-grid { grid-template-columns: 1fr; } .home-grid { grid-template-columns: 1fr; }
.clock-time { font-size: 48px; } .clock-time { font-size: 64px; }
.weather-temp { font-size: 44px; } .weather-temp { font-size: 64px; }
.weather-icon { font-size: 44px; } .weather-icon { font-size: 56px; }
.home-clock, .home-weather { padding: 32px 24px; min-height: 200px; }
} }
/* ---------- Toast ---------- */ /* ---------- Toast ---------- */
@ -899,18 +920,104 @@ input.flatpickr-input {
.menu-panel { min-width: 280px; } .menu-panel { min-width: 280px; }
} }
/* ---------- Responsive ---------- */ /* ---------- Responsive (mobile-first) ---------- */
@media (max-width: 900px) { @media (max-width: 900px) {
.grid { grid-template-columns: 1fr; } .grid { grid-template-columns: 1fr; }
.dashboard { grid-template-columns: 1fr 1fr; } .dashboard { grid-template-columns: 1fr 1fr; }
.topbar { padding: 12px 16px; } .topbar { padding: 10px 14px; height: auto; flex-wrap: wrap; gap: 8px; }
main { padding: 0 12px; margin: 16px auto; } main { padding: 0 12px; margin: 16px auto 60px; }
.card { padding: 16px; } .card { padding: 20px 16px; border-radius: var(--r-lg); }
.card h2 { font-size: 19px; margin-bottom: 16px; }
.who { gap: 6px; }
.who label { display: none; }
.brand-mark-secondary { display: none; }
.brand-mark-divider { display: none; }
} }
@media (max-width: 540px) { @media (max-width: 540px) {
/* Topbar */
.topbar { padding: 8px 12px; }
.topbar-left { gap: 10px; }
.brand-mark-primary { font-size: 18px; }
.who select { font-size: 12px; padding: 5px 22px 5px 10px; }
#resetDemo { font-size: 12px; padding: 6px 12px; }
/* Cards */
.card { padding: 16px 14px; }
.card h2 { font-size: 17px; padding-left: 10px; }
/* Dashboard */
.dashboard { grid-template-columns: 1fr; } .dashboard { grid-template-columns: 1fr; }
.brand-sub { display: none; }
table { font-size: 12px; } /* KPIs */
th, td { padding: 8px 6px; } .kpis { grid-template-columns: repeat(2, 1fr); gap: 12px; }
.kpi { padding: 16px; }
.kpi-num { font-size: 36px; }
.kpi-lbl { font-size: 12px; margin-top: 6px; }
/* Таблица — горизонтальный скролл */
.card:has(#tasksTable) { padding: 16px 0; }
#tasksTable { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
#tasksTable thead, #tasksTable tbody, #tasksTable tr { display: table; width: 100%; table-layout: fixed; }
table { font-size: 13px; min-width: 600px; }
th, td { padding: 10px 8px; }
td.title { max-width: 160px; word-break: break-word; }
td.actions-cell { flex-wrap: wrap; gap: 4px; }
.btn-sm { font-size: 11px; padding: 4px 10px; }
/* Filters — горизонтальный скролл */
.filters {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
gap: 8px;
padding-bottom: 6px;
scrollbar-width: none;
}
.filters::-webkit-scrollbar { display: none; }
.filters select { flex-shrink: 0; font-size: 13px; padding: 7px 28px 7px 12px; }
#clearFilters { flex-shrink: 0; }
/* Загрузка по сотрудникам */
.load { gap: 6px; }
.load .chip-btn { font-size: 13px; padding: 6px 6px 6px 12px; }
/* Форма создания поручения */
.actions { flex-direction: column; align-items: stretch; gap: 12px; }
.actions .btn { width: 100%; justify-content: center; }
.actions .hint { text-align: center; }
/* Новости */
.news-title { font-size: 15px; }
.news-link { gap: 12px; padding: 16px 4px; flex-wrap: wrap; }
.news-meta { gap: 8px; }
.news-host { display: none; }
/* Погода */
.weather-main { gap: 14px; }
.weather-temp { font-size: 48px; }
.weather-icon { font-size: 48px; }
.weather-label { font-size: 17px; }
.weather-meta { gap: 12px; font-size: 13px; }
/* Часы */
.clock-time { font-size: 56px; }
.clock-date { font-size: 17px; }
/* Toast */
.toast { left: 12px; right: 12px; bottom: 16px; max-width: none; font-size: 13px; }
/* Flatpickr */
.flatpickr-calendar { width: calc(100vw - 24px) !important; }
/* Меню */
.menu-panel {
min-width: calc(100vw - 24px);
left: 0;
right: 0;
position: fixed;
top: 56px;
}
} }