186 lines
12 KiB
HTML
186 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Мастер-классы — Morozovka Portal</title>
|
||
<style>
|
||
* { box-sizing: border-box; }
|
||
body { background: #0d1117; color: #e6edf3; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; font-size: 14px; line-height: 1.5; }
|
||
a { color: #58a6ff; text-decoration: none; }
|
||
a:hover { text-decoration: underline; }
|
||
|
||
.topnav { background: #161b22; border-bottom: 1px solid #30363d; padding: 12px 32px; display: flex; align-items: center; gap: 24px; }
|
||
.topnav-logo { display: flex; align-items: center; gap: 8px; color: #e6edf3; font-weight: 600; font-size: 15px; }
|
||
.topnav-logo svg { color: #58a6ff; }
|
||
.topnav-links { display: flex; gap: 20px; flex: 1; }
|
||
.topnav-links a { color: #c9d1d9; font-weight: 500; }
|
||
.topnav-links a:hover { color: #58a6ff; text-decoration: none; }
|
||
.topnav-actions { display: flex; gap: 12px; align-items: center; padding-right: 80px; }
|
||
|
||
.btn { display: inline-flex; align-items: center; gap: 6px; padding: 5px 16px; border-radius: 6px; font-size: 14px; font-weight: 500; line-height: 20px; border: 1px solid rgba(240,246,252,0.1); cursor: pointer; text-decoration: none; white-space: nowrap; transition: all .15s; }
|
||
.btn:hover { text-decoration: none; }
|
||
.btn-primary { background: #238636; color: #fff; }
|
||
.btn-primary:hover { background: #2ea043; }
|
||
.btn-default { background: #21262d; color: #c9d1d9; }
|
||
.btn-default:hover { background: #30363d; }
|
||
|
||
.container { max-width: 1100px; margin: 0 auto; padding: 24px 32px; }
|
||
.page-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 24px; gap: 16px; flex-wrap: wrap; }
|
||
.page-title { font-size: 24px; font-weight: 600; margin: 0 0 4px; color: #e6edf3; }
|
||
.page-subtitle { color: #8b949e; font-size: 14px; margin: 0; }
|
||
|
||
.filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 24px; padding: 16px; background: #161b22; border: 1px solid #30363d; border-radius: 6px; }
|
||
.filter-chip { display: inline-flex; align-items: center; padding: 4px 10px; font-size: 12px; font-weight: 500; border-radius: 2em; border: 1px solid #30363d; background: #21262d; color: #c9d1d9; cursor: pointer; }
|
||
.filter-chip:hover { background: #30363d; text-decoration: none; color: #e6edf3; }
|
||
.filter-chip.active { background: #1f6feb; border-color: #1f6feb; color: #fff; }
|
||
.filter-chip.active:hover { background: #388bfd; color: #fff; }
|
||
.filter-chip-clear { border-color: #f85149; color: #f85149; background: transparent; }
|
||
.filter-chip-clear:hover { background: rgba(248,81,73,0.1); color: #f85149; }
|
||
.filter-label { color: #8b949e; font-size: 12px; font-weight: 600; text-transform: uppercase; align-self: center; margin-right: 6px; }
|
||
|
||
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }
|
||
.ws-card { background: #161b22; border: 1px solid #30363d; border-radius: 6px; overflow: hidden; display: flex; flex-direction: column; transition: border-color .15s; }
|
||
.ws-card:hover { border-color: #58a6ff; }
|
||
.ws-card-cover { height: 120px; background: linear-gradient(135deg, #1f6feb 0%, #a371f7 100%); display: flex; align-items: center; justify-content: center; font-size: 2.5rem; position: relative; }
|
||
.ws-card-cover-partner { position: absolute; top: 8px; right: 10px; background: rgba(0,0,0,0.5); color: #fff; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600; }
|
||
.ws-card-body { padding: 16px; flex: 1; display: flex; flex-direction: column; }
|
||
.ws-card h3 { color: #e6edf3; font-size: 16px; font-weight: 600; margin: 0 0 8px; line-height: 1.4; }
|
||
.ws-card h3 a { color: inherit; }
|
||
.ws-card h3 a:hover { color: #58a6ff; text-decoration: none; }
|
||
.ws-card-desc { color: #8b949e; font-size: 13px; line-height: 1.5; margin: 0 0 12px; flex: 1; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
|
||
|
||
.badges { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
|
||
.badge { display: inline-block; padding: 0 7px; border-radius: 2em; font-size: 12px; font-weight: 500; line-height: 18px; border: 1px solid; white-space: nowrap; }
|
||
.badge-cat-soldering { background: rgba(88,166,255,0.15); color: #58a6ff; border-color: rgba(88,166,255,0.4); }
|
||
.badge-cat-embroidery { background: rgba(163,113,247,0.15); color: #a371f7; border-color: rgba(163,113,247,0.4); }
|
||
.badge-cat-embedded { background: rgba(63,185,80,0.15); color: #3fb950; border-color: rgba(63,185,80,0.4); }
|
||
.badge-cat-linux { background: rgba(210,153,34,0.15); color: #d29922; border-color: rgba(210,153,34,0.4); }
|
||
.badge-cat-other { background: rgba(139,148,158,0.15); color: #8b949e; border-color: rgba(139,148,158,0.4); }
|
||
.badge-status-draft { background: rgba(139,148,158,0.15); color: #8b949e; border-color: rgba(139,148,158,0.4); }
|
||
.badge-status-published { background: rgba(63,185,80,0.15); color: #3fb950; border-color: rgba(63,185,80,0.4); }
|
||
.badge-status-archived { background: rgba(210,153,34,0.15); color: #d29922; border-color: rgba(210,153,34,0.4); }
|
||
.badge-vis-internal { background: rgba(248,81,73,0.15); color: #f85149; border-color: rgba(248,81,73,0.4); }
|
||
.badge-difficulty-beginner { background: rgba(63,185,80,0.15); color: #3fb950; border-color: rgba(63,185,80,0.4); }
|
||
.badge-difficulty-intermediate { background: rgba(210,153,34,0.15); color: #d29922; border-color: rgba(210,153,34,0.4); }
|
||
.badge-difficulty-advanced { background: rgba(248,81,73,0.15); color: #f85149; border-color: rgba(248,81,73,0.4); }
|
||
|
||
.ws-meta { display: flex; flex-wrap: wrap; gap: 12px; font-size: 12px; color: #8b949e; padding-top: 12px; border-top: 1px solid #30363d; margin-top: auto; }
|
||
.ws-meta-item { display: inline-flex; align-items: center; gap: 4px; }
|
||
|
||
.empty-state { padding: 64px 24px; text-align: center; color: #8b949e; background: #161b22; border: 1px dashed #30363d; border-radius: 6px; }
|
||
.empty-state h3 { color: #e6edf3; margin-bottom: 8px; font-size: 16px; }
|
||
.empty-state p { margin-bottom: 16px; }
|
||
|
||
@media (max-width: 768px) {
|
||
.topnav { padding: 12px 16px; gap: 12px; }
|
||
.topnav-links { display: none; }
|
||
.topnav-actions { padding-right: 60px; }
|
||
.container { padding: 16px; }
|
||
.page-title { font-size: 20px; }
|
||
.grid { grid-template-columns: 1fr; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<nav class="topnav">
|
||
<a href="/" class="topnav-logo">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15h-2v-6h2v6zm0-8h-2V7h2v2zm4 8h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>
|
||
Morozovka Platform
|
||
</a>
|
||
<div class="topnav-links">
|
||
<a href="/schedule">Расписание</a>
|
||
<a href="/projects">Проекты</a>
|
||
<a href="/workshops" style="color:#58a6ff;">Мастер-классы</a>
|
||
<a href="/files">Файлы</a>
|
||
</div>
|
||
<div class="topnav-actions">
|
||
{% if session.get('username') %}
|
||
<a href="/profile" class="btn btn-default">{{ session.get('username') }}</a>
|
||
{% else %}
|
||
<a href="/login" class="btn btn-default">Войти</a>
|
||
{% endif %}
|
||
</div>
|
||
</nav>
|
||
|
||
<div class="container">
|
||
<div class="page-header">
|
||
<div>
|
||
<h1 class="page-title">Мастер-классы</h1>
|
||
<p class="page-subtitle">Практические занятия: пайка, embedded, Linux, творчество</p>
|
||
</div>
|
||
{% if can_create %}
|
||
<a href="/workshops/new" class="btn btn-primary">
|
||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8 2a.75.75 0 0 1 .75.75v4.5h4.5a.75.75 0 0 1 0 1.5h-4.5v4.5a.75.75 0 0 1-1.5 0v-4.5h-4.5a.75.75 0 0 1 0-1.5h4.5v-4.5A.75.75 0 0 1 8 2Z"/></svg>
|
||
Создать мастер-класс
|
||
</a>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div class="filters">
|
||
<span class="filter-label">Категория:</span>
|
||
<a href="?{% if current_status %}status={{ current_status }}&{% endif %}category=" class="filter-chip {% if not current_cat %}active{% endif %}">Все</a>
|
||
{% for cat in WORKSHOP_CATEGORIES %}
|
||
<a href="?{% if current_status %}status={{ current_status }}&{% endif %}category={{ cat }}" class="filter-chip {% if current_cat == cat %}active{% endif %}">{{ WORKSHOP_CATEGORY_LABELS[cat] }}</a>
|
||
{% endfor %}
|
||
<span style="width:16px;"></span>
|
||
<span class="filter-label">Статус:</span>
|
||
<a href="?{% if current_cat %}category={{ current_cat }}&{% endif %}status=" class="filter-chip {% if not current_status %}active{% endif %}">Все</a>
|
||
<a href="?{% if current_cat %}category={{ current_cat }}&{% endif %}status=published" class="filter-chip {% if current_status == 'published' %}active{% endif %}">Опубликован</a>
|
||
<a href="?{% if current_cat %}category={{ current_cat }}&{% endif %}status=archived" class="filter-chip {% if current_status == 'archived' %}active{% endif %}">В архиве</a>
|
||
{% if session.get('role') in ['admin', 'professor', 'lead'] %}
|
||
<a href="?{% if current_cat %}category={{ current_cat }}&{% endif %}status=draft" class="filter-chip {% if current_status == 'draft' %}active{% endif %}">Черновик</a>
|
||
{% endif %}
|
||
{% if current_cat or current_status %}
|
||
<a href="/workshops" class="filter-chip filter-chip-clear">✕ Сбросить</a>
|
||
{% endif %}
|
||
</div>
|
||
|
||
{% if workshops %}
|
||
<div class="grid">
|
||
{% for ws in workshops %}
|
||
<div class="ws-card">
|
||
<div class="ws-card-cover">
|
||
{% if ws.category == 'soldering' %}🔥
|
||
{% elif ws.category == 'embroidery' %}🎨
|
||
{% elif ws.category == 'embedded' %}⚙️
|
||
{% elif ws.category == 'linux' %}🐧
|
||
{% else %}🎓{% endif %}
|
||
{% if ws.partner %}<span class="ws-card-cover-partner">{{ ws.partner }}</span>{% endif %}
|
||
</div>
|
||
<div class="ws-card-body">
|
||
<div class="badges">
|
||
<span class="badge badge-cat-{{ ws.category }}">{{ WORKSHOP_CATEGORY_LABELS[ws.category] }}</span>
|
||
<span class="badge badge-difficulty-{{ ws.difficulty }}">{{ WORKSHOP_DIFFICULTY_LABELS[ws.difficulty] }}</span>
|
||
<span class="badge badge-status-{{ ws.status }}">{{ WORKSHOP_STATUS_LABELS[ws.status] }}</span>
|
||
{% if ws.visibility == 'internal' %}<span class="badge badge-vis-internal">Внутренний</span>{% endif %}
|
||
</div>
|
||
<h3><a href="/workshops/{{ ws.id }}">{{ ws.title }}</a></h3>
|
||
<p class="ws-card-desc">{{ ws.description or 'Без описания' }}</p>
|
||
<div class="ws-meta">
|
||
{% set lead = leads_map.get(ws.lead_id) %}
|
||
{% if lead %}<span class="ws-meta-item">👤 {{ lead.full_name or lead.username }}</span>{% endif %}
|
||
{% set sess = next_sessions.get(ws.id) %}
|
||
{% if sess %}
|
||
<span class="ws-meta-item">📅 {{ sess.start_time|msk_strftime('%d.%m %H:%M') }}–{{ sess.end_time|msk_strftime('%H:%M') }}</span>
|
||
{% endif %}
|
||
<span class="ws-meta-item">🎫 {{ reg_counts.get(ws.id, 0) }}{% if ws.max_participants %}/{{ ws.max_participants }}{% endif %}</span>
|
||
{% if ws.location %}<span class="ws-meta-item">📍 {{ ws.location }}</span>{% endif %}
|
||
{% if ws.has_certificate %}<span class="ws-meta-item">🏅 Сертификат</span>{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% else %}
|
||
<div class="empty-state">
|
||
<h3>Пока нет мастер-классов</h3>
|
||
<p>{% if can_create %}Создайте первый — он появится здесь.{% else %}Загляните позже.{% endif %}</p>
|
||
{% if can_create %}<a href="/workshops/new" class="btn btn-primary">Создать мастер-класс</a>{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
<script src="/static/notif_bell.js"></script>
|
||
</body>
|
||
</html>
|