веб-ui: знак «jb» стал единым для шапки, иконки вкладки и превью ссылки

- логотип сведён в web/static/logo.svg (буквы геометрией, оптическая
  центровка); прежний favicon с «play» убран
- <head> шести страниц свёрнут в партиал head с og-мета; адреса абсолютные,
  база берётся из запроса, хост из недоверенного заголовка проверяется
- растровые ассеты og-cover.jpg и apple-touch-icon.png собирает `task brand`
  из исходников web/*.html
This commit is contained in:
av
2026-09-02 10:55:45 +03:00
parent 3bce73fc34
commit 2971a520c7
24 changed files with 339 additions and 51 deletions
+32
View File
@@ -0,0 +1,32 @@
<!doctype html>
<!-- Исходник карточки превью ссылки (og:image). Растр собирается командой
`task brand` в web/static/og-cover.png; правим здесь, а не в PNG.
Размер 1200×630 — канонический для Open Graph. -->
<html lang="ru">
<meta charset="utf-8">
<style>
@font-face{font-family:'IBM Plex Sans';font-weight:400;
src:url(static/vendor/fonts/ibm-plex-sans-cyrillic-400.woff2) format('woff2');
unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'IBM Plex Sans';font-weight:400;
src:url(static/vendor/fonts/ibm-plex-sans-latin-400.woff2) format('woff2')}
@font-face{font-family:'IBM Plex Sans';font-weight:700;
src:url(static/vendor/fonts/ibm-plex-sans-cyrillic-700.woff2) format('woff2');
unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'IBM Plex Sans';font-weight:700;
src:url(static/vendor/fonts/ibm-plex-sans-latin-700.woff2) format('woff2')}
html,body{margin:0;padding:0}
body{width:1200px;height:630px;overflow:hidden;
font-family:'IBM Plex Sans',system-ui,sans-serif;
background:radial-gradient(900px 520px at 50% 8%,#1d2b4a 0%,#101724 58%,#0b0f18 100%);
color:#eef2f8;display:flex;flex-direction:column;
align-items:center;justify-content:center;gap:34px}
img{width:176px;height:176px;filter:drop-shadow(0 18px 46px rgba(47,111,237,.45))}
h1{margin:0;font-size:96px;font-weight:700;letter-spacing:-.035em;line-height:1}
p{margin:0;font-size:33px;font-weight:400;color:#94a3b8;letter-spacing:-.01em}
b{color:#7aa5f7;font-weight:400}
</style>
<img src="static/logo.svg" alt="">
<h1>jellybit</h1>
<p>раздача <b></b> распознавание <b></b> библиотека Jellyfin</p>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

+1 -2
View File
@@ -129,8 +129,7 @@ a:hover{text-decoration:underline}
.brand{display:flex;align-items:center;gap:9px;font-weight:700;font-size:var(--fs-md);
letter-spacing:-.01em;color:var(--text)}
.brand:hover{text-decoration:none}
.brand .logo{width:22px;height:22px;border-radius:6px;background:var(--accent);
display:grid;place-items:center;color:var(--on-accent);font-size:13px;flex:none}
.brand .logo{width:22px;height:22px;flex:none;display:block}
.nav{display:flex;gap:2px;margin-left:var(--sp-2)}
.nav a{padding:6px 11px;border-radius:var(--r-sm);font-size:var(--fs-sm);font-weight:500;
color:var(--text-dim)}
-12
View File
@@ -1,12 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="jellybit">
<defs>
<linearGradient id="j" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#8b5cf6"/>
<stop offset="1" stop-color="#6d28d9"/>
</linearGradient>
</defs>
<rect x="4" y="4" width="56" height="56" rx="14" fill="url(#j)"/>
<path d="M26 21 L45 32 L26 43 Z" fill="#fff"/>
<rect x="17" y="21" width="5" height="5" rx="1" fill="#fff" opacity=".85"/>
<rect x="17" y="38" width="5" height="5" rx="1" fill="#fff" opacity=".85"/>
</svg>

Before

Width:  |  Height:  |  Size: 563 B

+21
View File
@@ -0,0 +1,21 @@
<!-- Знак jellybit: буквы «jb» в скруглённом квадрате акцентного цвета.
Единственный источник логотипа — шапка веб-UI, favicon и карточка превью
ссылки (og-cover.jpg собирается из него же, `task brand`). Буквы заданы
геометрией, а не текстом: favicon рендерится без наших шрифтов.
Знак оптически центрирован — центр масс белого лежит на середине холста. -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="jellybit">
<defs>
<linearGradient id="jb-bg" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#4a86f5"/>
<stop offset="1" stop-color="#2453c8"/>
</linearGradient>
</defs>
<rect width="64" height="64" rx="15" fill="url(#jb-bg)"/>
<g fill="#fff" fill-rule="evenodd" transform="translate(0,-0.3)">
<!-- b: стержень и правая половина чаши одним контуром, дырка — вторым -->
<path d="M32.8 13.5h6.4V24.5A10.2 10.2 0 0 1 39.2 44.9H32.8ZM39.2 39.9A5.2 5.2 0 0 0 39.2 29.5Z"/>
<!-- j: стержень с хвостом влево -->
<path d="M20.3 24.5h6.4v17.2a7.6 7.6 0 0 1-7.6 7.6h-1.6a3.2 3.2 0 0 1 0-6.4h1.6a1.2 1.2 0 0 0 1.2-1.2z"/>
<circle cx="23.5" cy="17" r="3.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

+1 -5
View File
@@ -1,11 +1,7 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jellybit — удаление</title>
<link rel="icon" href="{{asset "favicon.svg"}}" type="image/svg+xml">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{template "head" .Meta}}
</head>
<body>
+1 -5
View File
@@ -1,11 +1,7 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jellybit — подтверждение удаления</title>
<link rel="icon" href="{{asset "favicon.svg"}}" type="image/svg+xml">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{template "head" .Meta}}
</head>
<body>
+1 -5
View File
@@ -1,11 +1,7 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jellybit — результат удаления</title>
<link rel="icon" href="{{asset "favicon.svg"}}" type="image/svg+xml">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{template "head" .Meta}}
</head>
<body>
+1 -5
View File
@@ -1,11 +1,7 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jellybit — загрузка #{{.ID}}</title>
<link rel="icon" href="{{asset "favicon.svg"}}" type="image/svg+xml">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{template "head" .Meta}}
<script src="{{asset "vendor/htmx.min.js"}}" defer></script>
<script src="{{asset "js/app.js"}}" defer></script>
</head>
+1 -5
View File
@@ -1,11 +1,7 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jellybit — загрузки</title>
<link rel="icon" href="{{asset "favicon.svg"}}" type="image/svg+xml">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{template "head" .Meta}}
<script src="{{asset "vendor/htmx.min.js"}}" defer></script>
<script src="{{asset "js/app.js"}}" defer></script>
</head>
+22
View File
@@ -0,0 +1,22 @@
{{define "head"}}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}}</title>
<meta name="description" content="Качает раздачу через qBittorrent, распознаёт фильм или сериал и раскладывает файлы для Jellyfin хардлинками.">
<link rel="icon" href="{{asset "logo.svg"}}" type="image/svg+xml">
<link rel="apple-touch-icon" href="{{asset "apple-touch-icon.png"}}">
<meta name="theme-color" content="#2f6fed">
{{/* Превью ссылки в мессенджере: карточка со знаком jb. Адреса абсолютные —
краулер не обязан разрешать относительные (см. pageMeta). */}}
<meta property="og:type" content="website">
<meta property="og:site_name" content="jellybit">
<meta property="og:title" content="{{.Title}}">
<meta property="og:description" content="Качает раздачу через qBittorrent, распознаёт фильм или сериал и раскладывает файлы для Jellyfin хардлинками.">
<meta property="og:url" content="{{.URL}}">
<meta property="og:image" content="{{.Image}}">
<meta property="og:image:type" content="image/jpeg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:card" content="summary_large_image">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{end}}
+1 -1
View File
@@ -1,7 +1,7 @@
{{define "header"}}
<header class="app-header">
<div class="bar">
<a class="brand" href="/"><span class="logo">jb</span>jellybit</a>
<a class="brand" href="/"><img class="logo" src="{{asset "logo.svg"}}" width="22" height="22" alt="">jellybit</a>
<nav class="nav">
<a href="/"{{if eq . "downloads"}} class="active"{{end}}>Загрузки</a>
<a href="/delete"{{if eq . "delete"}} class="active"{{end}}>Удаление</a>
+1 -5
View File
@@ -1,11 +1,7 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jellybit — ревью #{{.ID}}</title>
<link rel="icon" href="{{asset "favicon.svg"}}" type="image/svg+xml">
<link rel="stylesheet" href="{{asset "css/jellybit.css"}}">
{{template "head" .Meta}}
<script src="{{asset "vendor/htmx.min.js"}}" defer></script>
<script src="{{asset "js/app.js"}}" defer></script>
</head>
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<!-- Исходник иконки для домашнего экрана iOS (apple-touch-icon). Знак кладётся
на непрозрачную подложку того же градиента: iOS скругляет углы сама, и
прозрачные углы SVG стали бы чёрными. Растр собирает `task brand`. -->
<html lang="ru">
<meta charset="utf-8">
<style>
html,body{margin:0;padding:0}
body{width:180px;height:180px;overflow:hidden;background:linear-gradient(#4a86f5,#2453c8)}
img{width:180px;height:180px;display:block}
</style>
<img src="static/logo.svg" alt="">