first commit
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled

This commit is contained in:
2026-07-23 02:38:05 +03:00
commit 8757bec8ac
335 changed files with 61527 additions and 0 deletions

View File

@@ -0,0 +1,403 @@
<!doctype html>
<html lang="ru" data-theme="shell-dark">
<head>
<meta charset="UTF-8">
<title>VidConf — Лобби (хаб действий) — тёмная тема, НА СОГЛАСОВАНИИ</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="../../tokens.css">
<style>
/* =====================================================================
* ТЁМНЫЙ ВАРИАНТ ОБОЛОЧКИ — ПРЕДЛОЖЕНИЕ, НЕ УТВЕРЖДЕНО.
* Разметка и контент идентичны design/mockups/lobby.html 1:1, меняется
* только цветовая схема — палитра переиспользует токены комнаты
* конференции. Обоснование цветов — design/mockups/dark/README.md.
* ===================================================================== */
:root {
color-scheme: dark;
--color-bg: #1E1E1E;
--color-bg-alt: #242424;
--color-surface: #2A2A2A;
--color-surface-glass: rgba(51, 51, 51, .55);
--color-border: #3F3F3F;
--color-border-strong: #585858;
--color-border-pill: #7FDDA8;
--color-ink-900: #E8E8E8;
--color-ink-700: #7FDDA8;
--color-ink-500: #B0B0B0;
--color-ink-400: #5D9A78;
--color-ink-300: #7A7A7A;
--color-accent: #7FDDA8;
--color-accent-hover: #75CA9A;
--color-accent-active: #6CB78C;
--color-accent-text: #10331F;
--color-success: #7FDDA8;
--color-success-bg: rgba(127, 221, 168, .14);
--color-success-dot: #7FDDA8;
--color-danger: #EB93A1;
--color-danger-bg: rgba(235, 147, 161, .14);
--color-danger-dot: #EB93A1;
--color-danger-solid: #B85468;
--color-danger-solid-hover: #B9495F;
--color-warning: #D6A83D;
--color-warning-bg: rgba(214, 168, 61, .16);
--color-warning-dot: #D6A83D;
--color-focus-ring: #D6A83D;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, .35);
--shadow-md: 0 4px 16px rgba(0, 0, 0, .4);
--shadow-lg: 0 12px 32px rgba(0, 0, 0, .5);
--shadow-glass: 0 8px 24px rgba(0, 0, 0, .45);
}
.theme-toggle { display: inline-flex; gap: 2px; background: var(--color-bg-alt); padding: 4px; border-radius: var(--radius-full); border: 1px solid var(--color-border); }
.theme-toggle-btn { width: 32px; height: 32px; border-radius: 50%; border: none; background: transparent; color: var(--color-ink-500); display: flex; align-items: center; justify-content: center; }
.theme-toggle-btn .icon { width: 16px; height: 16px; }
.theme-toggle-btn:hover { color: var(--color-ink-900); }
.theme-toggle-btn.is-active { background: var(--color-surface); color: var(--color-ink-700); box-shadow: var(--shadow-sm); }
html { height: 100%; min-width: 1280px; }
body {
min-height: 100vh;
display: flex;
flex-direction: column;
background:
radial-gradient(1100px 520px at 10% -10%, rgba(214, 168, 61, 0.05), transparent 60%),
radial-gradient(900px 480px at 105% 110%, rgba(127, 221, 168, 0.14), transparent 55%),
var(--color-bg);
}
/* ---------- Верхняя панель ---------- */
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-5) var(--space-8);
}
.brand-mark { display: inline-flex; align-items: center; gap: 8px; font: var(--text-h3); color: var(--color-ink-700); }
.brand-mark .logo-mark { width: 22px; height: 22px; flex-shrink: 0; }
.topbar-right { display: flex; align-items: center; gap: var(--space-4); }
.burger {
width: 44px; height: 44px;
display: inline-flex; align-items: center; justify-content: center;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-ink-700);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.burger:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-sm); }
.burger[aria-expanded="true"] { border-color: var(--color-ink-700); }
.menu-wrap { position: relative; }
.menu {
position: absolute;
top: calc(100% + 10px);
right: 0;
min-width: 236px;
padding: var(--space-2);
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-lg);
display: none;
z-index: 30;
}
.menu.is-open { display: block; }
.menu a {
display: flex; align-items: center; gap: 10px;
padding: 10px 14px;
border-radius: var(--radius-sm);
font: var(--text-body-lg); font-weight: 600;
color: var(--color-ink-900);
text-decoration: none;
}
.menu a:hover { background: var(--color-bg-alt); color: var(--color-ink-700); }
.menu a .icon { color: var(--color-ink-400); }
.menu-divider { height: 1px; background: var(--color-border); margin: var(--space-2) 6px; }
.menu a.danger { color: var(--color-danger); }
.menu a.danger .icon { color: var(--color-danger); }
.user-pill {
display: inline-flex; align-items: center; gap: 10px;
padding: 6px 16px 6px 6px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-full);
font: var(--text-body); font-weight: 600; color: var(--color-ink-900);
transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.user-pill:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-sm); }
.user-pill .avatar {
width: 30px; height: 30px; border-radius: 50%;
background: var(--color-ink-700); color: var(--color-accent-text);
display: flex; align-items: center; justify-content: center;
font: var(--text-caption);
}
/* ---------- Мозаика действий ---------- */
main {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: var(--space-6) var(--space-8) var(--space-12);
}
.hub-wrap { display: flex; flex-direction: column; align-items: center; gap: var(--space-8); width: 100%; }
.hub-intro { text-align: center; max-width: 560px; }
.hub-intro .eyebrow { font: var(--text-caption); color: var(--color-ink-400); margin: 0 0 var(--space-2); }
.hub-intro h1 { font: var(--text-display-lg); font-family: var(--font-display); color: var(--color-ink-700); margin: 0; }
.hub {
position: relative;
width: min(1420px, 100%);
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(2, 340px);
gap: var(--space-8);
}
.action {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
gap: var(--space-3);
padding: var(--space-10) var(--space-12) var(--space-8);
margin-top: 34px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-3xl);
text-decoration: none;
color: var(--color-ink-900);
box-shadow: var(--shadow-sm);
transition:
transform var(--transition-base),
box-shadow var(--transition-base),
border-color var(--transition-base);
}
.action:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
border-color: var(--color-border-strong);
}
.action:active { transform: translateY(-1px); }
.action-icon {
position: absolute;
top: -34px;
left: 50%;
transform: translateX(-50%);
width: 68px; height: 68px;
border-radius: 50%;
background: var(--color-surface);
border: var(--border-thick) solid var(--color-ink-700);
color: var(--color-ink-700);
display: flex; align-items: center; justify-content: center;
box-shadow: var(--shadow-md);
}
.action-icon .icon { width: 30px; height: 30px; }
.action-title {
margin: 0;
font: 600 40px/1.2 var(--font-display);
letter-spacing: 0.01em;
color: var(--color-ink-700);
text-transform: uppercase;
}
.action-object { margin: 0; font: 600 21px/1.35 var(--font-body); color: var(--color-ink-900); }
.action-note { margin: 0; font: 400 17px/1.5 var(--font-body); color: var(--color-ink-500); }
.action--create {
background: var(--color-accent);
border-color: transparent;
}
.action--create:hover { background: var(--color-accent-hover); border-color: transparent; }
.action--create:active { background: var(--color-accent-active); }
.action--create .action-title { font: 700 54px/1.1 var(--font-display); }
.action--create .action-title,
.action--create .action-object { color: var(--color-accent-text); }
.action--create .action-note { color: var(--color-ink-700); }
.action--create .action-icon {
background: var(--color-accent);
border-color: var(--color-accent-text);
color: var(--color-accent-text);
}
/* ---------- Медальон VidConf в центре мозаики ---------- */
.hub-logo {
position: absolute;
top: 373px; left: 50%;
transform: translate(-50%, -50%);
width: 156px; height: 156px;
border-radius: 50%;
background: var(--color-surface);
border: var(--border-thick) solid var(--color-ink-700);
box-shadow: var(--shadow-lg);
display: flex; flex-direction: column;
align-items: center; justify-content: center;
gap: 6px;
z-index: 20;
pointer-events: none;
}
.hub-logo .logo-mark {
width: 56px; height: 56px;
color: var(--color-ink-700);
}
.hub-logo .logo-word {
font: 600 16px/1 var(--font-display);
color: var(--color-ink-700);
}
/* ---------- Появление ---------- */
@media (prefers-reduced-motion: no-preference) {
.action, .hub-logo {
animation: rise 480ms cubic-bezier(0.22, 0.9, 0.3, 1) backwards;
}
.action--create { animation-delay: 60ms; }
.action--calendar { animation-delay: 140ms; }
.action--join { animation-delay: 220ms; }
.action--mine { animation-delay: 300ms; }
.hub-logo { animation-delay: 420ms; }
@keyframes rise {
from { opacity: 0; transform: translateY(14px); }
to { opacity: 1; transform: translateY(0); }
}
.hub-logo { animation-name: rise-logo; }
@keyframes rise-logo {
from { opacity: 0; transform: translate(-50%, calc(-50% + 14px)); }
to { opacity: 1; transform: translate(-50%, -50%); }
}
}
</style>
</head>
<body>
<svg style="display:none" aria-hidden="true">
<symbol id="i-video" viewBox="0 0 24 24"><path d="M15 6H4a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2v-2.5l5 3.5V7l-5 3.5V8a2 2 0 0 0-2-2z"/></symbol>
<symbol id="i-calendar" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></symbol>
<symbol id="i-link2" viewBox="0 0 24 24"><path d="M9 17H7A5 5 0 0 1 7 7h2"/><path d="M15 7h2a5 5 0 1 1 0 10h-2"/><line x1="8" y1="12" x2="16" y2="12"/></symbol>
<symbol id="i-user" viewBox="0 0 24 24"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></symbol>
<symbol id="i-download" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></symbol>
<symbol id="i-info" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></symbol>
<symbol id="i-layout-dashboard" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="9" rx="1"/><rect x="14" y="3" width="7" height="5" rx="1"/><rect x="14" y="12" width="7" height="9" rx="1"/><rect x="3" y="16" width="7" height="5" rx="1"/></symbol>
<symbol id="i-logout" viewBox="0 0 24 24"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></symbol>
<symbol id="i-sun" viewBox="0 0 24 24"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></symbol>
<symbol id="i-moon" viewBox="0 0 24 24"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z"/></symbol>
</svg>
<header class="topbar">
<div class="brand-mark"><svg class="logo-mark" viewBox="0 0 32 32" fill="none" aria-hidden="true"><polygon points="21,16 18.5,20.3 13.5,20.3 11,16 13.5,11.7 18.5,11.7" fill="currentColor"/><circle cx="16" cy="16" r="13" stroke="currentColor" stroke-width="2.6" stroke-dasharray="12 6"/></svg> VidConf</div>
<div class="topbar-right">
<div class="theme-toggle" role="group" aria-label="Переключить тему оформления">
<button class="theme-toggle-btn" type="button" aria-pressed="false" aria-label="Светлая тема"><svg class="icon"><use href="#i-sun"/></svg></button>
<button class="theme-toggle-btn is-active" type="button" aria-pressed="true" aria-label="Тёмная тема"><svg class="icon"><use href="#i-moon"/></svg></button>
</div>
<button class="user-pill">
<span class="avatar" aria-hidden="true">ИИ</span>
Иванов Иван
</button>
<div class="menu-wrap">
<button class="burger" id="burger" aria-expanded="false" aria-controls="main-menu" aria-label="Открыть меню">
<svg class="icon" viewBox="0 0 24 24"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/></svg>
</button>
<nav class="menu" id="main-menu" aria-label="Основное меню">
<a href="#"><svg class="icon"><use href="#i-user"/></svg> Профиль</a>
<a href="admin.html"><svg class="icon"><use href="#i-layout-dashboard"/></svg> Админка</a>
<a href="#"><svg class="icon"><use href="#i-download"/></svg> Скачать приложение</a>
<a href="#"><svg class="icon"><use href="#i-info"/></svg> О сервисе</a>
<div class="menu-divider"></div>
<a href="login.html" class="danger"><svg class="icon"><use href="#i-logout"/></svg> Выйти</a>
</nav>
</div>
</div>
</header>
<main>
<div class="hub-wrap">
<div class="hub-intro">
<p class="eyebrow">[ ДОБРО ПОЖАЛОВАТЬ В VIDCONF ]</p>
<h1>Что делаем сегодня?</h1>
</div>
<div class="hub">
<a class="action action--create" href="../room.html">
<span class="action-icon" aria-hidden="true"><svg class="icon"><use href="#i-video"/></svg></span>
<h2 class="action-title">Создать</h2>
<p class="action-object">конференцию</p>
<p class="action-note">начнётся сразу — вы первый участник</p>
</a>
<a class="action action--calendar" href="calendar.html">
<span class="action-icon" aria-hidden="true"><svg class="icon"><use href="#i-calendar"/></svg></span>
<h2 class="action-title">Календарь</h2>
<p class="action-object">конференций</p>
<p class="action-note">запланировать · закрепить · повторять</p>
</a>
<a class="action action--join" href="join.html">
<span class="action-icon" aria-hidden="true"><svg class="icon"><use href="#i-link2"/></svg></span>
<h2 class="action-title">Подключиться</h2>
<p class="action-object">к конференции</p>
<p class="action-note">по ссылке или номеру</p>
</a>
<a class="action action--mine" href="my-conferences.html">
<span class="action-icon" aria-hidden="true"><svg class="icon"><use href="#i-user"/></svg></span>
<h2 class="action-title">Мои</h2>
<p class="action-object">конференции</p>
<p class="action-note">закреплённые и предстоящие</p>
</a>
<div class="hub-logo" aria-hidden="true">
<svg class="logo-mark" viewBox="0 0 64 64" fill="none" aria-hidden="true">
<polygon points="41,32 36.5,39.8 27.5,39.8 23,32 27.5,24.2 36.5,24.2" fill="currentColor"/>
<circle cx="32" cy="32" r="15" stroke="currentColor" stroke-width="3" stroke-dasharray="16 7 28 9 12 16" stroke-dashoffset="5"/>
<circle cx="32" cy="32" r="20" stroke="currentColor" stroke-width="2" stroke-dasharray="22 10 8 14 34 12 6 10" stroke-dashoffset="40"/>
<circle cx="32" cy="32" r="25" stroke="currentColor" stroke-width="3.5" stroke-dasharray="40 14 12 10 26 16 20 8" stroke-dashoffset="80"/>
<circle cx="32" cy="32" r="29" stroke="currentColor" stroke-width="1.6" stroke-dasharray="10 6 60 20 30 10 24 8" stroke-dashoffset="120"/>
</svg>
<span class="logo-word">VidConf</span>
</div>
</div>
</div>
</main>
<script>
// Бургер-меню: открытие/закрытие, клик мимо и Escape закрывают.
const burger = document.getElementById('burger');
const menu = document.getElementById('main-menu');
function setMenu(open) {
menu.classList.toggle('is-open', open);
burger.setAttribute('aria-expanded', String(open));
burger.setAttribute('aria-label', open ? 'Закрыть меню' : 'Открыть меню');
}
burger.addEventListener('click', () => setMenu(!menu.classList.contains('is-open')));
document.addEventListener('click', (e) => {
if (!e.target.closest('.menu-wrap')) setMenu(false);
});
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') { setMenu(false); burger.focus(); }
});
</script>
</body>
</html>