Files
site-portfolio/src/pages/cases/template-elements-demo.html
T
root c14bb1f543 fix: доработки слайдера и просмотрщика
- case-media-slider: обрамление+hover как у карточек, стрелки только при наведении (fade-in),
  группа пред/след-пилюля в правом нижнем углу, disabled-кнопки видны (не скрываются),
  убран border-radius у img/figcaption (скругление у viewport), неактивные слайды не скрываются
  visibility (нет 'дырки' при перелистывании), настраиваемая ширина --wide/--content/--natural
- image-load-placeholder: исключён .case-media-slider (нет блика/серого фона)
- icon-press: универсальный эффект 'продавливания' иконки при нажатии (.icon-press + :active/.is-pressed),
  применён к слайдеру и всем кнопкам просмотрщика
2026-09-09 19:29:30 +02:00

322 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru" data-theme="dark" data-radius="medium" data-font="merriweather">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="description" content="Демо-страница кейса со всеми разработанными элементами: карточки ссылок и медиа-блоки." />
<title>Демо элементов кейса — template</title>
{{> head-links}}
{{> head-plyr}}
<style>
.case-article {
max-width: 48rem;
margin: 0 auto;
}
.case-article h2 {
margin: 2rem 0 0.75rem;
font-size: clamp(1.15rem, 2vw, 1.35rem);
font-weight: 700;
color: var(--text);
}
.case-article h3 {
font-size: 1.05rem;
font-weight: 600;
color: var(--text);
}
.case-article .section__prose {
margin-bottom: 0.75rem;
color: var(--text);
}
.case-article a:not(.btn) {
color: var(--accent);
}
</style>
<script>
(function () {
try {
var t = JSON.parse(localStorage.getItem("siteThemeV1") || "{}");
var d = document.documentElement;
var m = t.mode;
if (m !== "light" && m !== "dark" && m !== "system") m = "system";
var eff =
m === "system"
? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
: m;
d.dataset.theme = eff;
var h = typeof t.h === "number" ? t.h : typeof t.hue === "number" ? t.hue : null;
var s = typeof t.s === "number" ? t.s : typeof t.sat === "number" ? t.sat : null;
var l = typeof t.l === "number" ? t.l : typeof t.light === "number" ? t.light : null;
if (h !== null) d.style.setProperty("--theme-h", String(h));
if (s !== null) d.style.setProperty("--theme-s", String(s));
if (l !== null) {
var L = Number(l);
if (Number.isFinite(L)) d.style.setProperty("--theme-l", String(Math.min(70, Math.max(20, L))));
}
var rad = t.radius;
if (rad === "soft" || rad === "medium" || rad === "strong") {
d.dataset.radius = rad;
} else {
d.dataset.radius = "medium";
}
var f = t.font;
if (f === "onest") f = "geologica";
if (f === "anonymous") f = "mono";
if (f === "merriweather" || f === "mono" || f === "geologica") {
d.dataset.font = f;
} else {
d.dataset.font = "merriweather";
}
var mb = t.meshBg;
if (mb === "off") {
d.dataset.meshBg = "off";
} else {
d.dataset.meshBg = "on";
}
} catch (e) {}
})();
</script>
</head>
<body>
{{> header-minimal}}
{{> fab-stack-home-contact}}
<main id="main" class="section section--tight">
<div class="section__inner case-article">
<p class="hero__eyebrow">Демо · template</p>
<h1 class="case-page__h1">Пример кейса: демо элементов</h1>
<p class="case-page__sub">Рыба-текст и блоки для быстрой сборки лонгрида</p>
<p class="section__prose case-page__code">Медиа для демо лежат в <code>public/assets/</code> (сборка страниц их не копирует). См. <code>public/assets/README.md</code>.</p>
<h2>Контекст</h2>
<p class="section__prose">
Этот раздел показывает пример рыбы для вступления. Здесь можно коротко описать продукт, аудиторию и ограничения проекта.
Текст нейтральный: цель — быстро набросать структуру и проверить визуальный ритм страницы.
</p>
<h2>Задача</h2>
<p class="section__prose">
Нужно собрать демонстрационный лонгрид с основными UI-элементами: карточками ссылок, медиа-блоками и примерами оформления контента.
Дополнительно важно проверить, как блоки ведут себя на узких и широких экранах.
</p>
<h2>Решение</h2>
<p class="section__prose">Ниже собраны готовые примеры, которые можно копировать в реальные кейсы.</p>
<h3>Карточки ссылок</h3>
<div class="case-links-grid">
<a class="case-link-card" href="https://www.examples.com/" target="_blank" rel="noopener noreferrer">
<span class="case-link-card__media" aria-hidden="true">
<img src="{{assetPrefix}}assets/template-elements-demo/wallpaper-1.jpg" alt="" loading="lazy" decoding="async" />
</span>
<span class="case-link-card__body">
<span class="case-link-card__title">Источник с превью</span>
<span class="case-link-card__meta">Короткая подпись: что пользователь увидит по ссылке</span>
<span class="case-link-card__url">www.examples.com</span>
</span>
</a>
<a class="case-link-card case-link-card--favicon" href="https://www.examples.com/docs" target="_blank" rel="noopener noreferrer">
<span class="case-link-card__media" aria-hidden="true">
<img src="https://www.google.com/s2/favicons?domain=www.examples.com&sz=128" alt="" decoding="async" />
</span>
<span class="case-link-card__body">
<span class="case-link-card__title">Источник с favicon</span>
<span class="case-link-card__meta">Вариант для более легких ссылок без скриншота</span>
<span class="case-link-card__url">www.examples.com/docs</span>
</span>
</a>
</div>
<h3>Картинка: 50% от оригинала (без превью)</h3>
<figure class="case-media case-media--natural">
<img src="{{assetPrefix}}assets/template-elements-demo/hello.gif" alt="Демо GIF в натуральном размере" loading="lazy" decoding="async" />
<figcaption>Изображение в уменьшенном натуральном размере, по центру.</figcaption>
</figure>
<h3>Картинка: по ширине контента (с превью)</h3>
<figure class="case-media case-media--content">
<img src="{{assetPrefix}}assets/template-elements-demo/wallpaper-1.jpg" alt="Демо изображения по ширине контента" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Изображение по ширине контента. Клик открывает viewer.</figcaption>
</figure>
<h3>Картинка: чуть шире контента (с превью)</h3>
<figure class="case-media case-media--wide">
<img src="{{assetPrefix}}assets/template-elements-demo/wallpaper-1.jpg" alt="Демо изображения шире контента" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Изображение немного выходит за пределы контентной колонки.</figcaption>
</figure>
<h3>Длинный скрин: свёрнутая высота и кнопка внутри превью</h3>
<p class="section__prose">
Блок <code>data-case-tall-media</code>: ширина задаётся атрибутом <code>data-case-tall-width="wide"</code> (как «широкая» картинка) или <code>content</code> (по колонке). В свёрнутом виде видна верхняя часть кадра, внизу превью — плотный «туман». Кнопка «Развернуть» / «Свернуть» с иконкой-шевроном поверх нижней части кадра, внутри рамки; после раскрытия туман скрывается, после сворачивания страница прокручивается к превью. Высоту превью — на <code>.case-media-tall__clip</code> через <code>--case-tall-max</code> (по умолчанию <code>min(70vh, 32rem)</code>).
</p>
<figure class="case-media" data-case-tall-media data-case-tall-width="wide">
<div class="case-media-tall" data-case-tall-root>
<div class="case-media-tall__clip" id="template-demo-tall-clip" data-case-tall-clip>
<img
src="{{assetPrefix}}assets/template-elements-demo/img-long.webp"
alt="Демо: длинный вертикальный скрин интерфейса"
width="1200"
loading="lazy"
decoding="async"
data-image-viewer
/>
<div class="case-media-tall__fog" aria-hidden="true"></div>
</div>
<div class="case-media-tall__actions">
<button
type="button"
class="case-media-tall__btn btn btn--ghost btn--flat"
data-case-tall-toggle
aria-expanded="false"
aria-controls="template-demo-tall-clip"
>
<span class="case-media-tall__btn-chev" aria-hidden="true"></span>
<span data-case-tall-label-more>Развернуть</span>
<span data-case-tall-label-less hidden>Свернуть</span>
</button>
</div>
</div>
<figcaption>Длинное изображение <code>img-long.webp</code> (исходник PNG рядом в <code>public/assets/template-elements-demo/</code>).</figcaption>
</figure>
<h3>Галерея: сетка по ширине контента</h3>
<p class="section__prose">
Колонок на широком экране задаётся на <code>figure</code>: атрибут <code>style="--case-gallery-cols: 3"</code>. Ниже порогов сетка схлопывается до двух и одной колонки. Клик по миниатюре открывает общий viewer кейса.
</p>
<figure class="case-media case-media-gallery" style="--case-gallery-cols: 3">
<div class="case-media-gallery__grid">
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-1.webp" alt="Демо миниатюра 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-2.webp" alt="Демо миниатюра 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-3.webp" alt="Демо миниатюра 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-4.webp" alt="Демо миниатюра 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-5.webp" alt="Демо миниатюра 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-6.webp" alt="Демо миниатюра 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-7.webp" alt="Демо миниатюра 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<figcaption>Сетка в колонке статьи; на этом примере три колонки на десктопе.</figcaption>
</figure>
<h3>Галерея: сетка на ширину страницы с боковыми отступами</h3>
<p class="section__prose">
Класс <code>case-media-gallery--wide</code> — та же логика выхода за колонку, что у одиночного <code>case-media--wide</code>. Здесь две колонки на широком экране (<code>--case-gallery-cols: 2</code>).
</p>
<figure class="case-media case-media-gallery case-media-gallery--wide" style="--case-gallery-cols: 2">
<div class="case-media-gallery__grid">
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-1.webp" alt="Wide-сетка, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-2.webp" alt="Wide-сетка, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-3.webp" alt="Wide-сетка, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-4.webp" alt="Wide-сетка, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-5.webp" alt="Wide-сетка, кадр 5" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-6.webp" alt="Wide-сетка, кадр 6" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-gallery__item">
<img src="{{assetPrefix}}assets/template-elements-demo/small-image-7.webp" alt="Wide-сетка, кадр 7" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<figcaption>Ширина как у wide-картинки; на узком экране wide-обёртка схлопывается в 100% ширины колонки (см. медиазапросы).</figcaption>
</figure>
<h3>Слайдер: одна картинка, стрелки и точки</h3>
<p class="section__prose">
Блок <code>.case-media-slider</code> показывает слайды по одному: навигация стрелками «пред/след»,
пагинация точками (активная — акцентным цветом). Поддерживается клавиатура (←/→, Home/End на точках),
тач/мышь-свайп и ленивая подгрузка соседних кадров через <code>data-src</code>. Клик по активному
кадру открывает общий viewer кейса.
</p>
<figure class="case-media case-media-slider" data-case-media-slider>
<div class="case-media-slider__viewport" data-slider-viewport>
<div class="case-media-slider__track" data-slider-track>
<div class="case-media-slider__slide">
<img src="{{assetPrefix}}assets/template-elements-demo/slider-demo-1.webp" alt="Слайдер, кадр 1" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="{{assetPrefix}}assets/template-elements-demo/slider-demo-2.webp" alt="Слайдер, кадр 2" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="{{assetPrefix}}assets/template-elements-demo/slider-demo-3.webp" alt="Слайдер, кадр 3" loading="lazy" decoding="async" data-image-viewer />
</div>
<div class="case-media-slider__slide">
<img src="{{assetPrefix}}assets/template-elements-demo/slider-demo-4.webp" alt="Слайдер, кадр 4" loading="lazy" decoding="async" data-image-viewer />
</div>
</div>
<div class="case-media-slider__nav-group">
<button type="button" class="case-media-slider__nav case-media-slider__nav--prev" data-slider-prev aria-label="Предыдущее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--left icon-press" aria-hidden="true"></span>
</button>
<button type="button" class="case-media-slider__nav case-media-slider__nav--next" data-slider-next aria-label="Следующее изображение">
<span class="case-media-slider__nav-ico case-media-slider__nav-ico--right icon-press" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="case-media-slider__dots" data-slider-dots role="tablist" aria-label="Выбор изображения">
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 1"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 2"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 3"></button>
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Перейти к изображению 4"></button>
</div>
</figure>
<h3>Callout: важный абзац с эмоджи</h3>
<aside class="case-callout" data-callout>
<span class="case-callout__emoji case-callout__emoji--pulse" aria-hidden="true">📌</span>
<div class="case-callout__content">
<p>Это пример акцентного callout-блока. Эмоджи вынесен влево и пульсирует, чтобы визуально усилить важную мысль.</p>
</div>
</aside>
<h3>Видео: карточка с тенью и фиксированными малыми углами</h3>
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
<div class="case-video-shell">
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/template-elements-demo/video-1.webp" data-case-video-player style="display: block; width: 100%; height: auto">
<source src="{{assetPrefix}}assets/template-elements-demo/video-1.webm" type="video/webm" />
<source src="{{assetPrefix}}assets/template-elements-demo/video-1.mp4" type="video/mp4" />
Ваш браузер не поддерживает видео.
</video>
</div>
<figcaption>Пример видео-карточки в стиле кейса.</figcaption>
</figure>
<h2>Результат</h2>
<p class="section__prose">
Шаблон готов для копирования в новый кейс: остаётся заменить рыбу на фактический текст, подставить реальные ссылки и медиа проекта.
</p>
</div>
</main>
{{> projects-section-mp}}{{> projects-section}}
{{> contact-section}}
{{> footer}}
{{> cookie-notice}}
{{> nav-more-floating}}
</body>
</html>