Files
site-portfolio/public/cases/orc-automation-panel/index.html
T
root daa623fe73 feat(mesh-bg): fade-in шейдера фона + modulepreload графа
- canvas стартует с opacity:0 и плавно проявляется (0.9s) при .is-ready
- initPageMeshShader ставит is-ready после первого кадра
- modulepreload page-mesh-shader.js для параллельной загрузки с main.js
- пересборка страниц (build:pages)
2026-09-24 21:37:40 +02:00

1032 lines
66 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="Кейс: редизайн веб-панели оркестратора Primo RPA — кураторство дизайна, внедрение Ant Design и Storybook, синхронизация токенов с Figma."
/>
<title>Веб-панель для оркестрации автоматизаций — кейс</title>
<script>
(function () {
var FONT_CSS = {
merriweather: "/assets/fonts/merriweather.css",
geologica: "/assets/fonts/geologica.css",
mono: "/assets/fonts/mono.css",
};
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 hVal = h !== null ? h : 210;
var sVal = s !== null ? s : 90;
var lVal = l !== null ? Math.min(70, Math.max(20, Number(l))) : 40;
var H = (((hVal % 360) + 360) % 360) / 360;
var S = Math.min(100, Math.max(0, sVal)) / 100;
var Lv = Math.min(100, Math.max(0, lVal)) / 100;
var r, g, b;
if (S === 0) { r = g = b = Lv; }
else {
var q = Lv < 0.5 ? Lv * (1 + S) : Lv + S - Lv * S;
var p = 2 * Lv - q;
var hue2rgb = function(p, q, t) {
if (t < 0) t += 1; if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
r = hue2rgb(p, q, H + 1/3);
g = hue2rgb(p, q, H);
b = hue2rgb(p, q, H - 1/3);
}
var lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
d.style.setProperty("--on-accent", lum > 0.58 ? "hsl(220 14% 12%)" : "hsl(0 0% 98%)");
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") f = "merriweather";
d.dataset.font = f;
var mb = t.meshBg;
if (mb === "off") {
d.dataset.meshBg = "off";
} else {
d.dataset.meshBg = "on";
}
var href = FONT_CSS[f];
if (href && !document.querySelector('link[data-theme-font="' + f + '"]')) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = href;
link.setAttribute("data-theme-font", f);
document.head.appendChild(link);
}
} catch (e) {}
})();
</script>
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon.png" />
<link rel="manifest" href="/assets/favicon/site.webmanifest" />
<link rel="preload" href="/assets/fonts/merriweather.css" as="style" />
<link rel="preload" href="/css/main.css" as="style" />
<link rel="preload" href="/js/skill-connectors.js" as="script" />
<link rel="modulepreload" href="/js/main.js" />
<link rel="modulepreload" href="/js/modules/ui/page-mesh-shader.js" />
<link rel="stylesheet" href="/css/main.css" />
<link rel="canonical" href="https://mamadaevv.site/cases/orc-automation-panel/" />
<link rel="alternate" hreflang="ru" href="https://mamadaevv.site/cases/orc-automation-panel/" />
<link rel="alternate" hreflang="en" href="https://mamadaevv.site/en/cases/orc-automation-panel/" />
<link rel="alternate" hreflang="x-default" href="https://mamadaevv.site/cases/orc-automation-panel/" />
<meta name="author" content="Николай Мамадаев" />
<meta name="robots" content="index, follow" />
<meta name="theme-color" content="#0f1115" />
<!-- Open Graph -->
<meta property="og:type" content="article" />
<meta property="og:site_name" content="Николай Мамадаев — продуктовый дизайнер" />
<meta property="og:locale" content="ru_RU" />
<meta property="og:locale:alternate" content="en_US" />
<meta property="og:title" content="Веб-панель для оркестрации автоматизаций — кейс" />
<meta property="og:description" content="Кейс: редизайн веб-панели оркестратора Primo RPA — кураторство дизайна, внедрение Ant Design и Storybook, синхронизация токенов с Figma." />
<meta property="og:url" content="https://mamadaevv.site/cases/orc-automation-panel/" />
<meta property="og:image" content="https://mamadaevv.site/assets/og/og-default.png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="Веб-панель для оркестрации автоматизаций — кейс" />
<!-- Twitter / X -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Веб-панель для оркестрации автоматизаций — кейс" />
<meta name="twitter:description" content="Кейс: редизайн веб-панели оркестратора Primo RPA — кураторство дизайна, внедрение Ant Design и Storybook, синхронизация токенов с Figma." />
<meta name="twitter:image" content="https://mamadaevv.site/assets/og/og-default.png" />
<meta name="twitter:image:alt" content="Веб-панель для оркестрации автоматизаций — кейс" />
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://mamadaevv.site/#person",
"name": "Николай Мамадаев",
"url": "https://mamadaevv.site",
"jobTitle": "Продуктовый дизайнер",
"description": "Продуктовый дизайнер с опытом более 10 лет. Проектирую цифровые продукты, интерфейсы и дизайн-системы.",
"knowsAbout": [
"UX/UI-дизайн",
"продуктовый дизайн",
"дизайн-системы",
"прототипирование",
"Figma",
"no-code"
],
"sameAs": [
"https://t.me/mamadaevv",
"https://vk.com/mamadaevv",
"https://github.com/mamadaevv"
]
},
{
"@type": "WebSite",
"@id": "https://mamadaevv.site/#website",
"url": "https://mamadaevv.site/",
"name": "Николай Мамадаев — продуктовый дизайнер",
"inLanguage": "ru",
"author": {
"@id": "https://mamadaevv.site/#person"
},
"publisher": {
"@id": "https://mamadaevv.site/#person"
}
},
{
"@type": "CreativeWork",
"@id": "https://mamadaevv.site/cases/orc-automation-panel/#page",
"url": "https://mamadaevv.site/cases/orc-automation-panel/",
"name": "Веб-панель для оркестрации автоматизаций — кейс",
"description": "Кейс: редизайн веб-панели оркестратора Primo RPA — кураторство дизайна, внедрение Ant Design и Storybook, синхронизация токенов с Figma.",
"isPartOf": {
"@id": "https://mamadaevv.site/#website"
},
"author": {
"@id": "https://mamadaevv.site/#person"
},
"inLanguage": "ru",
"creator": {
"@id": "https://mamadaevv.site/#person"
},
"datePublished": "2026-09-24",
"about": "UX/UI-дизайн и проектирование интерфейсов"
},
{
"@type": "BreadcrumbList",
"@id": "https://mamadaevv.site/cases/orc-automation-panel/#breadcrumbs",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Николай Мамадаев — продуктовый дизайнер",
"item": "https://mamadaevv.site/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Кейсы",
"item": "https://mamadaevv.site/cases/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Веб-панель для оркестрации автоматизаций — кейс",
"item": "https://mamadaevv.site/cases/orc-automation-panel/"
}
]
}
]
}
</script>
<script src="/js/skill-connectors.js" defer></script>
<script type="module" src="/js/main.js"></script>
<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);
margin: 1.25rem 0 0.5rem;
}
.case-article .section__prose {
margin-bottom: 0.75rem;
color: var(--text);
}
.case-article img {
display: block;
max-width: 100%;
height: auto;
margin: 0.75rem 0 1rem;
}
.case-article ul {
margin: 0.5rem 0 1rem 1.25rem;
padding: 0;
}
.case-article li {
margin-bottom: 0.35rem;
}
.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 data-current-case="orc-automation-panel">
<svg class="liquid-glass-defs" aria-hidden="true" width="0" height="0" focusable="false" style="position:absolute;width:0;height:0;overflow:hidden;pointer-events:none">
<filter id="liquid-glass-displacement" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
<feImage href="../../assets/liquid-glass/displacement.png" xlink:href="../../assets/liquid-glass/displacement.png" preserveAspectRatio="none" result="lgMap"/>
<feDisplacementMap in="SourceGraphic" in2="lgMap" scale="14" xChannelSelector="R" yChannelSelector="G"/>
</filter>
<filter id="liquid-glass-displacement-btn" x="-20%" y="-20%" width="140%" height="140%" color-interpolation-filters="sRGB">
<feImage href="../../assets/liquid-glass/displacement.png" xlink:href="../../assets/liquid-glass/displacement.png" preserveAspectRatio="none" result="lgMapBtn"/>
<feDisplacementMap in="SourceGraphic" in2="lgMapBtn" scale="6" xChannelSelector="R" yChannelSelector="G"/>
</filter>
</svg>
<a class="skip-link" href="#case-main">К содержимому кейса</a>
<header class="header" data-theme-picker>
<div class="header__inner">
<a class="logo" href="../../" aria-label="На главную">НМ</a>
<div class="header__cluster">
<nav class="nav" aria-label="Разделы страницы">
<a href="#contact">Контакты</a>
</nav>
</div>
</div>
</header>
<div class="fab-stack" aria-label="Быстрые действия">
<div class="theme-panel-fab-wrap">
<button type="button" class="fab fab--secondary glass-neutral" data-theme-panel-btn aria-expanded="false" aria-controls="theme-panel" aria-label="Настройки стиля">
<span class="theme-panel-fab__icon theme-panel-fab__icon--open-hide" aria-hidden="true"></span>
<svg class="theme-panel-fab__icon theme-panel-fab__icon--close" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M6 6L18 18M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" />
</svg>
</button>
<div id="theme-panel" class="theme-picker__panel glass-neutral" role="dialog" aria-label="Тема и оформление" hidden data-theme-panel>
<div class="theme-picker__stack">
<section class="theme-picker__section" aria-labelledby="theme-accent-title">
<h3 id="theme-accent-title" class="theme-picker__section-title">Акцентный цвет</h3>
<div class="colorpicker" data-colorpicker>
<div class="colorpicker__plane-box">
<canvas class="colorpicker__plane" width="320" height="180" data-sl-canvas aria-label="Насыщенность и светлость акцента"></canvas>
<div class="colorpicker__knob" data-sl-knob></div>
</div>
<div class="colorpicker__hue-wrap">
<label class="colorpicker__hue-sr" for="theme-hue-slider">Оттенок акцента</label>
<input id="theme-hue-slider" class="colorpicker__hue" type="range" min="0" max="360" value="210" data-hue-slider aria-valuemin="0" aria-valuemax="360" />
</div>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-mode-title">
<h3 id="theme-mode-title" class="theme-picker__section-title">Тема</h3>
<div class="radius-seg theme-mode-seg" role="radiogroup" aria-labelledby="theme-mode-title">
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="system" aria-label="Как в системе"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--system"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="light" aria-label="Светлая тема"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--light"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-theme-mode="dark" aria-label="Тёмная тема"><span class="radius-seg__viz" aria-hidden="true"><span class="theme-mode-seg__ico theme-mode-seg__ico--dark"></span></span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-radius-title">
<h3 id="theme-radius-title" class="theme-picker__section-title">Скругление углов</h3>
<div class="radius-seg" role="radiogroup" aria-labelledby="theme-radius-title">
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="soft" aria-label="Слабое скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--soft"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="medium" aria-label="Среднее скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--medium"></span></span></button>
<button type="button" class="radius-seg__btn" role="radio" aria-checked="false" data-radius-option="strong" aria-label="Сильное скругление"><span class="radius-seg__viz" aria-hidden="true"><span class="radius-seg__arc radius-seg__arc--strong"></span></span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-typography-title">
<h3 id="theme-typography-title" class="theme-picker__section-title">Типографика</h3>
<div class="radius-seg" role="radiogroup" aria-labelledby="theme-typography-title">
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="geologica" aria-label="Sans"><span class="theme-font-seg__label">Sans</span></button>
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="merriweather" aria-label="Sans Serif"><span class="theme-font-seg__label">Sans Serif</span></button>
<button type="button" class="radius-seg__btn theme-font-seg__btn" role="radio" aria-checked="false" data-font-option="mono" aria-label="Mono"><span class="theme-font-seg__label">Mono</span></button>
</div>
</section>
<section class="theme-picker__section" aria-labelledby="theme-mesh-bg-title">
<h3 id="theme-mesh-bg-title" class="theme-picker__section-title">Фон страницы</h3>
<div class="radius-seg radius-seg--two" role="radiogroup" aria-labelledby="theme-mesh-bg-title">
<button type="button" class="radius-seg__btn theme-mesh-bg-seg__btn" role="radio" aria-checked="false" data-mesh-bg-option="on" aria-label="Показать фоновый градиент"><span class="theme-mesh-bg-seg__label">Вкл</span></button>
<button type="button" class="radius-seg__btn theme-mesh-bg-seg__btn" role="radio" aria-checked="false" data-mesh-bg-option="off" aria-label="Скрыть фоновый градиент"><span class="theme-mesh-bg-seg__label">Выкл</span></button>
</div>
</section>
</div>
</div>
</div>
<a class="fab fab--primary" href="#contact" aria-label="Связаться">
<span class="fab-primary__ico" aria-hidden="true"></span>
</a>
</div>
<div class="content-edit-fab-stack" aria-label="Правки контента" data-content-edit-ui>
<button
type="button"
class="fab fab--secondary glass-neutral content-edit-fab"
data-content-edit-mode-toggle
hidden
aria-pressed="false"
aria-label="Режим правок контента"
title="Режим правок"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path
d="M4 20h4l10.5-10.5a2.12 2.12 0 0 0 0-3L16.5 4.5a2.12 2.12 0 0 0-3 0L3 15v5z"
stroke="currentColor"
stroke-width="1.75"
stroke-linejoin="round"
/>
</svg>
<span class="content-edit-fab__badge" hidden aria-hidden="true">0</span>
</button>
</div>
<main id="case-main" class="section section--tight">
<div class="section__inner case-article">
<p class="hero__eyebrow">Primo RPA · UX/UI · Web App</p>
<h1 class="case-page__h1">Веб-панель для оркестрации автоматизаций</h1>
<p class="case-page__sub">
Оркестратор Primo RPA: запуск роботов, проекты и контроль процессов в веб-кабинете для админов и разработчиков автоматизаций.
</p>
<div class="case-block" id="obzor">
<h2>Контекст</h2>
<p class="section__prose">
В стеке Primo RPA оркестратор отвечает за расписание, очередь и статусы RPA-роботов на инфраструктуре клиента. С ним работают не только из студии разработки, но и из браузера: смотрят проекты, перезапускают задания, разбирают сбои.
</p>
<p class="section__prose">
К тому моменту продукт уже был в эксплуатации, но интерфейс заметно устарел: пользователи сталкивались с неудобствами в навигации, визуальным шумом в таблицах и неочевидными сценариями в некоторых разделах. Задача стояла освежить вид интерфейса, сделать его современным и исправить накопившиеся UX-проблемы.
</p>
</div>
<div class="case-block" id="rol">
<h2>Роль и подход</h2>
<p class="section__prose">
Моя роль в этом проекте была скорее кураторской — я не делал дизайн самостоятельно, а выстраивал процесс так, чтобы команда дизайна и разработки работала слаженно.
</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>Я изучил продукт «с нуля»: разобрался с интерфейсом оркестратора, нашёл болевые точки пользователей и сформулировал задачи для обновления.</p>
</div>
</aside>
<p class="section__prose">
Параллельно я искал дизайнера, который взял бы на себя основную визуальную работу. Отбор прошла Елизавета — среди более чем 150 заявок она лучше всего подходила под предстоящий фронт работ.
</p>
<p class="section__prose">
В течение трёх месяцев я погружал новую сотрудницу в детали проекта: ставил задачи, давал обратную связь по создаваемым макетам, делился контекстом по пользовательским сценариям. Вместе с командой разработки мы планировали порядок обновления дизайна сервиса — меняли экраны по приоритету, вкладывая изменения в текущие релизы, без «остановить всё и перерисовать».
</p>
</div>
<div class="case-block" id="tekhnicheskiy-stek">
<h2>Технический стек и инструменты</h2>
<p class="section__prose">
В качестве фреймворка для интерфейса был выбран <a href="https://ant.design/" target="_blank" rel="noopener noreferrer">Ant Design</a> последней версии. Он уже использовался в проекте, и его свежий релиз предлагал <a href="https://ant.design/theme-editor" target="_blank" rel="noopener noreferrer">Theme Editor</a> — возможность настраивать внешний вид компонентов через дизайн-токены без переопределения стилей вручную. Это давало и дизайнерам, и разработчикам единый язык описания интерфейса.
</p>
<p class="section__prose">
Единым источником правды и мостом между дизайном и разработкой стал <a href="https://storybook.js.org/" target="_blank" rel="noopener noreferrer">Storybook</a>. В нём компоненты были не просто задокументированы, а реально работали в изолированной среде — это позволяло дизайнерам видеть реализацию элементов вживую, а разработчикам — быстрее интегрировать компоненты в панель.
</p>
</div>
<div class="case-block" id="dizayn-sistema">
<h2>Дизайн-система и синхронизация</h2>
<p class="section__prose">
Для удобства работы мы синхронизировали токены из Ant Design с токенами в Figma — цвета, отступы, типографика и радиусы скругления были приведены к единым значениям. Работало это так: если в Figma токены обновлялись, их можно было выгрузить в JSON и без проблем сразу загрузить в код — вместо того, чтобы разработчик вручную искал изменения и правил каждый токен индивидуально. Такой подход также позволил смотреть на дизайн более системно.
</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>Основная задача, которую решал подход такого тесного сотрудничества дизайна и разработки, — максимально точно перенести задуманное в прод и не растерять по пути мелочей.</p>
</div>
</aside>
<p class="section__prose">
Компоненты в Figma создавались с нуля — по референсам Ant Design, но без использования готовых библиотек. Отказ от готовых решений был осознанным: нам нужна была полная настройка под наш стиль работы и возможность использовать новые функции Figma, которые не поддерживались в библиотеках из сообщества Figma.
</p>
<p class="section__prose">
Для Storybook мы отобрали и настроили плагины, которые были уместны для наших задач — контроль доступности, просмотр состояний компонентов, переключение тем и локалей. Это сделало Storybook не просто витриной компонентов, а полноценным инструментом дизайн-ревью.
</p>
</div>
<div class="case-block" id="rabochaya-sreda">
<h2>Рабочая среда дизайнера</h2>
<p class="section__prose">
Мы настроили среду так, чтобы дизайнер мог видеть реализацию компонентов вживую у себя на компьютере, используя локальный Storybook и Git. Это позволяло точнее контролировать, как задуманный дизайн воплощается в коде, и оперативно замечать расхождения на ранних этапах.
</p>
<p class="section__prose">
Обсуждался также шаг ускорить поддержку Storybook тем, чтобы дизайнер сам мог описывать JSX для реализованного компонента — это сокращало путь от макета до документированного компонента в сторибуке.
</p>
<p class="section__prose">
Мы отладили рабочий процесс по передаче иконок в библиотеку. Особенность заключалась в том, чтобы иконки можно было отобразить в Storybook с фильтрацией и сортировкой. При этом дизайнер мог обновлять иконки без привлечения разработчика — просто пушил новые файлы в репозиторий.
</p>
<p class="section__prose">
Увидеть обновлённую иконку сразу в браузере позволяло лучше её оптимизировать и убрать косяки отображения при использовании булевых операций.
</p>
<p class="section__prose">
Для Figma также был разработан подход и правила, которые не только ограничивали дизайнера, но и позволяли гарантированно делать консистентные и рабочие иконки.
</p>
</div>
<div class="case-block" id="ux-uluchsheniya">
<h2>UX-улучшения</h2>
<p class="section__prose">
За время обновления интерфейса Елизавета предложила ещё и ряд улучшений пользовательского опыта. Часть из них была успешно внедрена — например, более понятная группировка элементов в сложных формах и переработанные состояния загрузки. Но в приоритете было не ломать старый UX, к которому привыкли пользователи, поэтому многие идеи сохранились в бэклог для следующей итерации.
</p>
</div>
<div class="case-block" id="proekty">
<h2>Список проектов</h2>
<p class="section__prose">
Таблица проектов — один из самых частых экранов. На старой версии много колонок, плотная сетка и мелкий текст: статус и имя проекта читаются с трудом, особенно на ноутбуке.
</p>
<p class="section__prose">В новой версии:</p>
<ul>
<li>колонки свели к тому, что нужно для ежедневной работы;</li>
<li>статусы и действия вынесли в предсказуемые зоны строки;</li>
<li>отступы и типографику подтянули под остальную панель на Ant Design.</li>
</ul>
<h3>Было</h3>
<figure class="case-media case-media--wide">
<img
src="../../assets/orc-primo-rpa/projects--table-old.webp"
alt="Список проектов в оркестраторе — предыдущая версия таблицы"
width="1919"
height="867"
loading="lazy"
decoding="async"
data-image-viewer
/>
</figure>
<h3>Стало</h3>
<figure class="case-media case-media--wide">
<img
src="../../assets/orc-primo-rpa/projects--table-new.webp"
alt="Список проектов в оркестраторе — обновлённая таблица"
width="1366"
height="768"
loading="lazy"
decoding="async"
data-image-viewer
/>
</figure>
</div>
<div class="case-block" id="itog">
<h2>Результаты и рефлексия</h2>
<p class="section__prose">
Экран проектов стал проще сканировать: меньше визуального шума, быстрее находить нужный проект и его состояние. После раскатывания нового дизайна среди нескольких клиентов мы получили положительные отзывы и множество идей для дальнейших улучшений.
</p>
<p class="section__prose">
Я оставил проект, когда Елизавета уже уверенно чувствовала себя в нём и могла самостоятельно вести дизайнерские задачи. Периодически я отвечал на точечные вопросы, но в целом передача прошла гладко.
</p>
<p class="section__prose">
Спустя год с небольшим процессы в команде заметно изменились. По словам ребят, в создании и передаче дизайна теперь активное участие принимают инструменты с нейросетями — такие как Claude Design. То, что мы начинали выстраивать вручную через токены, Storybook и синхронизацию сред, сейчас в какой-то мере автоматизируется.
</p>
<p class="section__prose">
Считаю, что проделанная работа была выполнена достаточно оперативно и качественно — в условиях постоянных изменений на рынке и внутри компании нам удалось не просто обновить интерфейс, но и выстроить устойчивый процесс, который продолжил работать уже без моего участия.
</p>
</div>
</div>
</main>
<section class="section section--surface" data-reveal>
<div class="section__inner">
<h2 class="section__title">Смотрите также</h2>
<ol class="mini-projects-grid" data-mini-projects-list>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="ai-platform-primo-rpa">
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="Платформа для работы с AI — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/ai-platform-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Primo AI Server</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Web App</li>
</ul>
<p class="mp-card__desc">Интерфейс для обучения и использования AI‑моделей в бизнес‑процессах: работа с данными, сценариями автоматизации и Smart OCR.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="lunacy">
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Графический редактор Lunacy — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/lunacy/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Lunacy</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Desktop App</li>
</ul>
<p class="mp-card__desc">Работа над интерфейсом Lunacy в команде Icons8: user flow, сложные прототипы, улучшение функциональности и интерфейсной логики.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="manu-game-maker" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="Игровой движок MANU — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/manu-game-maker/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Игровой движок MANU</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">Product Design</li>
<li class="mp-card__tag">Desktop App</li>
</ul>
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="mobile-clinic-app" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Мобильное приложение для сети клиник — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/mobile-clinic-app/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Mobile App</li>
</ul>
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="orc-automation-panel">
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Веб-панель для оркестрации автоматизаций — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/orc-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Primo Orc</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">Менторство и наставничество</li>
</ul>
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="task-distribution-concept" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="Концепт сервиса распределения задач — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/task-distribution-concept/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">UX/UI</li>
<li class="mp-card__tag">Analytics</li>
</ul>
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
</div>
</a>
</li>
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="task-tracker" hidden>
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Таск-трекер для бек-офис системы — открыть кейс">
<div class="mp-card__media" aria-hidden="true">
<img
class="mp-card__image"
src="../../assets/task-tracker/cover.webp"
alt=""
width="400"
height="225"
loading="lazy"
decoding="async"
/>
</div>
<div class="mp-card__body">
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
<ul class="mp-card__tags" aria-label="Тип проекта">
<li class="mp-card__tag">Product Design</li>
<li class="mp-card__tag">Web App</li>
</ul>
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&amp;Drop.</p>
</div>
</a>
</li>
</ol>
</div>
</section>
<section hidden class="section section--surface" aria-hidden="true">
<div class="section__inner">
<div class="projects__heading">
<h2 class="section__title projects__title">Портфолио</h2>
<div class="projects__controls" aria-label="Навигация по карточкам портфолио">
<button type="button" class="projects__nav-btn" data-projects-prev aria-label="Прокрутить влево" aria-controls="projects-viewport">
<span class="projects__nav-ico projects__nav-ico--left" aria-hidden="true"></span>
</button>
<button type="button" class="projects__nav-btn" data-projects-next aria-label="Прокрутить вправо" aria-controls="projects-viewport">
<span class="projects__nav-ico projects__nav-ico--right" aria-hidden="true"></span>
</button>
</div>
</div>
<div class="projects-carousel">
<div id="projects-viewport" class="projects-carousel__viewport" data-projects-viewport>
<div class="projects-carousel__track">
<div class="projects-carousel__spacer" aria-hidden="true"></div>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../orc-automation-panel/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Веб-панель для оркестрации автоматизаций</h3>
<p class="portfolio-card__summary">
Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под
продакшен без остановки релизов.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Web App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/orc-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../ai-platform-primo-rpa/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Платформа для работы с AI</h3>
<p class="portfolio-card__summary">
Интерфейс для обучения и использования AI‑моделей в бизнес‑процессах: работа с данными, сценариями
автоматизации и Smart OCR.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Web App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/ai-platform-primo-rpa/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../task-tracker/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Таск-трекер для бек-офис системы</h3>
<p class="portfolio-card__summary">
Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по
исполнителям; вкладки, фильтры, виды доска / список / таблица, Drag&amp;Drop.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">Product Design</li>
<li class="portfolio-card__tag">Web App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/task-tracker/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../manu-game-maker/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Игровой движок MANU</h3>
<p class="portfolio-card__summary">
Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и
проработка сотен сложных пользовательских сценариев.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">Product Design</li>
<li class="portfolio-card__tag">Desktop App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/manu-game-maker/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../lunacy/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Графический редактор Lunacy</h3>
<p class="portfolio-card__summary">
Работа над интерфейсом Lunacy в команде Icons8: user flow, сложные прототипы, улучшение функциональности и
интерфейсной логики.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Desktop App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/lunacy/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../mobile-clinic-app/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Мобильное приложение для сети клиник</h3>
<p class="portfolio-card__summary">
Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом
пользовательском пути, понятной навигации и быстром доступе к нужным действиям.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Mobile App</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/mobile-clinic-app/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../task-distribution-concept/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Концепт сервиса распределения задач</h3>
<p class="portfolio-card__summary">
Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность
процессов и удобство командной работы.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Analytics</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/task-distribution-concept/cover.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<article class="projects-carousel__item">
<a class="portfolio-card" href="../obsidian-plugin-columns-view/">
<div class="portfolio-card__body">
<h3 class="portfolio-card__title">Колоночный вид — плагин для Obsidian</h3>
<p class="portfolio-card__summary">
Интерфейс для многоколоночной работы с заметками: удобная навигация, фильтрация и настройка
колончатого отображения прямо в редакторе Obsidian.
</p>
<ul class="portfolio-card__tags" aria-label="Ключевые теги">
<li class="portfolio-card__tag">UX/UI</li>
<li class="portfolio-card__tag">Plugin</li>
</ul>
</div>
<div class="portfolio-card__cover" aria-hidden="true">
<img
class="portfolio-card__image"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
data-defer-src="../../assets/obsidian-plugin-columns-view/filter use.webp"
alt=""
width="400"
height="225"
decoding="async"
/>
</div>
</a>
</article>
<div class="projects-carousel__spacer" aria-hidden="true"></div>
</div>
</div>
<button
type="button"
class="projects-carousel__edge-hit projects-carousel__edge-hit--left"
data-projects-edge-prev
aria-label="Прокрутить портфолио влево"
></button>
<button
type="button"
class="projects-carousel__edge-hit projects-carousel__edge-hit--right"
data-projects-edge-next
aria-label="Прокрутить портфолио вправо"
></button>
</div>
</div>
</section>
<section id="contact" class="section section--surface section--footerish" data-reveal>
<div class="section__inner">
<h2 class="section__title">Контакты</h2>
<ul class="contact-grid">
<li><a class="contact-card contact-card--link contact-card--brand-tg" href="https://t.me/mamadaevv" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../assets/shared/icons/tg.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">Telegram</span><span class="contact-card__hint">Отвечу сегодня</span></span></a></li>
<li><a class="contact-card contact-card--link contact-card--brand-vk" href="https://vk.com/mamadaevv" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../assets/shared/icons/vk.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">ВКонтакте</span><span class="contact-card__hint">Стабильный коннект</span></span></a></li>
<li><button type="button" class="contact-card contact-card--action contact-card--brand-email" data-contact-copy data-email-b64="bmlrQG1hbWFkYWV2di5zaXRl" data-hint-default="Скопировать адрес" aria-label="Скопировать адрес электронной почты в буфер обмена"><span class="contact-card__corner contact-card__corner--copy" aria-hidden="true"></span><span class="contact-card__icon contact-card__icon--accent" aria-hidden="true"></span><span class="contact-card__body"><span class="contact-card__name">Почта</span><span class="contact-card__hint" data-contact-copy-hint>Скопировать адрес</span></span></button></li>
</ul>
</div>
</section>
<footer class="footer">
<div class="footer__inner">
<span class="footer__chunk footer__chunk--date">© 2015–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/">Политика cookie</a></span>
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Выбор языка" data-lang-switch>
<a class="lang-switch__btn" data-lang="en" href="/en/">English</a>
</nav>
<script>
(function () {
var p = location.pathname.replace(/^\/+/, "");
var isEn = p.indexOf("en/") === 0;
var base = isEn ? p.slice(3) : p;
var links = document.querySelectorAll("[data-lang-switch] [data-lang]");
for (var i = 0; i < links.length; i++) {
var l = links[i].getAttribute("data-lang");
links[i].setAttribute("href", (l === "en" ? "/en/" : "/") + base);
}
})();
</script>
</span>
</div>
</footer>
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
<p class="cookie-notice__text">
Сайт использует cookie для комфортной работы. Подробнее — в
<a href="../../cookie-policy/" data-cookie-policy-link>cookie policy</a>.
</p>
<button type="button" class="btn btn--secondary btn--flat cookie-notice__accept" data-cookie-accept>
<span>Принять</span>
<span class="cookie-notice__accept-icon" aria-hidden="true">
<img src="../../assets/shared/icons/сookie.svg" alt="" width="20" height="20" loading="eager" decoding="async" />
</span>
</button>
</aside>
<div id="nav-more-menu-floating" class="nav-more__floating" hidden data-nav-more-menu-floating aria-hidden="true"></div>
<script>
document.addEventListener('DOMContentLoaded',function(){
var s=document.body.dataset.currentCase;
if(!s)return;
document.querySelectorAll('[data-related-slug="'+s+'"]').forEach(function(el){el.hidden=true;});
});
</script>
</body>
</html>