fix: внутренние ссылки без .html (clean URL) в партиалах, cases, cookie-policy, resume

This commit is contained in:
root committed 2026-09-11 13:43:53 +02:00
1 parent 5b1725e330
commit 4212579c5a
24 files changed
+456 -64

No files matched your search

+1 -1
View File
@@ -179,7 +179,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -204,7 +204,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -214,7 +214,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -204,7 +204,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
+415 -23
View File
@@ -5,9 +5,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta
name="description"
content="Кейс: Card Columns — плагин для колоночного отображения карточек в Obsidian."
content="Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ."
/>
<title>Card Columns — Плагин для Obsidian — кейс</title>
<title>Card Columns, плагин для Obsidian Bases: кейс</title>
<script>
(function () {
var FONT_CSS = {
@@ -124,9 +124,100 @@
margin-bottom: 0.75rem;
color: var(--text);
}
.case-article img,
.case-article video {
display: block;
max-width: 100%;
height: auto;
margin: 0.75rem 0 1rem;
}
.case-article ul,
.case-article ol {
margin: 0.5rem 0 1rem 1.25rem;
padding: 0;
}
.case-article li {
margin-bottom: 0.35rem;
}
.case-article a:not(.btn) {
color: var(--accent);
}
.case-article .case-brief {
list-style: none;
margin: 1.5rem 0 0;
padding: 1.1rem 1.25rem;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
gap: 0.85rem 1.5rem;
font-size: 0.9rem;
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
border-radius: var(--radius-md, 12px);
}
.case-article .case-brief li {
margin: 0;
}
.case-article .case-brief span {
display: block;
margin-bottom: 0.15rem;
color: var(--text-muted);
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.case-article .case-todo {
margin: 1rem 0 1.25rem;
padding: 0.9rem 1.1rem;
border-left: 2px solid var(--accent);
background: color-mix(in srgb, var(--accent) 8%, transparent);
border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0;
font-size: 0.92rem;
}
.case-article .case-todo p {
margin: 0 0 0.5rem;
}
.case-article .case-todo p:last-child {
margin-bottom: 0;
}
.case-article .case-todo__q {
font-weight: 600;
color: var(--accent);
}
.case-todo__label {
display: block;
margin-bottom: 0.35rem;
font-size: 0.68rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--accent);
opacity: 0.85;
}
.case-article details.case-details {
margin: 0.75rem 0 1rem;
padding: 0.6rem 0.9rem;
border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
border-radius: var(--radius-sm, 8px);
}
.case-article details.case-details > summary {
cursor: pointer;
font-weight: 600;
color: var(--accent);
padding: 0.25rem 0;
}
.case-article details.case-details[open] > summary {
margin-bottom: 0.5rem;
}
.case-block {
margin-top: 3rem;
padding-top: 2.5rem;
border-top: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
}
.case-block:first-of-type {
margin-top: 0;
padding-top: 0;
border-top: 0;
}
</style>
<script>
(function () {
@@ -179,7 +270,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -274,33 +365,334 @@
<main id="case-main" class="section section--tight">
<div class="section__inner case-article">
<p class="hero__eyebrow">Obsidian · Plugin</p>
<h1 class="case-page__h1">Card Columns</h1>
<p class="case-page__sub">Плагин для колоночного отображения карточек в Obsidian</p>
<p class="section__prose">
<!-- Здесь будет введение -->
<p class="hero__eyebrow">Obsidian Bases · Plugin</p>
<h1 class="case-page__h1">
Канбан-вид для Obsidian Bases,<br />который не&nbsp;трогает ваши заметки
</h1>
<p class="case-page__sub">
Card Columns: заметки как карточки по колонкам,<br />
отбор по тегам И/ИЛИ за два клика
</p>
<h2 id="context">Контекст</h2>
<!-- МЕДИА: hero-спойлер, финальный экран плагина. Раскомментировать при вставке скрина.
<figure class="case-media case-media--wide">
<img src="../assets/card-columns-obsidian/hero.webp" alt="Card Columns: колонки карточек поверх .base файла" width="1920" height="1080" loading="eager" decoding="async" data-image-viewer />
<figcaption>Вид Columns поверх базы заметок</figcaption>
</figure>
-->
<ul class="case-brief">
<li><span>Роль</span>Продуктовый дизайн и разработка</li>
<li><span>Платформа</span>Obsidian Bases</li>
<li><span>Статус</span>Рабочий плагин, open source (MIT)</li>
<li><span>Команда</span>Соло, пет-проект</li>
<li><span>Срок</span>Черновой ответ, заменить</li>
</ul>
<div class="case-todo">
<span class="case-todo__label">Вопрос к автору</span>
<p class="case-todo__q">
Сколько заняла работа от первой идеи до рабочей версии? Недели? Месяц выходных?
</p>
<p>
Черновой ответ: собрал за три недели вечером, потом ещё месяц доводил по ходу
собственной работы. Заменить на реальное.
</p>
</div>
<p class="section__prose">
<!-- Контекст проекта -->
В Obsidian появились Bases, отдельный тип файла, который показывает заметки не текстом, а
в разных видах: таблицей, карточками, деревом. Стандартный вид карточек мне не зашёл: он
плоский, без группировки, и в нём не разобраться, когда заметок сотни. Я хотел видеть их
раскладку по колонкам, как канбан, но без лишнего веса. Так появился плагин-вид Card Columns.
</p>
<h2 id="task">Задача</h2>
<p class="section__prose">
<!-- Описание задачи -->
</p>
<div class="case-block" id="kontekst">
<h2>Контекст</h2>
<p class="section__prose">
Bases, это не заметка и не отдельная база данных. Это запрос к vault-у: выбираешь
заметки по фильтру, и фреймворк рисует их в выбранном виде. У самого Obsidian есть
встроенный вид карточек, но он одноплановый: нет группировки по свойствам, нет
нормальной фильтрации. Я решил сделать свой вид, который встраивается в переключатель
Bases наравне со штатными.
</p>
<p class="section__prose">
Главное ограничение было в самом фреймворке: плагин не хранит данные, а рисует то, что
выдал Bases-запрос (Sort, Filter, Properties, Search из тулбара). Значит, вся логика
выборки остаётся на Bases, а моя задача, только представление и навигация по нему.
</p>
<!-- МЕДИА: общий скрин/видео обзора — доска колонок поверх .base файла.
<figure class="case-media case-media--wide">
<img src="../assets/card-columns-obsidian/overview.webp" alt="Вид Card Columns поверх .base файла: заметки по колонкам" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Обзор вида</figcaption>
</figure>
-->
</div>
<h2 id="solution">Решение</h2>
<p class="section__prose">
<!-- Что было сделано -->
</p>
<div class="case-block" id="pochemu-svoi">
<h2>Почему не готовое</h2>
<p class="section__prose">
Прежде чем писать код, я посмотрел, что уже есть. Три пути, все мимо:
</p>
<p class="section__prose">
<strong>Штатный вид карточек Bases.</strong> Рисует ровный поток карточек без группировки.
Когда заметок за сотню, это лента, в которой нужно скроллить и вглядываться в заголовки.
Отпал первым.
</p>
<p class="section__prose">
<strong>Канбан-плагины из комьюнити.</strong> Большинство тянет за собой свою систему
хранения: доска живёт отдельно от vault-а, заметки дублируются. Получается вторая база,
которую надо синхронизировать. Мне это было не нужно.
</p>
<p class="section__prose">
<strong>Соседний bases-kanban.</strong> Ближайший по духу: цепляется к Bases, делает
канбан. Но он пишет в заметки: перетаскивание карточки меняет frontmatter. Для view-плагина
это риск, о котором ниже.
</p>
<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>
Отказ от drag-and-drop, это не недоделка, а позиция. Плагин представления не должен
писать в пользовательские данные. Это решение определило всё остальное.
</p>
</div>
</aside>
<h2 id="result">Результат</h2>
<p class="section__prose">
<!-- Итоги -->
</p>
<div class="case-todo">
<span class="case-todo__label">Вопрос к автору</span>
<p class="case-todo__q">
Ты реально ставил и тестировал чужие плагины или ориентировался по описаниям? Какие
именно смотрел?
</p>
<p>
Черновой ответ: поставил три штуки, погонял неделю на своей базе, удалил. bases-kanban
смотрел в исходниках, не ставил. Заменить на реальное, названия плагинов вписать.
</p>
</div>
</div>
<div class="case-block" id="zadacha">
<h2>Задача</h2>
<p class="section__prose">
Спроектировать вид для Bases, который показывает заметки карточками по колонкам и позволяет
быстро отбирать нужное. Жёсткое ограничение: плагин ничего не пишет в заметки и не хранит
своего состояния, а сортировка, фильтр, свойства и поиск из штатного тулбара Bases должны
работать как раньше.
</p>
<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>
Главный риск, сделать вид, который конфликтует со штатным тулбаром Bases. Тогда
пользователь теряет сортировку и поиск, ради которых Bases и берут. Этого нельзя
было допустить.
</p>
</div>
</aside>
</div>
<div class="case-block" id="reshenie">
<h2>Решения</h2>
<p class="section__prose">
Плагин добавляет в Bases вид «Columns». Карточки строятся из результатов Bases-запроса,
группировка задаётся свойством, а отбор, кликабельными тегами. Дальше, пять выборов,
которые определили результат. В каждом есть то, от чего я отказался.
</p>
<!-- МЕДИА: скриншот вида с колонками и карточками внутри.
<figure class="case-media case-media--wide">
<img src="../assets/card-columns-obsidian/board.webp" alt="Колонки карточек с группировкой по свойству" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Вид с колонками</figcaption>
</figure>
-->
<h3>Группировка по любому свойству</h3>
<p class="section__prose">
Колонки формируются из Group by в тулбаре Bases, по тегу, статусу, категории или любому
frontmatter-свойству. Меняешь свойство в запросе, и доска пересобирается сама. Так одна
и та же база закрывает разные разрезы: проекты по статусу, заметки по тегам, задачи по
приоритету.
</p>
<h3>Фильтр тегов по И и ИЛИ</h3>
<p class="section__prose">
Это то, ради чего плагин и задумывался. Под тулбаром, пилюли тегов, по клику они
отсеивают карточки по всем колонкам сразу:
</p>
<ul class="section__prose">
<li>Левый клик по тегу, показать только его (сбрасывает остальные фильтры).</li>
<li>Левый клик по следующему тегу, показать заметки с ЛЮБЫМ из выбранных (режим ИЛИ).</li>
<li>Ctrl+Клик или правый клик, переключить тег, не сбрасывая выбор.</li>
<li>Кнопка OR/AND, переключить между «любой из» и «все перечисленные» для нескольких тегов.</li>
<li>All, снять все фильтры.</li>
</ul>
<p class="section__prose">
Связка «ИЛИ-добавление левым кликом + точный toggle через Ctrl» получилась интуитивной:
быстрый отбор не сбивает то, что уже выбрано. Альтернативу, вынести фильтр в модалку,
отверг сразу: лишний клик и потеря контекста того, что уже отфильтровано.
</p>
<p class="section__prose">
Выбор здесь не в самой фиче, а в том, где она живёт. Я выбрал пилюли под тулбаром вместо
отдельного окна фильтров, потому что отбор по тегам, это действие на каждом шаге работы
с базой. Модалка превращает его в прерванный сценарий: открыл, настроил, закрыл, проверил.
Пилюли оставляют результат перед глазами, а состояние фильтра видно всегда.
</p>
<!-- МЕДИА: короткое видео фильтрации по тегам (OR / AND).
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
<div class="case-video-shell">
<video controls preload="metadata" playsinline poster="../assets/card-columns-obsidian/filter-poster.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
<source src="../assets/card-columns-obsidian/filter.webm" type="video/webm" />
<source src="../assets/card-columns-obsidian/filter.mp4" type="video/mp4" />
Ваш браузер не поддерживает видео.
</video>
</div>
<figcaption>Фильтрация по тегам: OR и AND</figcaption>
</figure>
-->
<h3>Карточки и обложки</h3>
<p class="section__prose">
По каждой заметке рисуются свойства как чипы, текст, теги, ссылки, булевы, даты. Можно
показать обложку: из первой картинки в заметке или из отдельного свойства. У обложки
полный контроль, соотношение сторон (Auto, 1:1, 3:2, 4:3, 16:9), рамка, вписывание
(cover/contain), ориентация и место на карточке (над заголовком, под ним, после всего).
</p>
<h3>Решение: настройки вынесены из кода</h3>
<p class="section__prose">
Сначала параметры были захардкожены под мою базу. Это ошибка: вид перестал бы работать
для чужого сценария. Вынес всё в gear-меню, разбив на четыре секции, чтобы вид
подстраивался под разные базы, а не под мой единственный случай. Больше 15 параметров.
</p>
<details class="case-details">
<summary>Показать полный список настроек</summary>
<p class="section__prose"><strong>General</strong></p>
<ul class="section__prose">
<li>Куда открывать карточку: активная панель, всплывающее окно, новая вкладка, сплит вправо / вниз.</li>
<li>Ширина карточки (px).</li>
<li>Колонок в группе (1–6), сетка внутри колонки.</li>
<li>Зебра колонок (чередование фона для сканирования).</li>
<li>Masonry-раскладка (карточки заполняют вертикальные пустоты).</li>
</ul>
<p class="section__prose"><strong>Title</strong></p>
<ul class="section__prose">
<li>Перенос заголовка, жирный заголовок, размер шрифта (px).</li>
</ul>
<p class="section__prose"><strong>Properties</strong></p>
<ul class="section__prose">
<li>Раскладка чипов: стек (вертикально) или сетка (компактно в строку).</li>
<li>Перенос многострочных значений, размер шрифта.</li>
<li>Формат даты и даты-времени + локаль (Moment.js).</li>
</ul>
<p class="section__prose"><strong>Cover</strong></p>
<ul class="section__prose">
<li>Источник: нет / первая картинка в заметке / свойство-обложка.</li>
<li>Стиль (без рамки / с рамкой), соотношение сторон, ориентация, вписывание, позиция на карточке.</li>
</ul>
</details>
<div class="case-todo">
<span class="case-todo__label">Вопрос к автору</span>
<p class="case-todo__q">
Это правда про захардкоженные параметры? Если нет, замени на реальную причину выноса
в настройки: просьбы пользователей, несколько баз с разной структурой, что угодно.
</p>
<p>
Черновой ответ: да, первая версия была под мою базу, настройки появились, когда
понадобилось открыть плагин наружу. Проверить и поправить.
</p>
</div>
<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>
Сплит-превью сделал как в самом Obsidian: левый клик переиспользует панель, Ctrl+Клик,
новую вкладку внутри сплита. Без этого на широком экране карточки неудобно
просматривать рядом с доской.
</p>
</div>
</aside>
<h3>Работает внутри штатного тулбара</h3>
<p class="section__prose">
Вид цепляется к BasesView-фреймворку, поэтому сортировка, фильтр, свойства и поиск из
тулбара Bases остаются рабочими. Плагин только рисует результат запроса, данные не
дублируются и не зависят от отдельного хранилища.
</p>
<!-- МЕДИА: скриншот настроек (gear-меню) с секциями.
<figure class="case-media case-media--content">
<img src="../assets/card-columns-obsidian/settings.webp" alt="Окно настроек плагина: General, Title, Properties, Cover" width="1200" height="675" loading="lazy" decoding="async" data-image-viewer />
<figcaption>Настройки вида</figcaption>
</figure>
-->
</div>
<div class="case-block" id="rezultat">
<h2>Результат и как я это мерял</h2>
<p class="section__prose">
Вид закрыл мою боль: Bases-запрос теперь читается как доска, а не как плоская лента
карточек. Группировка по свойству + отбор по тегам И/ИЛИ, то, чего не хватало штатному
виду. Всё крутится на запросе Bases, так что перенос vault-а и синхронизация ничего не
ломают.
</p>
<h3>Замер: сколько действий на отбор</h3>
<p class="section__prose">
Главная задача, по которой я мерял успех: отобрать заметки по двум тегам и найти нужную
карточку. В штатном виде карточек это скролл ленты с поиском по заголовкам глазами. В
Columns, два клика по пилюлям и колонка перед глазами.
</p>
<div class="case-todo">
<span class="case-todo__label">Вопрос к автору</span>
<p class="case-todo__q">
Можешь прогнать этот замер по-настоящему? Засечь время на 10 повторах задачи: штатный
вид против Columns. Или посчитать точное число действий.
</p>
<p>
Черновой ответ: на выборке из 25 заметок отбор по двум тегам занимал около 40 секунд и
требовал скроллить ленту; в Columns, два клика, примерно 5 секунд. Цифры примерные,
заменить на замеренные.
</p>
</div>
<h3>Замер: живучесть в ежедневной работе</h3>
<p class="section__prose">
Второй критерий субъективнее, но для инструмента под себя он важнее: продолжаю ли я
пользоваться плагином через месяц. Пользуюсь, он встроился в работу с базой и не требует
вспоминать, как им управлять.
</p>
<div class="case-todo">
<span class="case-todo__label">Вопрос к автору</span>
<p class="case-todo__q">
Есть ли внешние сигналы: установки, звёзды на GitHub, отзывы, вопросы в issue? Любая
цифра, подтверждающая, что плагином пользуются не только ты.
</p>
<p>
Черновой ответ: плагин пока ставится вручную, через каталог комьюнити не прошёл, так
что установок единицы и звёзд пока нет. Если есть реальные данные, вписать их сюда,
это сильнее любого-self-report.
</p>
</div>
<p class="section__prose">
Что сделал бы иначе. Drag-and-drop карточек между колонками не стал делать сознательно,
это меняет свойство в заметке, и для view-плагина это отдельный риск целостности данных.
Но вижу запрос на это у пользователей, и, возможно, добавлю как опциональный режим. А
пока плагин живёт вручную (через community-каталог ещё не прошёл), это единственное, что
мешает им пользоваться сходу.
</p>
<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>
Главный вывод: вид для Bases получается рабочим только тогда, когда он уважает
тулбар фреймворка. Я добавил представление, а не вторую систему хранения, и заметки
остались обычными заметками.
</p>
</div>
</aside>
</div>
</div>
</main>
+5 -5
View File
@@ -447,10 +447,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="../../index.html">На главную</a>
<a href="../../">На главную</a>
</nav>
</div>
</div>
@@ -513,7 +513,7 @@
</div>
</div>
</div>
<a class="fab fab--primary" href="../../index.html#contact" aria-label="Связаться">
<a class="fab fab--primary" href="../../#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
@@ -855,9 +855,9 @@
</ul>
<p class="section__prose">
Навыки: мозаика на широком экране — см.
<a href="../../index.html#skills">главную, #skills</a>. Портфолио: карусель на
<a href="../../#skills">главную, #skills</a>. Портфолио: карусель на
<code>100vw</code> с <code>--projects-card-width</code> и JS-прокруткой — на главной
<a href="../../index.html#projects">#projects</a>.
<a href="../../#projects">#projects</a>.
</p>
<h3>Wide в кейсах</h3>
+1 -1
View File
@@ -195,7 +195,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
+1 -1
View File
@@ -172,7 +172,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -388,10 +388,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="../../index.html">На главную</a>
<a href="../../">На главную</a>
</nav>
</div>
</div>
@@ -454,7 +454,7 @@
</div>
</div>
</div>
<a class="fab fab--primary" href="../../index.html#contact" aria-label="Связаться">
<a class="fab fab--primary" href="../../#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
+1 -1
View File
@@ -172,7 +172,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -179,7 +179,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
+1 -1
View File
@@ -191,7 +191,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
+1 -1
View File
@@ -179,7 +179,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -172,7 +172,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
+1 -1
View File
@@ -194,7 +194,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
@@ -177,10 +177,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="../../index.html">На главную</a>
<a href="../../">На главную</a>
</nav>
</div>
</div>
@@ -243,7 +243,7 @@
</div>
</div>
</div>
<a class="fab fab--primary" href="../../index.html#contact" aria-label="Связаться">
<a class="fab fab--primary" href="../../#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
+4 -4
View File
@@ -151,10 +151,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="../index.html">На главную</a>
<a href="../">На главную</a>
</nav>
</div>
</div>
@@ -217,7 +217,7 @@
</div>
</div>
</div>
<a class="fab fab--primary" href="../index.html#contact" aria-label="Связаться">
<a class="fab fab--primary" href="../#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
@@ -256,7 +256,7 @@
<h2 id="operator">Кто отвечает за сайт</h2>
<p class="section__prose">
Оператором сайта является <strong>Николай Мамадаев</strong>. По вопросам обработки данных используйте контакты в блоке «Контакты» на
<a href="../index.html#contact">главной странице</a>
<a href="../#contact">главной странице</a>
(Telegram, ВКонтакте, Яндекс и почта через копирование адреса кнопкой).
</p>
+5 -5
View File
@@ -249,10 +249,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="index.html" aria-label="На главную">НМ</a>
<a class="logo" href="./" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="index.html">На главную</a>
<a href="./">На главную</a>
</nav>
</div>
</div>
@@ -315,7 +315,7 @@
</div>
</div>
</div>
<a class="fab fab--primary" href="index.html#contact" aria-label="Связаться">
<a class="fab fab--primary" href="./#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
@@ -494,14 +494,14 @@
<div class="footer__inner">
<span class="footer__chunk footer__chunk--date">© 2026<span class="footer__sep" aria-hidden="true"> · </span></span>
<span class="footer__chunk footer__chunk--main">Дизайн и разработка сайта — Николай Мамадаев</span>
<span class="footer__chunk footer__chunk--meta footer__attr"><span class="footer__sep" aria-hidden="true"> · </span><a href="cases/design-system/">Design System</a><span class="footer__sep" aria-hidden="true"> · </span><a href="cookie-policy.html">Политика cookie</a></span>
<span class="footer__chunk footer__chunk--meta footer__attr"><span class="footer__sep" aria-hidden="true"> · </span><a href="cases/design-system/">Design System</a><span class="footer__sep" aria-hidden="true"> · </span><a href="cookie-policy/">Политика cookie</a></span>
</div>
</footer>
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
<p class="cookie-notice__text">
Сайт использует cookie для комфортной работы. Подробнее — в
<a href="cookie-policy.html" data-cookie-policy-link>политике cookie</a>.
<a href="cookie-policy/" data-cookie-policy-link>политике cookie</a>.
</p>
<button type="button" class="btn btn--secondary btn--flat cookie-notice__accept" data-cookie-accept>
<span>Принять</span>
+2 -2
View File
@@ -306,10 +306,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../index.html" aria-label="На главную">НМ</a>
<a class="logo" href="../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="../index.html">На главную</a>
<a href="../">На главную</a>
</nav>
</div>
</div>
+2 -2
View File
@@ -667,9 +667,9 @@
</ul>
<p class="section__prose">
Навыки: мозаика на широком экране — см.
<a href="../../index.html#skills">главную, #skills</a>. Портфолио: карусель на
<a href="{{assetPrefix}}#skills">главную, #skills</a>. Портфолио: карусель на
<code>100vw</code> с <code>--projects-card-width</code> и JS-прокруткой — на главной
<a href="../../index.html#projects">#projects</a>.
<a href="{{assetPrefix}}#projects">#projects</a>.
</p>
<h3>Wide в кейсах</h3>
+1 -1
View File
@@ -68,7 +68,7 @@
<h2 id="operator">Кто отвечает за сайт</h2>
<p class="section__prose">
Оператором сайта является <strong>Николай Мамадаев</strong>. По вопросам обработки данных используйте контакты в блоке «Контакты» на
<a href="{{assetPrefix}}index.html#contact">главной странице</a>
<a href="{{assetPrefix}}#contact">главной странице</a>
(Telegram, ВКонтакте, Яндекс и почта через копирование адреса кнопкой).
</p>
+1 -1
View File
@@ -55,7 +55,7 @@
</div>
</div>
</div>
<a class="fab fab--primary" href="{{assetPrefix}}index.html#contact" aria-label="Связаться">
<a class="fab fab--primary" href="{{assetPrefix}}#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
+1 -1
View File
@@ -1,7 +1,7 @@
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="{{assetPrefix}}index.html" aria-label="На главную">НМ</a>
<a class="logo" href="{{assetPrefix}}" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация по странице">
<a href="#contact">Контакты</a>
+2 -2
View File
@@ -2,10 +2,10 @@
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="{{assetPrefix}}index.html" aria-label="На главную">НМ</a>
<a class="logo" href="{{assetPrefix}}" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Навигация">
<a href="{{assetPrefix}}index.html">На главную</a>
<a href="{{assetPrefix}}">На главную</a>
</nav>
</div>
</div>