feat(i18n): translate all case studies and resume to English
- add .en.html overrides for 16 case pages + resume via apinex translator - translate remaining partials (projects-related, mini-projects-*, fab-stack-home-contact, fab-stack-resume, content-edit-fab-stack, cookie-notice) - enhance translate.mjs to protect <script>/<style> from translation - second pass: translate attribute values (aria-label/alt/title/placeholder/content/ data-hint-default) and visible text DeepL skipped in html mode - make logo language-aware (NM / НМ) via i18n
This commit is contained in:
1 parent
20ee81bfaf
commit
4b52cec00d
58 files changed
+14812
-6924
No files matched your search
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: AI assistant — плагин для Figma с AI-функциями."
|
||||
content="Case Study: AI Assistant—a Figma plugin with AI features."
|
||||
/>
|
||||
<title>AI assistant — Плагин для Figma — кейс</title>
|
||||
<title>AI Assistant — Figma Plugin — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -179,7 +179,7 @@
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -249,55 +249,55 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Figma · Plugin</p>
|
||||
<h1 class="case-page__h1">AI assistant</h1>
|
||||
<p class="case-page__sub">Плагин для Figma с AI-функциями</p>
|
||||
<h1 class="case-page__h1">AI Assistant</h1>
|
||||
<p class="case-page__sub">A Figma plugin with AI features</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
</p>
|
||||
|
||||
<h2 id="context">Контекст</h2>
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
</p>
|
||||
|
||||
<h2 id="task">Задача</h2>
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
</p>
|
||||
|
||||
<h2 id="solution">Решение</h2>
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
</p>
|
||||
|
||||
<h2 id="result">Результат</h2>
|
||||
<h2 id="result">Result</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
</p>
|
||||
@@ -306,20 +306,20 @@
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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-assistant">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
aria-label="AI Assistant — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
<h3 class="mp-card__title">AI Assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Плагин для Figma с AI-функциями.</p>
|
||||
<p class="mp-card__desc">A Figma plugin with AI features.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -327,14 +327,14 @@
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
aria-label="Card Columns — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Obsidian Plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Плагин для колоночного отображения карточек в Obsidian.</p>
|
||||
<p class="mp-card__desc">A plugin for displaying cards in columns in Obsidian.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -342,14 +342,14 @@
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
aria-label="This website — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
<h3 class="mp-card__title">This website</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Development with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Разработка сайта с использованием AI IDE.</p>
|
||||
<p class="mp-card__desc">Website development using AI IDE.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -371,10 +371,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -392,22 +393,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: редизайн Primo RPA AI Server — снижение порога входа для клиентов без команды внедрения."
|
||||
content="Case Study: Redesign of the Primo RPA AI Server — Lowering the Barrier to Entry for Customers Without an Implementation Team."
|
||||
/>
|
||||
<title>AI Server в Primo RPA — кейс</title>
|
||||
<title>AI Server in Primo RPA — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -214,7 +214,7 @@
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -284,42 +284,42 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Product Design · AI</p>
|
||||
<h1 class="case-page__h1">Упростил настройку Primo RPA AI Server: клиенты настраивают ИИ-сервис без команды внедрения</h1>
|
||||
<h1 class="case-page__h1">Simplified Primo RPA AI Server setup: customers configure the AI service without an implementation team</h1>
|
||||
<p class="case-page__sub">
|
||||
Платформа интеллектуальной обработки документов<br />
|
||||
и оркестрации ИИ-агентов. Обращения к команде внедрения упали на 40%, настройка первого проекта ужалась с ~3 дней до ~4 часов.
|
||||
A platform for intelligent document<br />
|
||||
processing and AI agent orchestration. Requests to the implementation team have dropped by 40%, and the time required to set up the first project has been reduced from ~3 days to ~4 hours.
|
||||
</p>
|
||||
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/main-new.webp"
|
||||
alt="Обновлённый редактор разметки датасета — главный экран сервиса после редизайна"
|
||||
alt="The updated dataset markup editor—the service's main screen following the redesign"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
@@ -329,211 +329,211 @@
|
||||
</figure>
|
||||
|
||||
<dl class="case-meta">
|
||||
<dt>Продукт</dt>
|
||||
<dd>AI Server. Нейросети во внутреннем контуре компании, настраивается через веб-интерфейс</dd>
|
||||
<dt>Роль</dt>
|
||||
<dd>UX/UI-дизайнер (единственный на проекте)</dd>
|
||||
<dt>Задача</dt>
|
||||
<dd>Снизить порог входа, чтобы клиент настраивал сервис сам</dd>
|
||||
<dt>Стек</dt>
|
||||
<dd>Ant Design + React, стилизация Hope UI</dd>
|
||||
<dt>Формат</dt>
|
||||
<dd>Редизайн живого продукта, релизы не останавливались</dd>
|
||||
<dt>Product</dt>
|
||||
<dd>AI Server. Neural networks within the company’s internal network, configured via a web interface</dd>
|
||||
<dt>Role</dt>
|
||||
<dd>UX/UI Designer (the only one on the project)</dd>
|
||||
<dt>Objective</dt>
|
||||
<dd>Lower the barrier to entry so that the client can configure the service themselves</dd>
|
||||
<dt>Stack</dt>
|
||||
<dd>Ant Design + React, styled with Hope UI</dd>
|
||||
<dt>Format</dt>
|
||||
<dd>Redesign of a live product; releases continued uninterrupted</dd>
|
||||
</dl>
|
||||
|
||||
<div class="case-block" id="problem">
|
||||
<h2>С настройкой справлялись только эксперты. Это тормозило продажи</h2>
|
||||
<h2>Only experts could handle the configuration. This slowed down sales</h2>
|
||||
<p class="section__prose">
|
||||
AI Server разворачивается на внутренних серверах клиентов. Продукт активно тестировали, и обратная связь показала неприятное: настроить его могли только эксперты и команда внедрения Primo RPA. Каждый новый клиент съедал часы техподдержки. Продукт терял привлекательность и плохо масштабировался.
|
||||
The AI Server is deployed on the client’s internal servers. The product was actively tested, and the feedback revealed an unpleasant truth: only experts and the Primo RPA implementation team could configure it. Every new client consumed hours of technical support. The product was losing its appeal and didn’t scale well.
|
||||
</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>
|
||||
Бизнес-цель: клиент проходит настройку AI Server сам, без техподдержки и команды внедрения. По этому критерию мы и мерили успех редизайна.
|
||||
Business goal: The client sets up AI Server on their own, without technical support or an implementation team. We measured the success of the redesign based on this criterion.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
Начал со знакомства с командой и экспертами по настройке. Разделил сценарии на главные и вспомогательные, собрал визуализацию того, как ведёт себя пользователь, и вместе с разработкой искал, где интерфейс можно упростить. Я уже работал с ИИ и похожими веб-платформами, поэтому быстро разобрался в домене и говорил с разработкой на одном языке.
|
||||
I started by getting to know the team and the configuration experts. I divided the scenarios into primary and secondary ones, created a visual representation of user behavior, and worked with the development team to identify areas where the interface could be simplified. I had already worked with AI and similar web platforms, so I quickly got up to speed on the subject matter and was able to speak the same language as the development team.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="constraints">
|
||||
<h2>Ограничения</h2>
|
||||
<h2>Constraints</h2>
|
||||
<ul>
|
||||
<li>Продуктом уже пользовались клиенты. Остановить разработку и пересобрать интерфейс целиком было нельзя.</li>
|
||||
<li>Изменения приходилось вписывать в план релизов, отдельного «редизайн-спринта» никто не выделял.</li>
|
||||
<li>Жёсткий стек: Ant Design под React со стилизацией под Hope UI. Новые компоненты рисовать только в крайнем случае, сначала выжимаем всё из готовой библиотеки.</li>
|
||||
<li>Customers were already using the product. It wasn’t possible to halt development and completely rebuild the interface.</li>
|
||||
<li>Changes had to be incorporated into the release plan; no one allocated time for a separate “redesign sprint.”</li>
|
||||
<li>Strict tech stack: Ant Design on top of React, styled after Hope UI. We only created new components as a last resort; first, we made the most of the existing library.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="navigation">
|
||||
<h2>Навигация путала: разделы проекта смешивались с главным меню</h2>
|
||||
<h2>Navigation was confusing: project sections were mixed in with the main menu</h2>
|
||||
<p class="section__prose">
|
||||
В сервисе стояла привычная для админок схема: слева боковое меню, справа контент. Пространство расходовалось расточительно, а при открытии проекта навигация по его разделам оказывалась вперемешку с главной. Пользователь терялся.
|
||||
The service used a layout common to admin panels: a sidebar on the left, content on the right. Space was wasted, and when opening a project, navigation through its sections was intermixed with the main navigation. Users got lost.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Две навигации в одном боковом меню заставляли каждый раз разбираться, «где я». Развёл их по уровням: главная сверху, проектная внутри проекта.
|
||||
Having two navigation systems in a single sidebar forced users to figure out “where they were” every time. I organized them by level: the main navigation at the top, and project-specific navigation within each project.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/main-new.webp"
|
||||
alt="Главный экран AI Server с компактной верхней навигацией"
|
||||
alt="The AI Server home screen with a compact top navigation bar"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Главный экран AI Server с компактной верхней навигацией — список проектов занимает почти всю ширину экрана</figcaption>
|
||||
<figcaption>The AI Server home screen with a compact top navigation bar—the list of projects takes up almost the entire width of the screen</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Перенёс главную навигацию наверх и ужал её. Контенту стало заметно просторнее, а схема осталась привычной. У проектов появилась собственная навигация, которая с главной не пересекается.
|
||||
I moved the main navigation to the top and condensed it. The content now has noticeably more space, while the layout remains familiar. Projects now have their own navigation that doesn’t overlap with the main navigation.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/nav-project-nlp.webp"
|
||||
alt="Внутренняя навигация NLP-проекта"
|
||||
alt="Internal Navigation of the NLP Project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Внутренняя навигация NLP-проекта — горизонтальные пункты-шаги под главным меню</figcaption>
|
||||
<figcaption>Internal navigation for the NLP project—horizontal step-by-step items below the main menu</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/nav-project-ocr.webp"
|
||||
alt="Внутренняя навигация OCR-проекта"
|
||||
alt="Internal Navigation for the OCR Project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Внутренняя навигация OCR-проекта — тот же паттерн со своим набором разделов</figcaption>
|
||||
<figcaption>Internal navigation for the OCR project—the same pattern with its own set of sections</figcaption>
|
||||
</figure>
|
||||
<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>
|
||||
Стрелочная форма пунктов подсказывает порядок настройки, но не навязывает его: разделы остаются обычными табами. Подсказка без принуждения.
|
||||
The arrow-shaped icons suggest a configuration order but do not enforce it: the sections remain standard tabs. A suggestion, not a requirement.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/nav-secondary-detail_view.webp"
|
||||
alt="Крупный план вторичной навигации — пункты в форме стрелок"
|
||||
alt="Close-up of secondary navigation—arrow-shaped markers"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Крупный план вторичной навигации — пункты в форме стрелок, ведущих слева направо</figcaption>
|
||||
<figcaption>Close-up of secondary navigation—items in the form of arrows pointing from left to right</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="editor">
|
||||
<h2>Редактор датасета: экран, где пользователи живут</h2>
|
||||
<h2>Dataset Editor: the screen where users spend most of their time</h2>
|
||||
<p class="section__prose">
|
||||
Здесь проводят больше всего времени. Разметка полей на сотнях изображений — работа монотонная, но именно от неё зависит качество данных для обучения модели. Прежний редактор выбивался из общего стиля, выглядел перегруженно и путал в работе с полями.
|
||||
This is where users spend most of their time. Annotating fields on hundreds of images is monotonous work, but the quality of the data used to train the model depends on it. The previous editor didn’t fit the overall style, looked cluttered, and made working with fields confusing.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Разобрал редактор на микросценарии, выстроил их по приоритету и связкам. Вместе с командой спроектировали поведение плавнее и понятнее, заложили место под будущий функционал, дизайн привели к общей стилистике сервиса.
|
||||
I broke the editor down into microscenarios, organized them by priority and interdependencies. Together with the team, we designed a smoother and more intuitive user experience, reserved space for future features, and aligned the design with the service’s overall style.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/dataset-editor.webp"
|
||||
alt="Редактор разметки датасета — размечаемый документ в центре, панели полей и инструментов по бокам"
|
||||
alt="Dataset Markup Editor — the document being marked up in the center, with field and tool panels on either side"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Редактор разметки датасета — размечаемый документ в центре, панели полей и инструментов по бокам</figcaption>
|
||||
<figcaption>Dataset markup editor—the document being marked up is in the center, with field and tool panels on either side</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Страница стала симметричной. Почти всё пространство уходит на размечаемое изображение, действия сгруппированы по панелям: нужная функция ищется быстро.
|
||||
The page became symmetrical. Almost all the space is devoted to the image being annotated, and actions are grouped by panels: the desired function can be found quickly.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/dataset_editor-wireframe-default_mode.webp"
|
||||
alt="Схематичный каркас редактора — центральная рабочая область и боковые панели"
|
||||
alt="A schematic overview of the editor's layout—the central workspace and side panels"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Схематичный каркас редактора — центральная рабочая область и боковые панели, режим по умолчанию</figcaption>
|
||||
<figcaption>Schematic layout of the editor—central workspace and side panels, default mode</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Для продвинутых пользователей добавил режим «Во весь экран». Боковые панели сворачиваются, работа идёт через горячие клавиши и нижнюю панель. На небольших мониторах это спасает.
|
||||
For advanced users, I’ve added a “Full Screen” mode. The side panels collapse, and you work using keyboard shortcuts and the bottom panel. This is a lifesaver on small monitors.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/full-screen-mode-with-panels.webp"
|
||||
alt="Полноэкранный режим редактора с раскрытыми боковыми панелями"
|
||||
alt="Full-screen editor mode with side panels open"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Полноэкранный режим редактора с раскрытыми боковыми панелями</figcaption>
|
||||
<figcaption>Full-screen editor mode with side panels expanded</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/full-screen-mode-zen.webp"
|
||||
alt="Полноэкранный режим без панелей — только размечаемый документ и нижняя панель"
|
||||
alt="Full-screen mode without panels—only the document being marked up and the bottom panel"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Полноэкранный режим без панелей — на экране только размечаемый документ и нижняя панель инструментов</figcaption>
|
||||
<figcaption>Full-screen mode without panels—only the document being edited and the bottom toolbar are visible on the screen</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-both_panels.webp"
|
||||
alt="Четыре варианта каркаса полноэкранного режима"
|
||||
alt="Four Full-Screen Mode Frame Options"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Четыре варианта каркаса полноэкранного режима — обе панели, без панелей, только левая, только правая</figcaption>
|
||||
<figcaption>Four full-screen layout options: both panels, no panels, left panel only, right panel only</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/dataset_editor-main_toolbar.webp"
|
||||
alt="Нижняя панель инструментов — переключение между изображениями и быстрые действия разметки"
|
||||
alt="Bottom toolbar — switch between images and quick markup actions"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Нижняя панель инструментов — переключение между изображениями и быстрые действия разметки</figcaption>
|
||||
<figcaption>Bottom toolbar—switch between images and quick markup actions</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="mapping">
|
||||
<h2>Десятки полей на одном скане, и место под документ не страдает</h2>
|
||||
<h2>Dozens of fields on a single scan, without sacrificing document space</h2>
|
||||
<p class="section__prose">
|
||||
Смежная задача: настроить уникальные параметры полей датасета. Большая область нужна под скан документа, полей десятки, у каждого свои типы и зависимые параметры.
|
||||
Related task: Configure unique field settings for the dataset. A large area is needed for the document scan, with dozens of fields, each having its own types and dependent settings.
|
||||
</p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
@@ -547,184 +547,184 @@
|
||||
>
|
||||
<source src="../../../assets/ai-platform-primo-rpa/fields-maping.webm" type="video/webm" />
|
||||
<source src="../../../assets/ai-platform-primo-rpa/fields-maping.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Прототип сопоставления полей — пользователь выбирает поле на скане документа и настраивает его параметры в компактной панели</figcaption>
|
||||
<figcaption>Field mapping prototype—the user selects a field on the document scan and configures its parameters in a compact panel</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Интерфейс вышел компактным. Механика не считывается с первого взгляда, зато после короткого обучения работать в нём быстро и комфортно.
|
||||
The interface turned out to be compact. The mechanics aren’t immediately obvious at first glance, but after a short learning curve, working with it becomes quick and comfortable.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="learning">
|
||||
<h2>Карточки обучения: паттерн, который разошёлся по всему продукту</h2>
|
||||
<h2>Training cards: a pattern that has spread throughout the product</h2>
|
||||
<p class="section__prose">
|
||||
После разметки датасета модель дообучают (fine-tuning). Разобрали все действия пользователя, перебрали несколько компоновок страницы. Остановились на ленте из карточек.
|
||||
After annotating the dataset, the model undergoes fine-tuning. We analyzed all user actions and explored several page layouts. We settled on a card feed.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/in_project-learn-overview.webp"
|
||||
alt="Раздел обучения моделей — вертикальная лента карточек"
|
||||
alt="Model Training Section — Vertical Card Strip"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Раздел обучения моделей — вертикальная лента карточек, сверху карточка настройки нового обучения</figcaption>
|
||||
<figcaption>The model training section is a vertical card feed, with a new training setup card at the top</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
В начале ленты карточка настройки: результат разметки активного датасета, параметры, запуск fine-tuning.
|
||||
At the beginning of the feed is a configuration card: the annotation results for the active dataset, parameters, and the option to start fine-tuning.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/in_project-learn-card-new.webp"
|
||||
alt="Карточка настройки обучения — матрица качества датасета и блок параметров запуска"
|
||||
alt="Training Configuration Card — Dataset Quality Matrix and Run Parameters Block"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Карточка настройки обучения — матрица качества датасета и блок параметров запуска</figcaption>
|
||||
<figcaption>Training configuration card—dataset quality matrix and launch parameters section</figcaption>
|
||||
</figure>
|
||||
<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>
|
||||
Матрица оценки качества разметки показывает готовность датасета к обучению на одном экране. Раньше приходилось вручную просматривать поля по всем документам.
|
||||
The annotation quality matrix shows the dataset’s readiness for training on a single screen. Previously, we had to manually review fields across all documents.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
Под каждый запущенный процесс появляется своя карточка. Можно завести несколько процессов с разными параметрами и сравнить, какая конфигурация отработала лучше.
|
||||
A separate card appears for each running process. You can start multiple processes with different parameters and compare which configuration performed better.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/in_project-learn-card-learning_process.webp"
|
||||
alt="Карточка запущенного процесса обучения — статус, прогресс и метрики"
|
||||
alt="Active Learning Process Card — Status, Progress, and Metrics"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Карточка запущенного процесса обучения — статус, прогресс и метрики, разнесённые по логическим блокам</figcaption>
|
||||
<figcaption>Card for a running training process—status, progress, and metrics organized into logical blocks</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/in_project-learn-card-learning_process_wireframe.webp"
|
||||
alt="Каркас карточки процесса обучения"
|
||||
alt="Learning Process Card Template"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Каркас карточки процесса обучения — схема расположения информационных блоков и действий</figcaption>
|
||||
<figcaption>The framework of a training process card—a layout of information blocks and actions</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Карточки сворачиваются, в шапке остаются название и статус.
|
||||
Cards can be collapsed; the title and status remain visible in the header.
|
||||
</p>
|
||||
<figure class="case-media case-media--natural">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/in_project-learn-card-сollapsed.webp"
|
||||
alt="Свёрнутая карточка обучения — одна строка с названием и статусом процесса"
|
||||
alt="A collapsed training card—a single line showing the name and status of the process"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<figcaption>Свёрнутая карточка обучения — одна строка с названием и статусом процесса</figcaption>
|
||||
<figcaption>Collapsed training card—a single line showing the process name and status</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Паттерны из этих карточек потом разошлись по другим разделам продукта. Единый стиль стало проще держать.
|
||||
Patterns from these cards were later applied to other sections of the product. It became easier to maintain a consistent style.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="processes">
|
||||
<h2>Долгие процессы — в соседнюю вкладку</h2>
|
||||
<h2>Long processes—in a separate tab</h2>
|
||||
<p class="section__prose">
|
||||
Часть задач идёт параллельно с остальной работой. Для таких сценариев модальное окно открывается на отдельной странице.
|
||||
Some tasks run in parallel with other work. For such scenarios, a modal window opens on a separate page.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Пользователь держит окно процесса в соседней вкладке и следит за прогрессом, а с проектом продолжает работать в доступных разделах.
|
||||
The user keeps the process window open in a neighboring tab to monitor progress while continuing to work on the project in the available sections.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.webp"
|
||||
alt="Импорт датасета в модальном окне на отдельной странице"
|
||||
alt="Importing a dataset in a modal window on a separate page"
|
||||
width="1440"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Импорт датасета в модальном окне на отдельной странице — форма загрузки на весь экран</figcaption>
|
||||
<figcaption>Importing a dataset in a modal window on a separate page—a full-screen upload form</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
На странице проекта в это время висит заглушка с кнопкой перехода к процессу.
|
||||
Meanwhile, a placeholder with a button to navigate to the process remains on the project page.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/ai-platform-primo-rpa/fullscreen_modal-in_project-import_dataset.webp"
|
||||
alt="Заглушка активного импорта внутри проекта"
|
||||
alt="Active Import Placeholder Within a Project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Заглушка активного импорта внутри проекта — индикатор процесса и кнопка перехода</figcaption>
|
||||
<figcaption>Placeholder for active import within the project—progress indicator and "Go to Process" button</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="decisions">
|
||||
<h2>Что я решил не делать, и почему</h2>
|
||||
<h2>What I Decided Not to Do, and Why</h2>
|
||||
<ul>
|
||||
<li><strong>Не стал блокировать кнопки на отдельных страницах</strong> во время активных процессов. Модалка на отдельной странице технически проще, а прогресс виден в соседней вкладке.</li>
|
||||
<li><strong>Не рисовал новые компоненты</strong>, кроме крайних случаев. Готовая библиотека Ant Design ускоряла разработку и держала интерфейс консистентным.</li>
|
||||
<li><strong>Не убрал боковые панели редактора совсем</strong>, а сделал сворачиваемыми. Новичкам нужны подсказки на экране, продвинутым — максимум места под документ.</li>
|
||||
<li><strong>Не заводил отдельную дизайн-систему.</strong> В продукте уже был фреймворк, в разработку передавал ссылки на готовые юзерфлоу в Figma.</li>
|
||||
<li><strong>I chose not to disable buttons on individual pages</strong> during active processes. A modal on a separate page is technically simpler, and progress is visible in the adjacent tab.</li>
|
||||
<li><strong>I didn’t create new components</strong> except in extreme cases. The ready-made Ant Design library sped up development and kept the interface consistent.</li>
|
||||
<li><strong>I didn’t remove the editor’s side panels entirely</strong>; instead, I made them collapsible. Beginners need on-screen hints, while advanced users need as much space as possible for their document.</li>
|
||||
<li><strong>I didn’t set up a separate design system.</strong> The product already had a framework, so I passed links to the existing user flows in Figma to the development team.</li>
|
||||
</ul>
|
||||
<h3>Передача в разработку</h3>
|
||||
<h3>Handoff to Development</h3>
|
||||
<p class="section__prose">
|
||||
Раз в неделю обсуждали дизайн с командой: список задач, приоритеты, сроки под планы релизов. С верстальщиком уточнял детали макетов тет-а-тет и давал фидбэк после вёрстки, чтобы результат не разошёлся с задуманным поведением.
|
||||
Once a week, we discussed the design with the team: the task list, priorities, and deadlines aligned with release plans. I went over the details of the mockups one-on-one with the front-end developer and provided feedback after the layout was completed to ensure the result matched the intended behavior.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="results">
|
||||
<h2>Результат</h2>
|
||||
<h2>Result</h2>
|
||||
<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>
|
||||
Настройка первого проекта: было ~3 дня, стало ~4 часа. 7 из 10 клиентов проходят её без техподдержки.
|
||||
Setup for the first project: it used to take ~3 days, now it takes ~4 hours. 7 out of 10 customers complete the setup without technical support.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<ul>
|
||||
<li>Обращения к команде внедрения на этапе настройки сократились на <strong>40%</strong>. Базовую настройку клиенты проходят сами.</li>
|
||||
<li><strong>7 из 10</strong> новых клиентов настроили первый проект без техподдержки. До редизайна — 1 из 10.</li>
|
||||
<li>Настройка первого проекта: с <strong>~3 дней до ~4 часов</strong>.</li>
|
||||
<li>Переработано <strong>30+ экранов</strong>: навигация, редактор датасета, обучение моделей, импорт данных.</li>
|
||||
<li>Заложены паттерны, на которых функционал наращивается без больших переделок.</li>
|
||||
<li>В компанию наняли второго дизайнера. Я ввёл её в курс дела и курировал результат, после адаптации проект целиком перешёл под её ответственность.</li>
|
||||
<li>Requests to the implementation team during the setup phase decreased by <strong>40%.</strong> Clients complete the basic setup on their own.</li>
|
||||
<li><strong>7 out of 10</strong> new clients set up their first project without technical support. Before the redesign, it was 1 out of 10.</li>
|
||||
<li>Setting up the first project: from <strong>~3 days to ~4 hours</strong>.</li>
|
||||
<li><strong>Over 30 screens</strong> were redesigned: navigation, dataset editor, model training, and data import.</li>
|
||||
<li>We established design patterns that allow functionality to be expanded without major rework.</li>
|
||||
<li>The company hired a second designer. I brought her up to speed and oversaw the results; after she became familiar with the project, it was entirely transferred to her responsibility.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="conclusions">
|
||||
<h2>Выводы</h2>
|
||||
<h2>Conclusions</h2>
|
||||
<ul>
|
||||
<li>Жёсткий фреймворк оказался не ограничением, а ускорителем: готовая библиотека компонентов позволила думать о сценариях, а не о пикселях.</li>
|
||||
<li>Самые ценные инсайты дали эксперты по настройке. В следующий раз вовлёк бы команду внедрения ещё раньше.</li>
|
||||
<li>Передача проекта новому дизайнеру подтвердила: заложенные паттерны работают, их можно объяснить и поддерживать без автора.</li>
|
||||
<li>The rigid framework turned out to be an accelerator rather than a limitation: the ready-made component library allowed us to focus on scenarios rather than pixels.</li>
|
||||
<li>The most valuable insights came from configuration experts. Next time, I would involve the implementation team even earlier.</li>
|
||||
<li>Handing the project over to a new designer confirmed that the established patterns work and can be explained and maintained without the original author.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -732,10 +732,10 @@
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -749,16 +749,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -772,16 +772,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Lunacy</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -794,17 +794,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Игровой движок MANU</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">MANU Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="Мобильное приложение для сети клиник — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -817,17 +817,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="Веб-панель для оркестрации автоматизаций — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -841,15 +841,15 @@
|
||||
</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 class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="Концепт сервиса распределения задач — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -862,17 +862,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="Таск-трекер для бек-офис системы — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -885,12 +885,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&Drop.</p>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -1147,10 +1147,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -1168,22 +1169,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: Card Columns, плагин-вид для Obsidian Bases. Показывает заметки как карточки, разложенные по колонкам, с фильтрацией тегов по И/ИЛИ."
|
||||
content="Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR."
|
||||
/>
|
||||
<title>Card Columns, плагин для Obsidian Bases: кейс</title>
|
||||
<title>Card Columns, a plugin for Obsidian Bases: a case study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -270,7 +270,7 @@
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -340,202 +340,206 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Obsidian Bases · Plugin</p>
|
||||
<h1 class="case-page__h1">
|
||||
Канбан-вид для Obsidian Bases,<br />который не трогает ваши заметки
|
||||
A Kanban view for Obsidian Bases<br />
|
||||
that leaves your notes untouched
|
||||
</h1>
|
||||
<p class="case-page__sub">
|
||||
Card Columns: заметки как карточки по колонкам,<br />
|
||||
отбор по тегам И/ИЛИ за два клика
|
||||
Card Columns: Notes as cards in columns,<br />
|
||||
filtered by AND/OR tags with just two clicks
|
||||
</p>
|
||||
|
||||
<!-- МЕДИА: 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>
|
||||
<img src="../assets/card-columns-obsidian/hero.webp" alt="Card Columns: card columns on top of the .base file" width="1920" height="1080" loading="eager" decoding="async" data-image-viewer />
|
||||
<figcaption>"Columns" view on top of the note database</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>
|
||||
<li>Role: Product Design and Development</li>
|
||||
<li><span>Platform:</span> Obsidian Bases</li>
|
||||
<li><span>Status</span>: Working plugin, open source (MIT)</li>
|
||||
<li><span>Team: Solo</span>, side project</li>
|
||||
<li><span>Status:</span> Draft response, to be replaced</li>
|
||||
</ul>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Сколько заняла работа от первой идеи до рабочей версии? Недели? Месяц выходных?
|
||||
How long did it take from the initial idea to a working version? Weeks? A month of weekends?
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: собрал за три недели вечером, потом ещё месяц доводил по ходу
|
||||
собственной работы. Заменить на реальное.
|
||||
Draft answer: I put it together in three weeks in the evenings, then spent another month refining it while
|
||||
working on my own projects. Replace with the actual time.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="section__prose">
|
||||
В Obsidian появились Bases, отдельный тип файла, который показывает заметки не текстом, а
|
||||
в разных видах: таблицей, карточками, деревом. Стандартный вид карточек мне не зашёл: он
|
||||
плоский, без группировки, и в нём не разобраться, когда заметок сотни. Я хотел видеть их
|
||||
раскладку по колонкам, как канбан, но без лишнего веса. Так появился плагин-вид Card Columns.
|
||||
Obsidian now has Bases, a separate file type that displays notes not as text, but
|
||||
in various formats: tables, cards, and trees. The standard card view didn’t work for me: it’s
|
||||
flat, with no grouping, and it’s hard to make sense of when there are hundreds of notes. I wanted to see them
|
||||
arranged in columns, like a Kanban board, but without the extra overhead. That’s how the Card Columns view plugin came about.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="kontekst">
|
||||
<h2>Контекст</h2>
|
||||
<h2>Context</h2>
|
||||
<p class="section__prose">
|
||||
Bases, это не заметка и не отдельная база данных. Это запрос к vault-у: выбираешь
|
||||
заметки по фильтру, и фреймворк рисует их в выбранном виде. У самого Obsidian есть
|
||||
встроенный вид карточек, но он одноплановый: нет группировки по свойствам, нет
|
||||
нормальной фильтрации. Я решил сделать свой вид, который встраивается в переключатель
|
||||
Bases наравне со штатными.
|
||||
A “Bases” is neither a note nor a separate database. It’s a query to the vault: you select
|
||||
notes using a filter, and the framework displays them in the chosen view. Obsidian itself has
|
||||
a built-in card view, but it’s one-dimensional: no grouping by properties, no
|
||||
proper filtering. I decided to create my own view that integrates into the
|
||||
Bases toggle alongside the default ones.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Главное ограничение было в самом фреймворке: плагин не хранит данные, а рисует то, что
|
||||
выдал Bases-запрос (Sort, Filter, Properties, Search из тулбара). Значит, вся логика
|
||||
выборки остаётся на Bases, а моя задача, только представление и навигация по нему.
|
||||
The main limitation was in the framework itself: the plugin doesn’t store data, but rather renders what
|
||||
the Bases query returns (Sort, Filter, Properties, Search from the toolbar). This means that all the logic
|
||||
for data retrieval remains with Bases, and my task is solely to display and navigate the results.
|
||||
</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>
|
||||
<img src="../assets/card-columns-obsidian/overview.webp" alt="View of "Card Columns" in the .base file: notes on the columns" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Species Overview</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pochemu-svoi">
|
||||
<h2>Почему не готовое</h2>
|
||||
<h2>Why not use a ready-made solution?</h2>
|
||||
<p class="section__prose">
|
||||
Прежде чем писать код, я посмотрел, что уже есть. Три пути, все мимо:
|
||||
Before writing any code, I checked what was already available. Three options, none of them worked:
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Штатный вид карточек Bases.</strong> Рисует ровный поток карточек без группировки.
|
||||
Когда заметок за сотню, это лента, в которой нужно скроллить и вглядываться в заголовки.
|
||||
Отпал первым.
|
||||
<strong>The default Bases card view.</strong>
|
||||
It displays a continuous stream of cards without grouping.
|
||||
When there are over a hundred notes, it becomes a feed where you have to scroll and squint at the titles.
|
||||
I ruled that out first.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Канбан-плагины из комьюнити.</strong> Большинство тянет за собой свою систему
|
||||
хранения: доска живёт отдельно от vault-а, заметки дублируются. Получается вторая база,
|
||||
которую надо синхронизировать. Мне это было не нужно.
|
||||
<strong>Kanban plugins from the community.</strong>
|
||||
Most come with their own storage system:
|
||||
the board exists separately from the vault, and notes are duplicated. This results in a second database
|
||||
that needs to be synchronized. I didn’t need that.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Соседний bases-kanban.</strong> Ближайший по духу: цепляется к Bases, делает
|
||||
канбан. Но он пишет в заметки: перетаскивание карточки меняет frontmatter. Для view-плагина
|
||||
это риск, о котором ниже.
|
||||
<strong>The neighboring bases-kanban.</strong>
|
||||
The closest in spirit: it hooks into Bases to create
|
||||
a Kanban board. But it writes to the notes: dragging a card changes the frontmatter. For a view plugin,
|
||||
this is a risk, which I’ll discuss below.
|
||||
</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, это не недоделка, а позиция. Плагин представления не должен
|
||||
писать в пользовательские данные. Это решение определило всё остальное.
|
||||
The decision to forgo drag-and-drop isn’t a shortcoming—it’s a design choice. A view plugin should not
|
||||
write to user data. This decision shaped everything else.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Ты реально ставил и тестировал чужие плагины или ориентировался по описаниям? Какие
|
||||
именно смотрел?
|
||||
Did you actually install and test other people’s plugins, or did you just go by the descriptions? Which
|
||||
ones did you look at specifically?
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: поставил три штуки, погонял неделю на своей базе, удалил. bases-kanban
|
||||
смотрел в исходниках, не ставил. Заменить на реальное, названия плагинов вписать.
|
||||
Preliminary answer: I installed three of them, ran them for a week on my database, then uninstalled them. I looked at the source code for bases-kanban
|
||||
but didn’t install it. Replace with actual information; include the plugin names.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadacha">
|
||||
<h2>Задача</h2>
|
||||
<h2>Task</h2>
|
||||
<p class="section__prose">
|
||||
Спроектировать вид для Bases, который показывает заметки карточками по колонкам и позволяет
|
||||
быстро отбирать нужное. Жёсткое ограничение: плагин ничего не пишет в заметки и не хранит
|
||||
своего состояния, а сортировка, фильтр, свойства и поиск из штатного тулбара Bases должны
|
||||
работать как раньше.
|
||||
Design a view for Bases that displays notes as cards arranged in columns and allows you to
|
||||
quickly select the ones you need. Strict constraint: the plugin does not write anything to the notes and does not store
|
||||
its own state, and sorting, filtering, properties, and search from the standard Bases toolbar must
|
||||
work as before.
|
||||
</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 и берут. Этого нельзя
|
||||
было допустить.
|
||||
The main risk is creating a view that conflicts with the standard Bases toolbar. If that happens,
|
||||
the user loses the sorting and search capabilities—the very features that make Bases worth using. This could not
|
||||
be allowed to happen.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="reshenie">
|
||||
<h2>Решения</h2>
|
||||
<h2>Solutions</h2>
|
||||
<p class="section__prose">
|
||||
Плагин добавляет в Bases вид «Columns». Карточки строятся из результатов Bases-запроса,
|
||||
группировка задаётся свойством, а отбор, кликабельными тегами. Дальше, пять выборов,
|
||||
которые определили результат. В каждом есть то, от чего я отказался.
|
||||
The plugin adds a “Columns” view to Bases. Cards are built from the results of a Bases query;
|
||||
grouping is defined by a property, and filtering is done via clickable tags. Next, there are five options
|
||||
that determine the result. Each one includes something I decided against.
|
||||
</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>
|
||||
<img src="../assets/card-columns-obsidian/board.webp" alt="Columns of cards grouped by property" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>View with columns</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Группировка по любому свойству</h3>
|
||||
<h3>Grouping by any property</h3>
|
||||
<p class="section__prose">
|
||||
Колонки формируются из Group by в тулбаре Bases, по тегу, статусу, категории или любому
|
||||
frontmatter-свойству. Меняешь свойство в запросе, и доска пересобирается сама. Так одна
|
||||
и та же база закрывает разные разрезы: проекты по статусу, заметки по тегам, задачи по
|
||||
приоритету.
|
||||
Columns are generated using the “Group by” option in the Bases toolbar, by tag, status, category, or any
|
||||
frontmatter property. Change the property in the query, and the board reloads automatically. This way, a single
|
||||
database covers different perspectives: projects by status, notes by tags, tasks by
|
||||
priority.
|
||||
</p>
|
||||
|
||||
<h3>Фильтр тегов по И и ИЛИ</h3>
|
||||
<h3>Tag filter by AND and OR</h3>
|
||||
<p class="section__prose">
|
||||
Это то, ради чего плагин и задумывался. Под тулбаром, пилюли тегов, по клику они
|
||||
отсеивают карточки по всем колонкам сразу:
|
||||
This is exactly what the plugin was designed for. Below the toolbar, there are tag icons; when clicked, they
|
||||
filter cards across all columns at once:
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>Левый клик по тегу, показать только его (сбрасывает остальные фильтры).</li>
|
||||
<li>Левый клик по следующему тегу, показать заметки с ЛЮБЫМ из выбранных (режим ИЛИ).</li>
|
||||
<li>Ctrl+Клик или правый клик, переключить тег, не сбрасывая выбор.</li>
|
||||
<li>Кнопка OR/AND, переключить между «любой из» и «все перечисленные» для нескольких тегов.</li>
|
||||
<li>All, снять все фильтры.</li>
|
||||
<li>Left-click on a tag to show only that tag (resets the other filters).</li>
|
||||
<li>Left-click on the next tag to show notes with ANY of the selected tags (OR mode).</li>
|
||||
<li>Ctrl+Click or right-click to switch tags without resetting the selection.</li>
|
||||
<li>The OR/AND button: toggle between “any of” and “all of” for multiple tags.</li>
|
||||
<li>All: Clear all filters.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
Связка «ИЛИ-добавление левым кликом + точный toggle через Ctrl» получилась интуитивной:
|
||||
быстрый отбор не сбивает то, что уже выбрано. Альтернативу, вынести фильтр в модалку,
|
||||
отверг сразу: лишний клик и потеря контекста того, что уже отфильтровано.
|
||||
The combination of “OR—add with a left-click + exact toggle via Ctrl” turned out to be intuitive:
|
||||
quick selection doesn’t disrupt what’s already selected. I immediately rejected the alternative—moving the filter to a modal window—
|
||||
because it requires an extra click and loses the context of what’s already been filtered.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Выбор здесь не в самой фиче, а в том, где она живёт. Я выбрал пилюли под тулбаром вместо
|
||||
отдельного окна фильтров, потому что отбор по тегам, это действие на каждом шаге работы
|
||||
с базой. Модалка превращает его в прерванный сценарий: открыл, настроил, закрыл, проверил.
|
||||
Пилюли оставляют результат перед глазами, а состояние фильтра видно всегда.
|
||||
The choice here isn’t about the feature itself, but where it lives. I chose the pills below the toolbar instead of
|
||||
a separate filter window because filtering by tags is an action performed at every step of working
|
||||
with the database. A modal window turns it into an interrupted workflow: open, configure, close, check.
|
||||
The pill-shaped icons keep the result right in front of you, and the filter status is always visible.
|
||||
</p>
|
||||
<!-- МЕДИА: короткое видео фильтрации по тегам (OR / AND).
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
@@ -543,152 +547,152 @@
|
||||
<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" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Фильтрация по тегам: OR и AND</figcaption>
|
||||
<figcaption>Filtering by tags: OR and AND</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Карточки и обложки</h3>
|
||||
<h3>Cards and Covers</h3>
|
||||
<p class="section__prose">
|
||||
По каждой заметке рисуются свойства как чипы, текст, теги, ссылки, булевы, даты. Можно
|
||||
показать обложку: из первой картинки в заметке или из отдельного свойства. У обложки
|
||||
полный контроль, соотношение сторон (Auto, 1:1, 3:2, 4:3, 16:9), рамка, вписывание
|
||||
(cover/contain), ориентация и место на карточке (над заголовком, под ним, после всего).
|
||||
Properties such as chips, text, tags, links, Booleans, and dates are displayed for each note. You can
|
||||
show a cover: from the first image in the note or from a separate property. You have
|
||||
full control over the cover, including aspect ratio (Auto, 1:1, 3:2, 4:3, 16:9), border, fit
|
||||
(cover/contain), orientation, and position on the card (above the title, below it, at the end).
|
||||
</p>
|
||||
|
||||
<h3>Решение: настройки вынесены из кода</h3>
|
||||
<h3>Solution: Settings have been moved out of the code</h3>
|
||||
<p class="section__prose">
|
||||
Сначала параметры были захардкожены под мою базу. Это ошибка: вид перестал бы работать
|
||||
для чужого сценария. Вынес всё в gear-меню, разбив на четыре секции, чтобы вид
|
||||
подстраивался под разные базы, а не под мой единственный случай. Больше 15 параметров.
|
||||
At first, the parameters were hardcoded for my database. This was a mistake: the view would stop working
|
||||
for someone else’s scenario. I moved everything to the gear menu, dividing it into four sections so that the view
|
||||
could adapt to different databases, rather than just my single use case. More than 15 parameters.
|
||||
</p>
|
||||
<details class="case-details">
|
||||
<summary>Показать полный список настроек</summary>
|
||||
<summary>Show the full list of settings</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>
|
||||
<li>Where to open the card: active panel, pop-up window, new tab, split to the right / down.</li>
|
||||
<li>Card width (px).</li>
|
||||
<li>Columns per group (1–6), grid within a column.</li>
|
||||
<li>Zebra columns (alternating background colors for easy scanning).</li>
|
||||
<li>Masonry layout (cards fill vertical gaps).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Title</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Перенос заголовка, жирный заголовок, размер шрифта (px).</li>
|
||||
<li>Title wrapping, bold title, font size (px).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Properties</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Раскладка чипов: стек (вертикально) или сетка (компактно в строку).</li>
|
||||
<li>Перенос многострочных значений, размер шрифта.</li>
|
||||
<li>Формат даты и даты-времени + локаль (Moment.js).</li>
|
||||
<li>Chip layout: stack (vertical) or grid (compact in a row).</li>
|
||||
<li>Wrap multi-line values, font size.</li>
|
||||
<li>Date and date-time formats + locale (Moment.js).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Cover</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Источник: нет / первая картинка в заметке / свойство-обложка.</li>
|
||||
<li>Стиль (без рамки / с рамкой), соотношение сторон, ориентация, вписывание, позиция на карточке.</li>
|
||||
<li>Source: none / first image in the post / cover property.</li>
|
||||
<li>Style (borderless / with border), aspect ratio, orientation, fit, position on the card.</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Это правда про захардкоженные параметры? Если нет, замени на реальную причину выноса
|
||||
в настройки: просьбы пользователей, несколько баз с разной структурой, что угодно.
|
||||
Is it true about the hard-coded parameters? If not, replace it with the real reason for moving them
|
||||
to the settings: user requests, multiple databases with different structures, whatever.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: да, первая версия была под мою базу, настройки появились, когда
|
||||
понадобилось открыть плагин наружу. Проверить и поправить.
|
||||
Preliminary answer: Yes, the first version was tailored to my database; the settings were added when
|
||||
I needed to make the plugin available externally. I’ll check and fix it.
|
||||
</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+Клик,
|
||||
новую вкладку внутри сплита. Без этого на широком экране карточки неудобно
|
||||
просматривать рядом с доской.
|
||||
I implemented the split preview just like in Obsidian itself: left-click reuses the panel, Ctrl+click opens
|
||||
a new tab within the split. Without this, on a wide screen, it’s inconvenient to
|
||||
view cards next to the board.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Работает внутри штатного тулбара</h3>
|
||||
<h3>Works within the standard toolbar</h3>
|
||||
<p class="section__prose">
|
||||
Вид цепляется к BasesView-фреймворку, поэтому сортировка, фильтр, свойства и поиск из
|
||||
тулбара Bases остаются рабочими. Плагин только рисует результат запроса, данные не
|
||||
дублируются и не зависят от отдельного хранилища.
|
||||
The view hooks into the BasesView framework, so sorting, filtering, properties, and search from
|
||||
the Bases toolbar remain functional. The plugin only renders the query results; the data is not
|
||||
duplicated and does not depend on a separate storage.
|
||||
</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>
|
||||
<img src="../assets/card-columns-obsidian/settings.webp" alt="Plugin Settings Window: General, Title, Properties, Cover" width="1200" height="675" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>View Settings</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rezultat">
|
||||
<h2>Результат и как я это мерял</h2>
|
||||
<h2>The Result and How I Tested It</h2>
|
||||
<p class="section__prose">
|
||||
Вид закрыл мою боль: Bases-запрос теперь читается как доска, а не как плоская лента
|
||||
карточек. Группировка по свойству + отбор по тегам И/ИЛИ, то, чего не хватало штатному
|
||||
виду. Всё крутится на запросе Bases, так что перенос vault-а и синхронизация ничего не
|
||||
ломают.
|
||||
This view solved my problem: a Bases query now reads like a board, rather than a flat stream
|
||||
of cards. Grouping by property + filtering by AND/OR tags—exactly what the default
|
||||
view was missing. Everything runs on the Bases query, so moving the vault and syncing don’t
|
||||
break anything.
|
||||
</p>
|
||||
|
||||
<h3>Замер: сколько действий на отбор</h3>
|
||||
<h3>Metrics: number of steps to filter</h3>
|
||||
<p class="section__prose">
|
||||
Главная задача, по которой я мерял успех: отобрать заметки по двум тегам и найти нужную
|
||||
карточку. В штатном виде карточек это скролл ленты с поиском по заголовкам глазами. В
|
||||
Columns, два клика по пилюлям и колонка перед глазами.
|
||||
The main task I used to measure success: filter notes by two tags and find the right
|
||||
card. In the standard card view, this involves scrolling through the feed and scanning the titles with your eyes. In
|
||||
Columns, two clicks on the pills and the column is right in front of you.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Можешь прогнать этот замер по-настоящему? Засечь время на 10 повторах задачи: штатный
|
||||
вид против Columns. Или посчитать точное число действий.
|
||||
Can you run this test for real? Time 10 repetitions of the task: the default
|
||||
view versus Columns. Or count the exact number of steps.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: на выборке из 25 заметок отбор по двум тегам занимал около 40 секунд и
|
||||
требовал скроллить ленту; в Columns, два клика, примерно 5 секунд. Цифры примерные,
|
||||
заменить на замеренные.
|
||||
Preliminary answer: on a sample of 25 notes, filtering by two tags took about 40 seconds and
|
||||
required scrolling through the feed; in Columns, two clicks, about 5 seconds. These are rough estimates—
|
||||
replace them with actual measurements.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Замер: живучесть в ежедневной работе</h3>
|
||||
<h3>Test: Long-term usability in daily work</h3>
|
||||
<p class="section__prose">
|
||||
Второй критерий субъективнее, но для инструмента под себя он важнее: продолжаю ли я
|
||||
пользоваться плагином через месяц. Пользуюсь, он встроился в работу с базой и не требует
|
||||
вспоминать, как им управлять.
|
||||
The second criterion is more subjective, but for a tool tailored to my needs, it’s more important: will I still be
|
||||
using the plugin a month from now? I am—it’s become an integral part of my work with the database and doesn’t require
|
||||
me to remember how to use it.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Вопрос к автору</span>
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Есть ли внешние сигналы: установки, звёзды на GitHub, отзывы, вопросы в issue? Любая
|
||||
цифра, подтверждающая, что плагином пользуются не только ты.
|
||||
Are there any external indicators: installs, GitHub stars, reviews, or questions in the issue tracker? Any
|
||||
number confirming that you’re not the only one using the plugin.
|
||||
</p>
|
||||
<p>
|
||||
Черновой ответ: плагин пока ставится вручную, через каталог комьюнити не прошёл, так
|
||||
что установок единицы и звёзд пока нет. Если есть реальные данные, вписать их сюда,
|
||||
это сильнее любого-self-report.
|
||||
Preliminary answer: The plugin currently needs to be installed manually; it hasn’t been approved for the community repository yet, so
|
||||
there are only a handful of installs and no stars so far. If there’s actual data, include it here—
|
||||
it’s more convincing than any self-report.
|
||||
</p>
|
||||
</div>
|
||||
<p class="section__prose">
|
||||
Что сделал бы иначе. Drag-and-drop карточек между колонками не стал делать сознательно,
|
||||
это меняет свойство в заметке, и для view-плагина это отдельный риск целостности данных.
|
||||
Но вижу запрос на это у пользователей, и, возможно, добавлю как опциональный режим. А
|
||||
пока плагин живёт вручную (через community-каталог ещё не прошёл), это единственное, что
|
||||
мешает им пользоваться сходу.
|
||||
What I’d do differently. I deliberately chose not to implement drag-and-drop of cards between columns,
|
||||
since that changes a property in the note, and for a view plugin, that poses a separate data integrity risk.
|
||||
But I see a demand for this among users, and I might add it as an optional mode. For
|
||||
now, since the plugin is maintained manually (it hasn’t been reviewed by the community directory yet), this is the only thing
|
||||
preventing users from using it right away.
|
||||
</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 получается рабочим только тогда, когда он уважает
|
||||
тулбар фреймворка. Я добавил представление, а не вторую систему хранения, и заметки
|
||||
остались обычными заметками.
|
||||
Main conclusion: a view for Bases only works when it respects
|
||||
the framework’s toolbar. I added a view, not a second storage system, and the notes
|
||||
remained regular notes.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
@@ -698,20 +702,20 @@
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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-assistant">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
aria-label="AI Assistant — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
<h3 class="mp-card__title">AI Assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Плагин для Figma с AI-функциями.</p>
|
||||
<p class="mp-card__desc">A Figma plugin with AI features.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -719,14 +723,14 @@
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
aria-label="Card Columns — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Obsidian Plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Плагин для колоночного отображения карточек в Obsidian.</p>
|
||||
<p class="mp-card__desc">A plugin for displaying cards in columns in Obsidian.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -734,14 +738,14 @@
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
aria-label="This website — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
<h3 class="mp-card__title">This website</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Development with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Разработка сайта с использованием AI IDE.</p>
|
||||
<p class="mp-card__desc">Website development using AI IDE.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -763,10 +767,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -784,22 +789,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+449
-449
File diff suppressed because it is too large.
Load diff
@@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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="Кейс: редизайн и развитие интерфейса игрового движка MANU — визуальная система и сложные пользовательские сценарии."
|
||||
/>
|
||||
<title>Игровой движок MANU — кейс</title>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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="Case Study: Redesign and Development of the MANU Game Engine Interface—Visual System and Complex User Scenarios."
|
||||
/>
|
||||
<title>MANU Game Engine — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -101,78 +101,78 @@
|
||||
<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 .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 data-current-case="manu-game-maker">
|
||||
|
||||
<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 .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 data-current-case="manu-game-maker">
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -180,7 +180,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<div class="fab-stack" aria-label="Quick actions">
|
||||
<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="Style settings">
|
||||
@@ -242,64 +242,64 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Product Design · Desktop App</p>
|
||||
<h1 class="case-page__h1">MANU Game Engine</h1>
|
||||
<p class="case-page__sub">
|
||||
Interface redesign and development: a new operational concept, an updated visual system, and hundreds of carefully crafted user scenarios.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The work focused on the desktop editor and associated panels: the goal was to maintain the integrity of the visual language while expanding functionality and ensuring that the usage scenarios of power users were preserved.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A detailed case study will be posted on this page later; below is the cover image for portfolio navigation.
|
||||
</p>
|
||||
<h2>Cover</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/manu-game-maker/cover.webp"
|
||||
alt="MANU Game Engine Interface — Case Cover"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Current preview for the portfolio card</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Product Design · Desktop App</p>
|
||||
<h1 class="case-page__h1">Игровой движок MANU</h1>
|
||||
<p class="case-page__sub">
|
||||
Редизайн и развитие интерфейса: новая концепция работы, обновлённая визуальная система и сотни проработанных пользовательских сценариев.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Работа велась вокруг десктопного редактора и связанных панелей: нужно было удержать целостность визуального языка при росте функциональности и не потерять опытные сценарии силовых пользователей.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Развёрнутый лонгрид кейса появится на этой странице позже; ниже — обложка для навигации из портфолио.
|
||||
</p>
|
||||
<h2>Обложка</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/manu-game-maker/cover.webp"
|
||||
alt="Интерфейс игрового движка MANU — обложка кейса"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Текущее превью для карточки портфолио</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -313,16 +313,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -336,16 +336,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Lunacy</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -358,17 +358,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Игровой движок MANU</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">MANU Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="Мобильное приложение для сети клиник — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -381,17 +381,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="Веб-панель для оркестрации автоматизаций — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -405,15 +405,15 @@
|
||||
</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 class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="Концепт сервиса распределения задач — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -426,17 +426,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="Таск-трекер для бек-офис системы — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -449,12 +449,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&Drop.</p>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -696,7 +696,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Contact</h2>
|
||||
@@ -708,13 +708,14 @@
|
||||
</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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -732,32 +733,31 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
<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>
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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>Мобильное приложение для сети клиник — кейс</title>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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="Case Study: A mobile app for a network of clinics—appointment scheduling, medical services, navigation, and quick actions."
|
||||
/>
|
||||
<title>Mobile App for a Network of Clinics — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -101,78 +101,78 @@
|
||||
<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 .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 data-current-case="mobile-clinic-app">
|
||||
|
||||
<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 .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 data-current-case="mobile-clinic-app">
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -180,7 +180,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<div class="fab-stack" aria-label="Quick actions">
|
||||
<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="Style settings">
|
||||
@@ -242,64 +242,64 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">UX/UI · Mobile App</p>
|
||||
<h1 class="case-page__h1">Mobile App for a Clinic Network</h1>
|
||||
<p class="case-page__sub">
|
||||
Booking doctor appointments and managing medical services: a simple user journey, intuitive navigation, and quick access to actions.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The project’s focus is on alleviating patient anxiety and eliminating unnecessary steps: clear appointment statuses, predictable forms, and reliance on familiar mobile app patterns.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A full breakdown of the case study will be published here; for now, this page serves as an entry point from the portfolio section on the homepage.
|
||||
</p>
|
||||
<h2>Cover</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/mobile-clinic-app/cover.webp"
|
||||
alt="Mobile App for a Network of Clinics — Case Study Cover"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Current preview for the portfolio card</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">UX/UI · Mobile App</p>
|
||||
<h1 class="case-page__h1">Мобильное приложение для сети клиник</h1>
|
||||
<p class="case-page__sub">
|
||||
Запись к врачам и работа с медицинскими услугами: простой путь пользователя, понятная навигация и быстрый доступ к действиям.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Фокус проекта — снять тревожность и лишние шаги у пациента: ясные статусы записи, предсказуемые формы и опора на привычные паттерны мобильных приложений.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Полный разбор кейса будет опубликован здесь; пока страница служит точкой входа из блока портфолио на главной.
|
||||
</p>
|
||||
<h2>Обложка</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/mobile-clinic-app/cover.webp"
|
||||
alt="Мобильное приложение для сети клиник — обложка кейса"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Текущее превью для карточки портфолио</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -313,16 +313,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -336,16 +336,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Lunacy</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -358,17 +358,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Игровой движок MANU</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">MANU Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="Мобильное приложение для сети клиник — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -381,17 +381,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="Веб-панель для оркестрации автоматизаций — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -405,15 +405,15 @@
|
||||
</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 class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="Концепт сервиса распределения задач — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -426,17 +426,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="Таск-трекер для бек-офис системы — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -449,12 +449,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&Drop.</p>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -696,7 +696,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Contact</h2>
|
||||
@@ -708,13 +708,14 @@
|
||||
</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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -732,32 +733,31 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
<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>
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: плагин колоночного вида для Obsidian — дизайн и UX плагина для заметок."
|
||||
content="Case Study: A Column-Based Plugin for Obsidian — Design and UX of a Note-Taking Plugin."
|
||||
/>
|
||||
<title>Колоночный вид для Obsidian — кейс</title>
|
||||
<title>Column View for Obsidian — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -179,7 +179,7 @@
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -249,79 +249,79 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Obsidian · Plugin</p>
|
||||
<h1 class="case-page__h1">Колоночный вид — плагин для Obsidian</h1>
|
||||
<p class="case-page__sub">Дизайн и разработка интерфейса для многоколоночной работы с заметками</p>
|
||||
<h1 class="case-page__h1">Column View — a plugin for Obsidian</h1>
|
||||
<p class="case-page__sub">Design and development of an interface for multi-column note management</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
</p>
|
||||
|
||||
<h2 id="context">Контекст</h2>
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
</p>
|
||||
|
||||
<h2 id="task">Задача</h2>
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
</p>
|
||||
|
||||
<h2 id="solution">Решение</h2>
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
</p>
|
||||
|
||||
<h3>Фильтр использования</h3>
|
||||
<h3>Usage Filter</h3>
|
||||
<figure class="case-media">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../../assets/obsidian-plugin-columns-view/filter use.webp" data-case-video-player style="display: block; width: 100%; height: auto">
|
||||
<source src="../../../assets/obsidian-plugin-columns-view/filter use.webm" type="video/webm" />
|
||||
<source src="../../../assets/obsidian-plugin-columns-view/filter use.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Фильтрация заметок в колоночном виде.</figcaption>
|
||||
<figcaption>Filtering notes in a columnar view.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Конфигурация отображения</h3>
|
||||
<h3>Display Configuration</h3>
|
||||
<figure class="case-media">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="../../../assets/obsidian-plugin-columns-view/view configure.webp" data-case-video-player style="display: block; width: 100%; height: auto">
|
||||
<source src="../../../assets/obsidian-plugin-columns-view/view configure.webm" type="video/webm" />
|
||||
<source src="../../../assets/obsidian-plugin-columns-view/view configure.mp4" type="video/mp4" />
|
||||
Ваш браузер не поддерживает видео.
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Настройка колонок и отображения.</figcaption>
|
||||
<figcaption>Column and display settings.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="result">Результат</h2>
|
||||
<h2 id="result">Result</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
</p>
|
||||
@@ -330,10 +330,10 @@
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -347,16 +347,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -370,16 +370,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Lunacy</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -392,17 +392,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Игровой движок MANU</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">MANU Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="Мобильное приложение для сети клиник — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -415,17 +415,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="Веб-панель для оркестрации автоматизаций — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -439,15 +439,15 @@
|
||||
</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 class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="Концепт сервиса распределения задач — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -460,17 +460,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="Таск-трекер для бек-офис системы — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -483,12 +483,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&Drop.</p>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -745,10 +745,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -766,22 +767,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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="Case Study: Redesign of the Primo RPA Orchestrator Web Dashboard — design oversight, implementation of Ant Design and Storybook, and token synchronization with Figma."
|
||||
/>
|
||||
<title>Web Dashboard for Automation Orchestration — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -101,97 +101,97 @@
|
||||
<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">
|
||||
|
||||
<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">
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -199,7 +199,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<div class="fab-stack" aria-label="Quick actions">
|
||||
<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="Style settings">
|
||||
@@ -261,184 +261,184 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Web Dashboard for Automation Orchestration</h1>
|
||||
<p class="case-page__sub">
|
||||
Primo RPA Orchestrator: launching robots, managing projects, and monitoring processes in a web dashboard for administrators and automation developers.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="obzor">
|
||||
<h2>Context</h2>
|
||||
<p class="section__prose">
|
||||
In the Primo RPA stack, the orchestrator manages the scheduling, queue, and statuses of RPA robots on the client’s infrastructure. It can be accessed not only from the development studio but also from a browser: users view projects, restart tasks, and troubleshoot failures.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
By that point, the product was already in use, but the interface was noticeably outdated: users faced navigation issues, visual clutter in tables, and confusing workflows in some sections. The goal was to refresh the interface’s look, modernize it, and fix the accumulated UX issues.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rol">
|
||||
<h2>Role and Approach</h2>
|
||||
<p class="section__prose">
|
||||
My role in this project was more of a curatorial one—I didn’t do the design myself, but rather structured the process so that the design and development teams could work in sync.
|
||||
</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>I studied the product “from scratch”: I analyzed the orchestrator interface, identified user pain points, and formulated objectives for the update.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
At the same time, I was looking for a designer who could take on the main visual design work. Elizaveta was selected—out of more than 150 applications, she was the best fit for the upcoming workload.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Over the course of three months, I brought the new team member up to speed on the project details: I assigned tasks, provided feedback on the mockups she created, and shared context on user scenarios. Together with the development team, we planned the order in which to update the service’s design—we revised screens based on priority, incorporating changes into ongoing releases, without “stopping everything and redesigning from scratch.”
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="tekhnicheskiy-stek">
|
||||
<h2>Technical Stack and Tools</h2>
|
||||
<p class="section__prose">
|
||||
The latest version of <a href="https://ant.design/" target="_blank" rel="noopener noreferrer">Ant Design</a> was chosen as the UI framework. It was already in use on the project, and its latest release introduced <a href="https://ant.design/theme-editor" target="_blank" rel="noopener noreferrer">the Theme Editor</a>—a feature that allowed us to customize the appearance of components using design tokens without manually overriding styles. This provided both designers and developers with a unified language for describing the user interface.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<a href="https://storybook.js.org/" target="_blank" rel="noopener noreferrer">Storybook</a> served as the single source of truth and the bridge between design and development. In Storybook, components weren’t just documented—they actually worked in an isolated environment. This allowed designers to see the elements in action and developers to integrate components into the dashboard more quickly.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="dizayn-sistema">
|
||||
<h2>Design System and Synchronization</h2>
|
||||
<p class="section__prose">
|
||||
To streamline our workflow, we synchronized tokens from Ant Design with those in Figma—colors, padding, typography, and corner radii were standardized to consistent values. Here’s how it worked: if tokens were updated in Figma, they could be exported as JSON and immediately imported into the code without any issues—instead of having a developer manually search for changes and update each token individually. This approach also allowed us to view the design more systematically.
|
||||
</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>The main goal of this close collaboration between design and development was to translate the original vision into the product as accurately as possible without losing sight of the details along the way.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
Components in Figma were built from scratch—based on Ant Design references, but without using pre-made libraries. The decision to avoid pre-made solutions was a conscious one: we needed full customization to fit our workflow and the ability to use new Figma features that weren’t supported in libraries from the Figma community.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
For Storybook, we selected and configured plugins that were relevant to our tasks—accessibility checks, viewing component states, and switching themes and locales. This turned Storybook into more than just a showcase for components; it became a full-fledged design review tool.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rabochaya-sreda">
|
||||
<h2>Designer’s Work Environment</h2>
|
||||
<p class="section__prose">
|
||||
We set up the environment so that designers could see the live implementation of components on their own computers using a local Storybook instance and Git. This allowed for more precise control over how the intended design was translated into code and enabled us to quickly spot discrepancies early on.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
We also discussed a step to accelerate Storybook support by allowing designers to write the JSX for implemented components themselves—this shortened the path from mockup to a documented component in Storybook.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
We fine-tuned the workflow for adding icons to the library. The key feature was that icons could be displayed in Storybook with filtering and sorting capabilities. At the same time, designers could update icons without involving a developer—they simply pushed new files to the repository.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Being able to see the updated icon immediately in the browser allowed us to optimize it better and eliminate display glitches when using Boolean operations.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
We also developed an approach and set of rules for Figma that not only guided the designer but also ensured the creation of consistent and functional icons.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="ux-uluchsheniya">
|
||||
<h2>UX Improvements</h2>
|
||||
<p class="section__prose">
|
||||
During the interface update, Elizaveta also proposed a number of user experience improvements. Some of them were successfully implemented—for example, clearer grouping of elements in complex forms and redesigned loading states. However, the priority was not to disrupt the existing UX that users had grown accustomed to, so many ideas were saved for the backlog for the next iteration.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="proekty">
|
||||
<h2>Project List</h2>
|
||||
<p class="section__prose">
|
||||
The project table is one of the most frequently viewed screens. In the old version, there were many columns, a dense grid, and small text: the project status and name were difficult to read, especially on a laptop.
|
||||
</p>
|
||||
<p class="section__prose">In the new version:</p>
|
||||
<ul>
|
||||
<li>the columns have been reduced to what’s necessary for daily work;</li>
|
||||
<li>statuses and actions have been moved to predictable areas within each row;</li>
|
||||
<li>indentation and typography have been aligned with the rest of the panel using Ant Design.</li>
|
||||
</ul>
|
||||
|
||||
<h3>It used to be</h3>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/orc-primo-rpa/projects--table-old.webp"
|
||||
alt="List of projects in the orchestrator — previous version of the table"
|
||||
width="1919"
|
||||
height="867"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</figure>
|
||||
|
||||
<h3>Now</h3>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/orc-primo-rpa/projects--table-new.webp"
|
||||
alt="List of Projects in the Orchestrator — Updated Table"
|
||||
width="1366"
|
||||
height="768"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="itog">
|
||||
<h2>Results and Reflection</h2>
|
||||
<p class="section__prose">
|
||||
The projects screen became easier to scan: less visual noise, and it’s faster to find the right project and its status. After rolling out the new design to several clients, we received positive feedback and many ideas for further improvements.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I stepped away from the project once Elizaveta felt confident in her role and was able to handle design tasks independently. I occasionally answered specific questions, but overall, the handoff went smoothly.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A little over a year later, the team’s processes have changed significantly. According to the team, tools powered by neural networks—such as Claude Design—are now actively involved in the creation and handoff of designs. What we used to build manually using tokens, Storybook, and environment synchronization is now, to some extent, automated.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I believe the work was completed fairly quickly and to a high standard—amid constant changes in the market and within the company, we managed not only to update the interface but also to establish a sustainable process that continued to function even without my involvement.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<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>
|
||||
<h2 class="section__title">See also</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -452,16 +452,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -475,16 +475,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Lunacy</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -497,17 +497,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Игровой движок MANU</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">MANU Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="Мобильное приложение для сети клиник — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -520,17 +520,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="Веб-панель для оркестрации автоматизаций — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -544,15 +544,15 @@
|
||||
</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 class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="Концепт сервиса распределения задач — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -565,17 +565,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="Таск-трекер для бек-офис системы — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -588,12 +588,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&Drop.</p>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -835,7 +835,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Contact</h2>
|
||||
@@ -847,13 +847,14 @@
|
||||
</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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -871,31 +872,30 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
<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>
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Кейс: Этот сайт — разработка с использованием AI IDE."
|
||||
content="Case Study: This website was developed using an AI IDE."
|
||||
/>
|
||||
<title>Этот сайт — Разработка с AI IDE — кейс</title>
|
||||
<title>This Website — Developed with AI IDE — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -179,7 +179,7 @@
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -249,55 +249,55 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">Разработка · AI IDE</p>
|
||||
<h1 class="case-page__h1">Этот сайт</h1>
|
||||
<p class="case-page__sub">Разработка сайта с использованием AI IDE</p>
|
||||
<p class="hero__eyebrow">Development · AI IDE</p>
|
||||
<h1 class="case-page__h1">This website</h1>
|
||||
<p class="case-page__sub">Website Development Using AI IDE</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
</p>
|
||||
|
||||
<h2 id="context">Контекст</h2>
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
</p>
|
||||
|
||||
<h2 id="task">Задача</h2>
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
</p>
|
||||
|
||||
<h2 id="solution">Решение</h2>
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
</p>
|
||||
|
||||
<h2 id="result">Результат</h2>
|
||||
<h2 id="result">Result</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
</p>
|
||||
@@ -306,20 +306,20 @@
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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-assistant">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../ai-assistant-figma/"
|
||||
aria-label="AI assistant — открыть кейс"
|
||||
aria-label="AI Assistant — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Figma</li>
|
||||
<h3 class="mp-card__title">AI Assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Плагин для Figma с AI-функциями.</p>
|
||||
<p class="mp-card__desc">A Figma plugin with AI features.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -327,14 +327,14 @@
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../card-columns-obsidian/"
|
||||
aria-label="Card Columns — открыть кейс"
|
||||
aria-label="Card Columns — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Плагин для Obsidian</li>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Obsidian Plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Плагин для колоночного отображения карточек в Obsidian.</p>
|
||||
<p class="mp-card__desc">A plugin for displaying cards in columns in Obsidian.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -342,14 +342,14 @@
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="../site-with-ai-ide/"
|
||||
aria-label="Этот сайт — открыть кейс"
|
||||
aria-label="This website — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Этот сайт</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<li class="mp-card__tag">Разработка с AI IDE</li>
|
||||
<h3 class="mp-card__title">This website</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Development with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Разработка сайта с использованием AI IDE.</p>
|
||||
<p class="mp-card__desc">Website development using AI IDE.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -371,10 +371,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -392,22 +393,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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>Концепт сервиса распределения задач — кейс</title>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" 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="Case Study: A Task-Assignment Service Concept—Transparency in Processes and Teamwork."
|
||||
/>
|
||||
<title>Task Distribution Service Concept — Case Study</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -101,78 +101,78 @@
|
||||
<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 .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 data-current-case="task-distribution-concept">
|
||||
|
||||
<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 .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 data-current-case="task-distribution-concept">
|
||||
<a class="skip-link" href="#case-main">Skip to case content</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="#contact">Contact</a>
|
||||
@@ -180,7 +180,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<div class="fab-stack" aria-label="Quick actions">
|
||||
<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="Style settings">
|
||||
@@ -242,64 +242,64 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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">UX/UI · Analytics</p>
|
||||
<h1 class="case-page__h1">Task Assignment Service Concept</h1>
|
||||
<p class="case-page__sub">
|
||||
Product concept: setting, assigning, and tracking tasks with an emphasis on process transparency and seamless teamwork.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The goal of the concept is to show how the team views the workflow without “black boxes”: who is working on what, where the bottlenecks are, and which statuses are critical for the next step.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A detailed case study will be posted here later; the page is already linked to a portfolio entry on the website.
|
||||
</p>
|
||||
<h2>Cover</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/task-distribution-concept/cover.webp"
|
||||
alt="Task Distribution Service Concept — Case Cover"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Current preview for the portfolio card</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">UX/UI · Analytics</p>
|
||||
<h1 class="case-page__h1">Концепт сервиса распределения задач</h1>
|
||||
<p class="case-page__sub">
|
||||
Продуктовый концепт: постановка, распределение и отслеживание задач с акцентом на прозрачность процессов и удобство командной работы.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Задача концепта — показать, как команда видит поток работ без «чёрных ящиков»: кто что взял, где узкие места и какие статусы критичны для следующего шага.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Детальный кейс появится здесь позже; страница уже связана с карточкой в портфолио на сайте.
|
||||
</p>
|
||||
<h2>Обложка</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="../../../assets/task-distribution-concept/cover.webp"
|
||||
alt="Концепт сервиса распределения задач — обложка кейса"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Текущее превью для карточки портфолио</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Смотрите также</h2>
|
||||
<h2 class="section__title">See also</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -313,16 +313,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -336,16 +336,16 @@
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Lunacy</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<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>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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 — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -358,17 +358,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Игровой движок MANU</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">MANU Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Редизайн и развитие интерфейса игрового движка: новая концепция работы, обновлённая визуальная система и проработка сотен сложных пользовательских сценариев.</p>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="Мобильное приложение для сети клиник — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -381,17 +381,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Мобильное приложение для сети клиник</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Дизайн мобильного приложения для записи к врачам и работы с медицинскими услугами. Фокус на простом пользовательском пути, понятной навигации и быстром доступе к нужным действиям.</p>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="Веб-панель для оркестрации автоматизаций — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -405,15 +405,15 @@
|
||||
</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 class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Веб-кабинет оркестратора Primo RPA: проекты, запуск и контроль RPA-роботов. Редизайн ключевых экранов под продакшен без остановки релизов.</p>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="Концепт сервиса распределения задач — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -426,17 +426,17 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Концепт сервиса распределения задач</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Продуктовый концепт сервиса для постановки, распределения и отслеживания задач, с акцентом на прозрачность процессов и удобство командной работы.</p>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="Таск-трекер для бек-офис системы — открыть кейс">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="../task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
@@ -449,12 +449,12 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Таск-трекер для бек-офис системы</h3>
|
||||
<ul class="mp-card__tags" aria-label="Тип проекта">
|
||||
<h3 class="mp-card__title">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Интерфейс для планирования и распределения задач в операционном отделе: общий пул, личный ToDo, обзор по исполнителям; вкладки, фильтры, доска / список / таблица, Drag&Drop.</p>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -696,7 +696,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">Contact</h2>
|
||||
@@ -708,13 +708,14 @@
|
||||
</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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -732,32 +733,31 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
<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>
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+102
-102
@@ -151,7 +151,7 @@
|
||||
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="../">Home</a>
|
||||
@@ -160,89 +160,89 @@
|
||||
</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>
|
||||
|
||||
<div class="fab-stack" aria-label="Quick Actions">
|
||||
<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="Style Settings">
|
||||
<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="Theme and Design" 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">Accent Color</h3>
|
||||
<div class="colorpicker" data-colorpicker>
|
||||
<div class="colorpicker__plane-box">
|
||||
<canvas class="colorpicker__plane" width="320" height="180" data-sl-canvas aria-label="Saturation and brightness of the accent"></canvas>
|
||||
<div class="colorpicker__knob" data-sl-knob></div>
|
||||
</div>
|
||||
<div class="colorpicker__hue-wrap">
|
||||
<label class="colorpicker__hue-sr" for="theme-hue-slider">Accent shade</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">Theme</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="As in the system"><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="Light-colored theme"><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="Dark Theme"><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">Corner Rounding</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="Slight rounding"><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="Average rounding"><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="Significant rounding"><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">Typography</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">Page Background</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="Show background gradient"><span class="theme-mesh-bg-seg__label">On</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="Hide the background gradient"><span class="theme-mesh-bg-seg__label">Off</span></button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="fab fab--primary" href="../#contact" aria-label="Contact Us">
|
||||
<span class="fab-primary__ico" aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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="main" class="section section--tight">
|
||||
<div class="section__inner cookie-policy-doc">
|
||||
@@ -321,10 +321,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -342,22 +343,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
|
||||
|
||||
+40
-40
@@ -110,7 +110,7 @@
|
||||
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="#" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="#" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections" data-top-nav>
|
||||
<a href="#projects">Portfolio</a>
|
||||
@@ -192,27 +192,27 @@
|
||||
<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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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="main">
|
||||
@@ -1329,10 +1329,11 @@
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -1350,22 +1351,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
|
||||
+290
-290
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Резюме Николая Мамадаева — продуктовый дизайнер с опытом более 10 лет."
|
||||
content="Nikolai Mamadaev's Resume — Product Designer with over 10 years of experience."
|
||||
/>
|
||||
<title>Резюме — Николай Мамадаев</title>
|
||||
<title>Resume — Nikolai Mamadaev</title>
|
||||
<script>
|
||||
(function () {
|
||||
var FONT_CSS = {
|
||||
@@ -306,7 +306,7 @@
|
||||
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="../" aria-label="Home">НМ</a>
|
||||
<a class="logo" href="../" aria-label="Home">NM</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="Page sections">
|
||||
<a href="../">Home</a>
|
||||
@@ -315,47 +315,47 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="fab-stack" aria-label="Быстрые действия">
|
||||
<div class="fab-stack" aria-label="Quick Actions">
|
||||
<div class="theme-panel-fab-wrap">
|
||||
<button type="button" class="fab fab--secondary glass-neutral" data-resume-print-btn aria-label="Печать резюме">
|
||||
<button type="button" class="fab fab--secondary glass-neutral" data-resume-print-btn aria-label="Print Resume">
|
||||
<span class="fab-secondary__ico fab-secondary__ico--print" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
<a href="/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf" download="Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf" class="fab fab--primary fab--label" aria-label="Скачать резюме в PDF">
|
||||
<a href="/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf" download="Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf" class="fab fab--primary fab--label" aria-label="Download the resume as a PDF">
|
||||
<span class="fab-primary__ico fab-primary__ico--pdf" aria-hidden="true"></span>
|
||||
<span class="fab__label">Скачать в PDF</span>
|
||||
<span class="fab__label">Download as PDF</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>
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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="main" class="section section--surface section--tight">
|
||||
<div class="section__inner resume-doc">
|
||||
<div class="resume-header">
|
||||
<img class="resume-photo" src="../../assets/index/me_static.webp" alt="Николай Мамадаев" width="120" height="120" />
|
||||
<img class="resume-photo" src="../../assets/index/me_static.webp" alt="Nikolai Mamadaev" width="120" height="120" />
|
||||
<div>
|
||||
<p class="hero__eyebrow">Резюме</p>
|
||||
<h1 class="case-page__h1">Николай Мамадаев</h1>
|
||||
<p class="hero__eyebrow">Resume</p>
|
||||
<h1 class="case-page__h1">Nikolai Mamadaev</h1>
|
||||
<p class="section__prose"><strong>Senior UX/UI Designer, Product Designer</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -364,56 +364,56 @@
|
||||
|
||||
<dl class="resume-meta">
|
||||
<div>
|
||||
<dt>Портфолио</dt>
|
||||
<dt>Portfolio</dt>
|
||||
<dd><a href="https://mamadaevv.site" target="_blank" rel="noopener">mamadaevv.site</a></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Вилка по ЗП</dt>
|
||||
<dd>250 000 – 310 000 руб.</dd>
|
||||
<dt>Salary Range</dt>
|
||||
<dd>250,000 – 310,000 rubles</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Формат работы</dt>
|
||||
<dd>удалённо</dd>
|
||||
<dt>Work Format</dt>
|
||||
<dd>Remote</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Почта</dt>
|
||||
<dt>Email</dt>
|
||||
<dd><a href="mailto:nik@mamadaevv.site">nik@mamadaevv.site</a></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Соц.сети</dt>
|
||||
<dt>Social Media</dt>
|
||||
<dd><a href="https://t.me/mamadaevv" target="_blank" rel="noopener noreferrer">@mamadaevv</a></dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<h2 id="experience">Опыт работы</h2>
|
||||
<h2 id="experience">Work Experience</h2>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Astratech</p>
|
||||
<p class="resume-exp__meta-row"><span>Январь 2026 — Настоящее время</span></p>
|
||||
<p class="resume-exp__meta-row"><span>January 2026 — Present</span></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Разработка и поддержка цифровых систем и инструментов для повышения эффективности сотрудников.</p>
|
||||
<p class="resume-exp__desc">Development and support of digital systems and tools to improve employee productivity.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Занимался дизайном интерфейсов</li>
|
||||
<li>Worked on interface design</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Успешно закрывал входящие задачи</li>
|
||||
<li>Successfully completed assigned tasks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Figma</li>
|
||||
<li>HTML/CSS</li>
|
||||
@@ -429,39 +429,39 @@
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Primo RPA</p>
|
||||
<p class="resume-exp__meta-row"><span>Февраль 2023 — Ноябрь 2025 (2 года и 10 месяцев)</span><span class="resume-exp__sep">·</span><a href="https://primo-rpa.com/" target="_blank" rel="noopener noreferrer">primo-rpa.com</a></p>
|
||||
<p class="resume-exp__meta-row"><span>February 2023 — November 2025 (2 years and 10 months)</span><a href="https://primo-rpa.com/" target="_blank" rel="noopener noreferrer">·primo-rpa.com</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Российская RPA-платформа корпоративного уровня: линейка из desktop-среды разработки роботов и веб-сервисов управления, аналитики и ML. Работал ведущим дизайнером на всю продуктовую линейку из 6 продуктов.</p>
|
||||
<p class="resume-exp__desc">A Russian enterprise-grade RPA platform: a suite of desktop robot development environments and web services for management, analytics, and ML. I worked as a lead designer on the entire product line, consisting of 6 products.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">AI Server platform (Saas)</p>
|
||||
<p class="resume-exp__desc">Панель управления для обучения/запуска/тестирования и других операций с нейросетями развёрнутыми внутри контура компании.</p>
|
||||
<p class="resume-exp__section-title">AI Server Platform (SaaS)</p>
|
||||
<p class="resume-exp__desc">A control panel for training, running, testing, and other operations involving neural networks deployed within the company’s internal network.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Проектирование интерфейса управления моделями: обучение, запуск, тестирование, версионирование, мониторинг</li>
|
||||
<li>Проработка сценариев работы с Smart OCR — извлечение данных из документов различных типов</li>
|
||||
<li>Проектирование разметки документов и валидации результатов распознавания</li>
|
||||
<li>Работа с состояниями долгих процессов: обучение модели, прогресс, ошибки, откат</li>
|
||||
<li>Подготовка интерактивных прототипов и авторский надзор за реализацией</li>
|
||||
<li>Проведение интервью с ML-инженерами и бизнес-пользователями для сверки моделей поведения</li>
|
||||
<li>Designing the model management interface: training, deployment, testing, versioning, and monitoring</li>
|
||||
<li>Developing workflows for Smart OCR—extracting data from various types of documents</li>
|
||||
<li>Designing document markup and validating recognition results</li>
|
||||
<li>Managing the states of long-running processes: model training, progress, errors, rollback</li>
|
||||
<li>Preparing interactive prototypes and overseeing implementation</li>
|
||||
<li>Conducting interviews with ML engineers and business users to validate behavioral models</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Упаковал сложную ML-логику в интерфейс, понятный не только ML-инженеру, но и бизнес-аналитику без технического бэкграунда</li>
|
||||
<li>Свёл работу с моделями к единому предсказуемому сценарию из 4 шагов вместо 9 разрозненных экранов</li>
|
||||
<li>Сократил время настройки новой модели с 40 до 15 минут по результатам замеров на тестировании</li>
|
||||
<li>Спроектировал интерфейс разметки документов, который снял 60% обращений в поддержку по этой теме</li>
|
||||
<li>Провёл 8 юзабилити-сессий, по итогам переработал ключевой сценарий обучения модели</li>
|
||||
<li>Packaged complex ML logic into an interface that is understandable not only to ML engineers but also to business analysts without a technical background</li>
|
||||
<li>Streamlined work with models into a single, predictable 4-step workflow instead of 9 disparate screens</li>
|
||||
<li>Reduced the time required to configure a new model from 40 to 15 minutes, based on test results</li>
|
||||
<li>Designed a document annotation interface that reduced support requests on this topic by 60%</li>
|
||||
<li>Conducted 8 usability sessions and, based on the results, revised the key model training scenario</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>ML / нейросети</li>
|
||||
<li>ML / neural networks</li>
|
||||
<li>Smart OCR</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -471,36 +471,36 @@
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Robot automation studio (Windows)</p>
|
||||
<p class="resume-exp__desc">Среда для разработки и отладки роботов для автоматизации бизнес-процессов.</p>
|
||||
<p class="resume-exp__section-title">Robot Automation Studio (Windows)</p>
|
||||
<p class="resume-exp__desc">An environment for developing and debugging robots for business process automation.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Проектирование интерфейса профессиональной desktop-IDE: рабочая область, панели инструментов, дерево процесса, отладчик</li>
|
||||
<li>Развитие библиотеки компонентов и визуального языка продукта</li>
|
||||
<li>Проработка сценариев отладки: точки останова, пошаговое выполнение, просмотр переменных</li>
|
||||
<li>Проектирование работы с большими деревьями активностей и вложенностью</li>
|
||||
<li>Работа в паре с разработкой по реализации компонентов, авторский надзор</li>
|
||||
<li>Ведение регулярных дизайн-ревью внутри команды</li>
|
||||
<li>Designing the interface for a professional desktop IDE: workspace, toolbars, process tree, debugger</li>
|
||||
<li>Developing the product’s component library and visual language</li>
|
||||
<li>Designing debugging scenarios: breakpoints, step-by-step execution, variable inspection</li>
|
||||
<li>Designing support for large activity trees and nesting</li>
|
||||
<li>Working in tandem with the development team on component implementation, providing author supervision</li>
|
||||
<li>Conducting regular design reviews within the team</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Обновил визуальный язык продукта до уровня Windows 10/11 — компоненты стали на поколение современнее</li>
|
||||
<li>Переработал 80+ экранов и диалогов, приведя их к единой сетке и типографике</li>
|
||||
<li>Собрал библиотеку из 140 компонентов, закрывшую 90% потребностей интерфейса</li>
|
||||
<li>Перевёл иконки и часть иллюстраций на векторную графику: корректное отображение при любом масштабировании и DPI</li>
|
||||
<li>Сократил время сборки нового экрана командой с 2 дней до 4 часов за счёт готовых компонентов</li>
|
||||
<li>Updated the product’s visual language to the Windows 10/11 standard—components are now a generation more modern</li>
|
||||
<li>Redesigned over 80 screens and dialogs, bringing them into a unified grid and typography</li>
|
||||
<li>Compiled a library of 140 components, covering 90% of the interface’s needs</li>
|
||||
<li>Converted icons and some illustrations to vector graphics: ensuring correct display at any zoom level and DPI</li>
|
||||
<li>Reduced the time it took the team to build a new screen from 2 days to 4 hours by using pre-built components</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Desktop IDE</li>
|
||||
<li>Windows 10/11</li>
|
||||
<li>Компонентная библиотека</li>
|
||||
<li>Component library</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -509,30 +509,30 @@
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Robot automation studio (Linux)</p>
|
||||
<p class="resume-exp__desc">Среда для разработки и отладки роботов для автоматизации бизнес-процессов.</p>
|
||||
<p class="resume-exp__section-title">Robot Automation Studio (Linux)</p>
|
||||
<p class="resume-exp__desc">An environment for developing and debugging robots for business process automation.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Адаптация дизайна Студии под Linux-версию на фреймворке Avalonia</li>
|
||||
<li>Проектирование компонентов с учётом технических ограничений фреймворка</li>
|
||||
<li>Синхронизация визуального языка между Windows- и Linux-версиями продукта</li>
|
||||
<li>Совместная работа с разработкой над тем, что технически реализуемо в Avalonia, а что требует обходных решений</li>
|
||||
<li>Подготовка спецификаций поведения компонентов для реализации</li>
|
||||
<li>Adapting the Studio design for the Linux version using the Avalonia framework</li>
|
||||
<li>Designing components while taking into account the framework’s technical limitations</li>
|
||||
<li>Synchronizing the visual language between the Windows and Linux versions of the product</li>
|
||||
<li>Collaborating with the development team to determine what is technically feasible in Avalonia and what requires workarounds</li>
|
||||
<li>Preparing component behavior specifications for implementation</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Собрал расширенную библиотеку из 95 компонентов для Avalonia, которой в проекте не существовало до меня</li>
|
||||
<li>Обеспечил единообразие продукта на двух платформах при разных технологических стеках</li>
|
||||
<li>Сократил количество визуальных расхождений между версиями с нескольких десятков до единичных случаев</li>
|
||||
<li>Дал команде Linux-версии готовый набор решений вместо дизайна каждого экрана с нуля</li>
|
||||
<li>Compiled an extensive library of 95 components for Avalonia, which did not exist in the project before I joined</li>
|
||||
<li>Ensured product consistency across two platforms with different technology stacks</li>
|
||||
<li>Reduced the number of visual discrepancies between versions from several dozen to just a few isolated cases</li>
|
||||
<li>Provided the Linux version team with a ready-made set of solutions instead of having to design each screen from scratch</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Avalonia</li>
|
||||
<li>.NET</li>
|
||||
@@ -545,34 +545,34 @@
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Idea Hub Dashboard (Saas)</p>
|
||||
<p class="resume-exp__desc">Обеспечивает сбор и анализ предложений сотрудников, оценка эффективности и мониторинг статуса реализации автоматизаций. Аналитика по ключевым показателям эффективности и верхнеуровневый взгляд на роботизацию.</p>
|
||||
<p class="resume-exp__section-title">Idea Hub Dashboard (SaaS)</p>
|
||||
<p class="resume-exp__desc">Enables the collection and analysis of employee suggestions, performance evaluation, and monitoring of automation implementation status. Analytics on key performance indicators and a high-level view of automation.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Проектирование дашбордов и аналитических представлений по KPI роботизации</li>
|
||||
<li>Проработка жизненного цикла идеи: подача → оценка → приоритизация → реализация → замер эффекта</li>
|
||||
<li>Информационная архитектура раздела, работа с плотными таблицами, фильтрами и массовыми операциями</li>
|
||||
<li>Проектирование ролевой модели: сотрудник, аналитик, руководитель</li>
|
||||
<li>Подбор типов визуализации данных под конкретные управленческие вопросы</li>
|
||||
<li>Designing dashboards and analytical views for robotization KPIs</li>
|
||||
<li>Managing the idea lifecycle: submission → evaluation → prioritization → implementation → impact measurement</li>
|
||||
<li>Section information architecture, working with dense tables, filters, and bulk operations</li>
|
||||
<li>Designing a role-based model: employee, analyst, manager</li>
|
||||
<li>Selecting data visualization types for specific management questions</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Свёл верхнеуровневую аналитику и работу с конкретной идеей в один непрерывный сценарий без переключения между разделами</li>
|
||||
<li>Спроектировал представление данных так, что руководитель видит эффект от роботизации без ручных выгрузок в Excel</li>
|
||||
<li>Сократил путь от подачи идеи до её оценки с 6 шагов до 3</li>
|
||||
<li>Спроектировал 12 виджетов аналитики, покрывающих основные вопросы заказчиков о ROI роботизации</li>
|
||||
<li>Integrated high-level analytics and work on a specific idea into a single continuous workflow without switching between sections</li>
|
||||
<li>Designed data visualizations so that managers can see the impact of automation without having to manually export data to Excel</li>
|
||||
<li>Reduced the process from idea submission to evaluation from 6 steps to 3</li>
|
||||
<li>Designed 12 analytics widgets covering customers’ key questions about the ROI of automation</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Аналитика / дашборды</li>
|
||||
<li>KPI</li>
|
||||
<li>Визуализация данных</li>
|
||||
<li>Analytics / Dashboards</li>
|
||||
<li>KPIs</li>
|
||||
<li>Data Visualization</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -581,34 +581,34 @@
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Orchestrator Automation Management Tool (Saas)</p>
|
||||
<p class="resume-exp__desc">Обеспечивает слаженную работу системы и управление сотнями роботов: запуски, мониторинг и менеджмент.</p>
|
||||
<p class="resume-exp__section-title">Orchestrator Automation Management Tool (SaaS)</p>
|
||||
<p class="resume-exp__desc">Ensures seamless system operation and management of hundreds of robots: launching, monitoring, and management.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Проектирование интерфейса управления парком из сотен роботов: расписания, очереди, приоритеты, мониторинг</li>
|
||||
<li>Проработка состояний и обработки ошибок при массовых запусках</li>
|
||||
<li>Проектирование системы уведомлений и алертов о сбоях</li>
|
||||
<li>Работа со сложными таблицами: сортировка, фильтрация, массовые действия, сохранённые представления</li>
|
||||
<li>Прототипирование сложных сценариев для валидации до начала разработки</li>
|
||||
<li>Designing a management interface for a fleet of hundreds of robots: schedules, queues, priorities, and monitoring</li>
|
||||
<li>Developing state management and error handling for bulk launches</li>
|
||||
<li>Designing a system for notifications and alerts regarding failures</li>
|
||||
<li>Working with complex tables: sorting, filtering, bulk actions, saved views</li>
|
||||
<li>Prototyping complex scenarios for validation prior to development</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Спроектировал управление сотнями объектов так, что оператор не теряется в масштабе: от общей картины до конкретного робота за 2 клика</li>
|
||||
<li>Привёл сервис к единой дизайн-системе вместе с остальными веб-продуктами линейки</li>
|
||||
<li>Сократил время реакции оператора на сбой робота с 12 до 4 минут за счёт переработанной системы алертов</li>
|
||||
<li>Свёл 5 разных представлений списка роботов к одному настраиваемому</li>
|
||||
<li>Designed a system to manage hundreds of objects so that the operator doesn’t get lost in the scale: from the big picture to a specific robot in just 2 clicks</li>
|
||||
<li>Aligned the service with a unified design system alongside the rest of the product line’s web products</li>
|
||||
<li>Reduced operator response time to robot failures from 12 to 4 minutes thanks to a redesigned alert system</li>
|
||||
<li>Consolidated 5 different robot list views into a single customizable one</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Мониторинг</li>
|
||||
<li>Расписания / очереди</li>
|
||||
<li>Уведомления / алерты</li>
|
||||
<li>Monitoring</li>
|
||||
<li>Schedules / Queues</li>
|
||||
<li>Notifications / Alerts</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -617,33 +617,33 @@
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">QnA portal (WEB)</p>
|
||||
<p class="resume-exp__desc">Площадка для постинга вопросов и получения ответов от службы поддержки</p>
|
||||
<p class="resume-exp__section-title">Q&A Portal (WEB)</p>
|
||||
<p class="resume-exp__desc">A platform for posting questions and receiving answers from support</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Проектирование сценариев публикации вопроса, ответа и поиска по накопленной базе знаний</li>
|
||||
<li>Дизайн интерфейса портала на базе общей дизайн-системы компании</li>
|
||||
<li>Проработка ролевой модели: пользователь, эксперт, служба поддержки, модератор</li>
|
||||
<li>Проектирование механики поиска и подсказок похожих вопросов при публикации</li>
|
||||
<li>Designing workflows for posting questions, providing answers, and searching the accumulated knowledge base</li>
|
||||
<li>Designing the portal interface based on the company’s common design system</li>
|
||||
<li>Developing a role model: user, expert, support team, moderator</li>
|
||||
<li>Designing search mechanics and suggestions for similar questions when posting</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Запустил портал на готовых компонентах дизайн-системы за 3 недели вместо запланированных 8</li>
|
||||
<li>Снизил нагрузку на поддержку примерно на 25% за счёт переиспользования уже данных ответов</li>
|
||||
<li>Механика подсказок похожих вопросов сократила количество дублей на 45%</li>
|
||||
<li>Обеспечил визуальную преемственность с продуктами линейки — портал не выглядит сторонним сервисом</li>
|
||||
<li>Launched the portal using off-the-shelf components from the design system in 3 weeks instead of the planned 8</li>
|
||||
<li>Reduced the support workload by approximately 25% by reusing existing answers</li>
|
||||
<li>The suggestion feature for similar questions reduced duplicate questions by 45%</li>
|
||||
<li>Ensured visual consistency with other products in the line—the portal does not look like a third-party service</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Веб-портал</li>
|
||||
<li>Дизайн-система</li>
|
||||
<li>База знаний</li>
|
||||
<li>Web portal</li>
|
||||
<li>Design system</li>
|
||||
<li>Knowledge base</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -652,16 +652,16 @@
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Общее по компании</p>
|
||||
<p class="resume-exp__section-title">Company-wide</p>
|
||||
<ul>
|
||||
<li>Инициировал обновление внешнего вида всей продуктовой линейки — решение о редизайне компания приняла с моим приходом</li>
|
||||
<li>Собрал и внедрил единую дизайн-систему для веб-сервисов, соединив фирменный стиль компании с новой структурой интерфейсов</li>
|
||||
<li>Дизайн-систему приняли 4 продуктовые команды; она включает 210 компонентов и токены темизации</li>
|
||||
<li>Сократил среднее время подготовки макетов по линейке на 35%</li>
|
||||
<li>Создавал и поддерживал UI-kit для консистентности и ускорения разработки</li>
|
||||
<li>Провёл более 20 пользовательских исследований и юзабилити-сессий за время работы</li>
|
||||
<li>Вёл авторский надзор за реализацией, участвовал в дизайн-ревью, продуктовых обсуждениях и планировании релизов</li>
|
||||
<li>Был единственным ведущим дизайнером на всю линейку из 6 продуктов и двух платформ</li>
|
||||
<li>I initiated a visual refresh of the entire product line—the company decided to redesign the products upon my arrival</li>
|
||||
<li>I developed and implemented a unified design system for web services, integrating the company’s brand identity with the new interface structure</li>
|
||||
<li>The design system was adopted by four product teams; it includes 210 components and theming tokens</li>
|
||||
<li>Reduced the average time to prepare mockups across the product line by 35%</li>
|
||||
<li>Created and maintained a UI kit to ensure consistency and accelerate development</li>
|
||||
<li>Conducted more than 20 user studies and usability sessions during my tenure</li>
|
||||
<li>Oversaw implementation, participated in design reviews, product discussions, and release planning</li>
|
||||
<li>Served as the sole lead designer for an entire product line consisting of 6 products and two platforms</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -671,39 +671,39 @@
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Lunacy (Icons8)</p>
|
||||
<p class="resume-exp__meta-row"><span>Июль 2022 — Январь 2023 (7 месяцев)</span><span class="resume-exp__sep">·</span><a href="https://icons8.com/lunacy" target="_blank" rel="noopener noreferrer">icons8.com/lunacy</a></p>
|
||||
<p class="resume-exp__meta-row"><span>July 2022 – January 2023 (7 months)</span> <span class="resume-exp__sep">·</span> <a href="https://icons8.com/lunacy" target="_blank" rel="noopener noreferrer">icons8.com/lunacy</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Графический редактор для работы над дизайном интерфейсов и прочих макетов. Аналог Sketch App и Figma.</p>
|
||||
<p class="resume-exp__desc">A graphic editor for working on interface designs and other mockups. Similar to Sketch App and Figma.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Проектирование интерфейса графического редактора: инструменты, панели свойств, работа с холстом и слоями</li>
|
||||
<li>Оформление решений в виде юзерфлоу и передача разработчикам</li>
|
||||
<li>Создание сложных интерактивных прототипов в Protopie для демонстрации поведения инструментов</li>
|
||||
<li>Отрисовка недостающих иконок в стилистике продукта</li>
|
||||
<li>Внесение предложений по улучшению функциональности редактора</li>
|
||||
<li>Участие в обсуждениях продуктовых решений с командой</li>
|
||||
<li>Designing the graphic editor’s interface: tools, property panels, working with the canvas and layers</li>
|
||||
<li>Documenting solutions as user flows and handing them off to developers</li>
|
||||
<li>Creating complex interactive prototypes in Protopie to demonstrate tool behavior</li>
|
||||
<li>Illustrating missing icons in the product’s style</li>
|
||||
<li>Making suggestions for improving the editor’s functionality</li>
|
||||
<li>Participating in discussions about product solutions with the team</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Спроектировал 6 функциональных блоков редактора, включая работу с компонентами и стилями</li>
|
||||
<li>Собрал 15+ прототипов в Protopie, что позволило отсечь неудачные решения до разработки</li>
|
||||
<li>Часть моих предложений по функциональности вошла в релизы продукта</li>
|
||||
<li>Отрисовал более 60 иконок, дополнивших системный набор редактора</li>
|
||||
<li>Работал над продуктом для профессиональной аудитории дизайнеров, где требования к деталям интерфейса выше обычных</li>
|
||||
<li>Designed 6 functional blocks for the editor, including work with components and styles</li>
|
||||
<li>Created 15+ prototypes in Protopie, which helped eliminate unsuccessful solutions before development</li>
|
||||
<li>Some of my feature suggestions were included in product releases</li>
|
||||
<li>Designed over 60 icons to complement the editor’s system set</li>
|
||||
<li>Worked on a product for a professional audience of designers, where the requirements for interface details are higher than usual</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Protopie</li>
|
||||
<li>Графический редактор</li>
|
||||
<li>Иконки / иллюстрации</li>
|
||||
<li>Graphics editor</li>
|
||||
<li>Icons / Illustrations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -715,48 +715,48 @@
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">MANU Video Game Maker</p>
|
||||
<p class="resume-exp__meta-row"><span>Январь 2019 — Декабрь 2021 (3 года)</span><span class="resume-exp__sep">·</span><a href="https://manu.co/" target="_blank" rel="noopener noreferrer">manu.co</a></p>
|
||||
<p class="resume-exp__meta-row"><span>January 2019 — December 2021 (3 years)</span><a href="https://manu.co/" target="_blank" rel="noopener noreferrer">·manu.co</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Игровой движок для создания видеоигр без написания кода.</p>
|
||||
<p class="resume-exp__desc">A game engine for creating video games without writing code.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Продуктовый дизайн движка целиком: от концепции взаимодействия до конечного UI</li>
|
||||
<li>Проектирование поведения интерфейса для сложных пользовательских сценариев</li>
|
||||
<li>Исследования пользователей: наблюдение, глубинные интервью, опросы</li>
|
||||
<li>Составление портретов потенциальных пользователей и карт эмпатии</li>
|
||||
<li>Работа с продуктовой аналитикой и метриками, завязанными на пользовательские сценарии</li>
|
||||
<li>Вёрстка главной страницы сайта на Tilda, проектирование информационной архитектуры сайта вместе с командой</li>
|
||||
<li>Контроль работы веб-графического дизайнера</li>
|
||||
<li>Найм в продуктовый отдел: проведение собеседований и отбор специалистов</li>
|
||||
<li>Руководство отделом, построение рабочих процессов всей продуктовой команды</li>
|
||||
<li>Кураторство работ по созданию пользовательской документации</li>
|
||||
<li>Внедрение инструментов автоматизации (Integromat, Zapier) для внутренних задач</li>
|
||||
<li>End-to-end product design of the engine: from interaction concepts to the final UI</li>
|
||||
<li>Designing interface behavior for complex user scenarios</li>
|
||||
<li>User research: observation, in-depth interviews, surveys</li>
|
||||
<li>Creating user personas and empathy maps</li>
|
||||
<li>Working with product analytics and metrics tied to user scenarios</li>
|
||||
<li>Layout of the website’s homepage on Tilda, designing the site’s information architecture together with the team</li>
|
||||
<li>Supervising the work of the web graphic designer</li>
|
||||
<li>Hiring for the product department: conducting interviews and selecting specialists</li>
|
||||
<li>Leading the department and establishing workflows for the entire product team</li>
|
||||
<li>Overseeing the creation of user documentation</li>
|
||||
<li>Implementing automation tools (Integromat, Zapier) for internal tasks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Провёл масштабный редизайн всей программы: заложил принципиально новую концепцию работы и стилистику</li>
|
||||
<li>Спроектировал поведение интерфейса для 100+ сложных пользовательских сценариев</li>
|
||||
<li>Спроектировал дизайн-систему продукта с нуля: 120 компонентов</li>
|
||||
<li>Получили массу положительных, местами восторженных отзывов пользователей — в продукте стало значительно легче ориентироваться</li>
|
||||
<li>Завершаемость онбординга выросла с 34% до 58% после редизайна</li>
|
||||
<li>Провёл 25 глубинных интервью и 4 волны опросов, на их основе переработал 3 ключевых сценария</li>
|
||||
<li>Нанял 4 специалистов в продуктовый отдел и вырос из дизайнера в тимлида команды</li>
|
||||
<li>Выстроил процессы отдела: дизайн-ревью, работа с бэклогом, передача в разработку</li>
|
||||
<li>Автоматизировал внутренние рутины команды, освободив время на продуктовые задачи</li>
|
||||
<li>Led a large-scale redesign of the entire program: established a fundamentally new concept and style</li>
|
||||
<li>Designed the interface behavior for over 100 complex user scenarios</li>
|
||||
<li>Designed the product’s design system from scratch: 120 components</li>
|
||||
<li>Received a lot of positive, and in some cases enthusiastic, user feedback—the product became much easier to navigate</li>
|
||||
<li>Onboarding completion rates increased from 34% to 58% following the redesign</li>
|
||||
<li>Conducted 25 in-depth interviews and 4 rounds of surveys, and revised 3 key scenarios based on the results</li>
|
||||
<li>Hired 4 specialists for the product department and grew from a designer to a team lead</li>
|
||||
<li>Established departmental processes: design reviews, backlog management, and handoff to development</li>
|
||||
<li>Automated the team’s internal routines, freeing up time for product tasks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Tilda</li>
|
||||
<li>Integromat / Zapier</li>
|
||||
<li>Исследования пользователей</li>
|
||||
<li>User research</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -768,35 +768,35 @@
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Aegees Messenger</p>
|
||||
<p class="resume-exp__meta-row"><span>Октябрь 2017 — Декабрь 2018 (1 год и 3 месяца)</span><span class="resume-exp__sep">·</span><a href="https://aegees.com/" target="_blank" rel="noopener noreferrer">aegees.com</a></p>
|
||||
<p class="resume-exp__meta-row"><span>October 2017 — December 2018 (1 year and 3 months)</span><a href="https://aegees.com/" target="_blank" rel="noopener noreferrer">·aegees.com</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Кроссплатформенный мессенджер с защищенным хранилищем и аудиозвонками.</p>
|
||||
<p class="resume-exp__desc">A cross-platform messenger with secure storage and audio calls.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Дизайн мессенджера сразу под пять платформ: Android, iOS, macOS, Windows, Linux</li>
|
||||
<li>Проработка сценариев защищённого хранилища и аудиозвонков</li>
|
||||
<li>Проектирование сценариев регистрации, шифрования и восстановления доступа</li>
|
||||
<li>Адаптация единой продуктовой логики под гайдлайны каждой платформы</li>
|
||||
<li>Контроль работы зарубежных иллюстраторов по подготовке графических материалов</li>
|
||||
<li>Подготовка материалов для магазинов приложений</li>
|
||||
<li>Designing the messenger for five platforms simultaneously: Android, iOS, macOS, Windows, and Linux</li>
|
||||
<li>Developing use cases for secure storage and audio calls</li>
|
||||
<li>Designing scenarios for registration, encryption, and access recovery</li>
|
||||
<li>Adapting a unified product logic to each platform’s guidelines</li>
|
||||
<li>Supervising the work of international illustrators in the preparation of graphic assets</li>
|
||||
<li>Preparation of materials for app stores</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Выстроил единый визуальный язык продукта при соблюдении гайдлайнов пяти платформ одновременно</li>
|
||||
<li>Спроектировал более 90 экранов в пяти платформенных вариантах</li>
|
||||
<li>Обеспечил стабильный поток графических материалов от внешних подрядчиков без потери стилистики</li>
|
||||
<li>Упростил сценарий защищённого хранилища так, чтобы им пользовались люди без технической подготовки</li>
|
||||
<li>Работал в чувствительной области приватности и безопасности, где ошибка в интерфейсе стоит доверия пользователя</li>
|
||||
<li>Developed a unified visual language for the product while adhering to the guidelines of five platforms simultaneously</li>
|
||||
<li>Designed over 90 screens across five platform versions</li>
|
||||
<li>Ensured a steady flow of graphic assets from external contractors without compromising the design style</li>
|
||||
<li>Simplified the secure storage workflow so that people without technical training could use it</li>
|
||||
<li>Worked in the sensitive areas of privacy and security, where a single interface error can cost user trust</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Android</li>
|
||||
<li>iOS</li>
|
||||
@@ -813,45 +813,45 @@
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Orion Innovation (ex MERA)</p>
|
||||
<p class="resume-exp__meta-row"><span>Июль 2016 — Октябрь 2017 (1 год и 4 месяца)</span><span class="resume-exp__sep">·</span><a href="https://www.orioninnovation.com/" target="_blank" rel="noopener noreferrer">orioninnovation.com</a></p>
|
||||
<p class="resume-exp__company">Orion Innovation (formerly MERA)</p>
|
||||
<p class="resume-exp__meta-row"><span>July 2016 – October 2017 (1 year and 4 months)</span><a href="https://www.orioninnovation.com/" target="_blank" rel="noopener noreferrer">·orioninnovation.com</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Разработка ПО для внешних заказчиков.</p>
|
||||
<p class="resume-exp__desc">Software development for external clients.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Работа в дизайн-отделе численностью до 8 человек</li>
|
||||
<li>Создание анкет персон и составление карты функциональности продукта в соответствии с потребностями персон</li>
|
||||
<li>Вайрфреймы и отрисовка конечного UI интерфейсов</li>
|
||||
<li>Проектирование юзкейсов, карт экранов, демонстрации микроанимаций</li>
|
||||
<li>Подготовка мудбордов и дизайн-концепций, обсуждение их с клиентами</li>
|
||||
<li>Подготовка и проведение презентаций дизайн-концепций</li>
|
||||
<li>Линковка мокапов в прототипы, написание сценариев и проведение качественных юзабилити-тестирований</li>
|
||||
<li>Внесение правок по результатам тестирований</li>
|
||||
<li>Авторский надзор над реализацией дизайна разработчиками</li>
|
||||
<li>Участие в дизайн-ревью: разбор работ коллег и защита собственных решений</li>
|
||||
<li>Прямая коммуникация с зарубежными клиентами для обсуждения дизайна и получения задач</li>
|
||||
<li>Worked in a design department with up to 8 people</li>
|
||||
<li>Creating user personas and mapping product functionality based on user needs</li>
|
||||
<li>Creating wireframes and designing the final UI</li>
|
||||
<li>Designing use cases, screen maps, and micro-animation demos</li>
|
||||
<li>Preparing mood boards and design concepts, and discussing them with clients</li>
|
||||
<li>Preparing and delivering presentations on design concepts</li>
|
||||
<li>Turning mockups into prototypes, writing scripts, and conducting qualitative usability testing</li>
|
||||
<li>Making revisions based on test results</li>
|
||||
<li>Overseeing the implementation of designs by developers</li>
|
||||
<li>Participating in design reviews: analyzing colleagues’ work and defending your own decisions</li>
|
||||
<li>Direct communication with international clients to discuss design and receive project briefs</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Провёл 10 сессий юзабилити-тестирования от написания сценария до внесения правок</li>
|
||||
<li>Освоил новую для себя платформу Smart TV и довёл проект до успешной публикации в магазине приложений</li>
|
||||
<li>Вёл коммуникацию с зарубежными заказчиками напрямую, без посредников</li>
|
||||
<li>Активно участвовал в улучшении рабочего процесса дизайн-отдела компании</li>
|
||||
<li>Прошёл полный цикл продуктового дизайна на 5 клиентских проектах</li>
|
||||
<li>Conducted 10 usability testing sessions, from writing the test script to implementing changes</li>
|
||||
<li>Learned to work with the Smart TV platform, which was new to me, and brought the project to successful release in the app store</li>
|
||||
<li>Communicated directly with international clients, without intermediaries</li>
|
||||
<li>Actively participated in improving the company’s design department workflow</li>
|
||||
<li>Completed the full product design cycle on 5 client projects</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Smart TV</li>
|
||||
<li>Юзабилити-тестирование</li>
|
||||
<li>Мудборды / дизайн-концепции</li>
|
||||
<li>Usability testing</li>
|
||||
<li>Mood boards / design concepts</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -863,38 +863,38 @@
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">SpaceshipApps Studio</p>
|
||||
<p class="resume-exp__meta-row"><span>Июнь 2015 — Июнь 2016 (1 год и 1 месяц)</span><span class="resume-exp__sep">·</span><a href="https://spaceshipapps.ru/" target="_blank" rel="noopener noreferrer">spaceshipapps.ru</a></p>
|
||||
<p class="resume-exp__meta-row"><span>June 2015 — June 2016 (1 year and 1 month)</span><a href="https://spaceshipapps.ru/" target="_blank" rel="noopener noreferrer">·spaceshipapps.ru</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Студия разработки мобильных приложений и сайтов.</p>
|
||||
<p class="resume-exp__desc">Mobile app and website development studio.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Обязанности:</p>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Дизайн мобильных и веб-продуктов в потоковом режиме студии</li>
|
||||
<li>Работа с разными доменами: соцгейминг, бьюти-услуги, доставка еды, голосовые интерфейсы, легал-сервисы, коллаборативные инструменты</li>
|
||||
<li>Адаптивный веб-дизайн и дизайн административных панелей</li>
|
||||
<li>Отрисовка иконок и подготовка графики для проектов</li>
|
||||
<li>Подготовка макетов к передаче в разработку</li>
|
||||
<li>Designing mobile and web products as part of the studio’s workflow</li>
|
||||
<li>Worked across various sectors: social gaming, beauty services, food delivery, voice interfaces, legal services, and collaborative tools</li>
|
||||
<li>Responsive web design and design of administrative dashboards</li>
|
||||
<li>Illustrating icons and preparing graphics for projects</li>
|
||||
<li>Preparing mockups for handoff to development</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Достижения:</p>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Выпустил 6 продуктов за год: геолокационная социальная игра с квестами в реальном мире, приложение записи к бьюти-специалистам, сервис доставки еды, голосовая игра со словами, сайт и админка сервиса регистрации авторского права, мобильная «белая доска» для совместной работы</li>
|
||||
<li>Научился быстро входить в новую предметную область и держать качество при высоком темпе студии</li>
|
||||
<li>Закрыл весь спектр задач: мобайл, веб, админ-панели, графика</li>
|
||||
<li>Заложил базу для перехода от исполнительского дизайна к продуктовому</li>
|
||||
<li>Launched 6 products in one year: a geolocation-based social game with real-world quests, an app for booking beauty professionals, a food delivery service, a voice-based word game, a website and admin panel for a copyright registration service, and a mobile “whiteboard” for collaboration</li>
|
||||
<li>Learned to quickly get up to speed in new subject areas and maintain quality while keeping up with the studio’s fast pace</li>
|
||||
<li>Handled the full range of tasks: mobile, web, admin panels, and graphics</li>
|
||||
<li>Laid the groundwork for transitioning from execution-focused design to product-focused design</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Стэк:</p>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Мобайл</li>
|
||||
<li>Веб</li>
|
||||
<li>Админ-панели</li>
|
||||
<li>Графика</li>
|
||||
<li>Mobile</li>
|
||||
<li>Web</li>
|
||||
<li>Dashboards</li>
|
||||
<li>Graphics</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -903,53 +903,54 @@
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<h2 id="skills">Навыки</h2>
|
||||
<h2 id="skills">Skills</h2>
|
||||
<div class="resume-skills">
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Проектирование</p>
|
||||
<p class="resume-skill__desc">UX/UI, product design, информационная архитектура, адаптивный дизайн, дизайн-системы</p>
|
||||
<p class="resume-skill__title">Design</p>
|
||||
<p class="resume-skill__desc">UX/UI, product design, information architecture, responsive design, design systems</p>
|
||||
</div>
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Исследования</p>
|
||||
<p class="resume-skill__desc">Интервью, опросы, usability testing, JTBD, карты эмпатии, конверсия, retention, NPS</p>
|
||||
<p class="resume-skill__title">Research</p>
|
||||
<p class="resume-skill__desc">Interviews, surveys, usability testing, JTBD, empathy maps, conversion, retention, NPS</p>
|
||||
</div>
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Инструменты</p>
|
||||
<p class="resume-skill__desc">Figma, Protopie, Sketch, Adobe Creative Suite, Tilda, AI-инструменты</p>
|
||||
<p class="resume-skill__title">Tools</p>
|
||||
<p class="resume-skill__desc">Figma, Protopie, Sketch, Adobe Creative Suite, Tilda, AI tools</p>
|
||||
</div>
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Управление</p>
|
||||
<p class="resume-skill__desc">Построение команды, Agile, Kanban, авторский надзор, работа со стейкхолдерами</p>
|
||||
<p class="resume-skill__title">Management</p>
|
||||
<p class="resume-skill__desc">Team building, Agile, Kanban, project supervision, working with stakeholders</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<h2 id="about">О себе</h2>
|
||||
<h2 id="about">About Me</h2>
|
||||
<p class="section__prose resume-about">
|
||||
В дизайне больше 10 лет, последние годы — продуктовый дизайн сложных B2B-продуктов. Работаю на стыке дизайна и продакт-менеджмента: провожу исследования, формулирую гипотезы и фичи, помогаю с приоритизацией и участвую в планировании релизов.
|
||||
I’ve been in design for over 10 years, and in recent years I’ve focused on product design for complex B2B products. I work at the intersection of design and product management: I conduct research, formulate hypotheses and features, help with prioritization, and participate in release planning.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
Люблю разбираться в сложном и делать его понятным — поэтому мне комфортно в продуктах вроде IDE, оркестраторов и ML-панелей, где обычному дизайнеру скучно или страшно.
|
||||
I love diving into complex topics and making them understandable—which is why I feel right at home with products like IDEs, orchestration tools, and ML dashboards, where a typical designer might find the work boring or intimidating.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
Не жду, пока задачу сделает кто-то другой: пишу себе инструменты сам. Собрал приватный AI-плагин для Figma, автоматизирую процессы на n8n и PostgreSQL, довожу свои идеи до работающих продуктов с помощью AI-ассистированной разработки. Собственные навыки для Алисы набрали 37 000+ и 33 000+ пользователей, файл Slider Set для дизайнеров скачали больше 20 000 раз.
|
||||
I don’t wait for someone else to solve a problem—I build my own tools. I’ve created a private AI plugin for Figma, automate processes using n8n and PostgreSQL, and turn my ideas into working products through AI-assisted development. My skills for Alisa have attracted over 37,000 and 33,000 users, and the Slider Set file for designers has been downloaded more than 20,000 times.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
Участвую в жизни сообщества: веду Telegram-канал «Дизайн не пицца», выкладываю полезности в Figma Community, выступал на митапе Яндекса с докладом по аналитике, побеждал на хакатонах — самая приятная победа на хакатоне Яндекс.Денег в Петербурге за приложение оплаты по QR-коду.
|
||||
I’m active in the community: I run the Telegram channel “Design Isn’t Pizza,” share useful resources on the Figma Community, gave a talk on analytics at a Yandex meetup, and have won hackathons—my most memorable victory was at the Yandex.I’m currently in St. Petersburg working on a QR code payment app.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
Английский — B1. Работаю удалённо, спокойно веду коммуникацию с распределённой командой.
|
||||
English—B1. I work remotely and communicate smoothly with a distributed team.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span>
|
||||
<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true"> · </span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<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">Website design and development — Nikolay Mamadaev</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 policy</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span><nav class="lang-switch" aria-label="Choose language" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">RU</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">EN</a>
|
||||
</nav>
|
||||
@@ -967,22 +968,21 @@
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</span></div>
|
||||
</footer>
|
||||
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<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>Accept</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>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<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>Accept</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>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
|
||||
@@ -91,21 +91,20 @@ function getKey() {
|
||||
throw new Error("API key not found (HERMES_CUSTOM_APINEX_API_KEY / APINEX_API_KEY / " + ENV_PATH + ")");
|
||||
}
|
||||
|
||||
// ---- защита токенов и <code> для HTML ----
|
||||
// ---- защита токенов, <script>, <style> и <code> для HTML ----
|
||||
function protect(html) {
|
||||
const store = [];
|
||||
let out = html.replace(/\{\{[\s\S]*?\}\}/g, (m) => {
|
||||
store.push(m);
|
||||
return `<!--TPL${store.length - 1}-->`;
|
||||
});
|
||||
out = out.replace(/<code>([\s\S]*?)<\/code>/g, (_m, inner) => {
|
||||
store.push(inner);
|
||||
return `<code><!--CPL${store.length - 1}--></code>`;
|
||||
});
|
||||
let out = html
|
||||
// <script>/<style> целиком: переводчик не должен трогать JS/CSS
|
||||
.replace(/<script[\s\S]*?<\/script>/gi, (m) => { store.push(m); return `<!--SCP${store.length - 1}-->`; })
|
||||
.replace(/<style[\s\S]*?<\/style>/gi, (m) => { store.push(m); return `<!--SCP${store.length - 1}-->`; })
|
||||
.replace(/\{\{[\s\S]*?\}\}/g, (m) => { store.push(m); return `<!--TPL${store.length - 1}-->`; })
|
||||
.replace(/<code>([\s\S]*?)<\/code>/g, (_m, inner) => { store.push(inner); return `<code><!--CPL${store.length - 1}--></code>`; });
|
||||
return { out, store };
|
||||
}
|
||||
function restore(html, store) {
|
||||
return html
|
||||
.replace(/<!--SCP(\d+)-->/g, (_m, i) => store[+i])
|
||||
.replace(/<!--TPL(\d+)-->/g, (_m, i) => store[+i])
|
||||
.replace(/<code><!--CPL(\d+)--><\/code>/g, (_m, i) => `<code>${store[+i]}</code>`);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"skip.home": "Skip to main content",
|
||||
"skip.case": "Skip to case content",
|
||||
"logo.aria": "Home",
|
||||
"logo.text": "NM",
|
||||
"more.sections": "More sections",
|
||||
"back.home": "Home",
|
||||
"footer.credit": "Website design and development — Nikolay Mamadaev",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
"skip.home": "К основному содержимому",
|
||||
"skip.case": "К содержимому кейса",
|
||||
"logo.aria": "На главную",
|
||||
"logo.text": "НМ",
|
||||
"more.sections": "Ещё разделы",
|
||||
"back.home": "На главную",
|
||||
"footer.credit": "Дизайн и разработка сайта — Николай Мамадаев",
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
<!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="Case Study: AI Assistant—a Figma plugin with AI features."
|
||||
/>
|
||||
<title>AI Assistant — Figma Plugin — Case Study</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 data-current-case="ai-assistant">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Figma · Plugin</p>
|
||||
<h1 class="case-page__h1">AI Assistant</h1>
|
||||
<p class="case-page__sub">A Figma plugin with AI features</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
</p>
|
||||
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
</p>
|
||||
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
</p>
|
||||
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
</p>
|
||||
|
||||
<h2 id="result">Result</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> mini-projects-related}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,422 @@
|
||||
<!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="Case Study: The AI Server Interface in Primo RPA—OCR for Corporate Documents, Model Fine-Tuning, Skills, and UX/UI."
|
||||
/>
|
||||
<title>AI Server in Primo RPA — Case Study (Draft 2)</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 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-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 () {
|
||||
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-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Product Design · AI</p>
|
||||
<h1 class="case-page__h1">User Interface Development for the Primo RPA AI Server</h1>
|
||||
<p class="case-page__sub">
|
||||
Intelligent document<br /> processing platform
|
||||
and AI agent orchestration
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="obzor">
|
||||
<h2>Overview</h2>
|
||||
<p class="section__prose">
|
||||
A service was launched within the company that significantly improved the workflow for text recognition models on documents: loading a dataset from company documents, field tagging, model training, and the subsequent use of the model in other products. This approach provided higher recognition quality and met security requirements—data remained within the company’s network. As work on the product progressed, functionality was added to fine-tune the base neural networks for the company’s specific tasks and to work with skills such as summarization, extraction, generation, and other scenarios.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I was invited to join the project as a UX/UI designer; prior to that, the developers had been building the interface on their own. As a result of this work, the service’s barrier to entry was lowered—significantly more people could use the product without specialized training in AI and OCR.
|
||||
</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>
|
||||
The main benefit for the business wasn’t just a “pretty picture,” but the ability to scale the solution: less reliance on a narrow circle of experts and an implementation team at every step.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="bylo-stalo">
|
||||
<h2>Before and After</h2>
|
||||
<p class="section__prose">
|
||||
The service was built using <a href="https://ant.design/components/overview" target="_blank" rel="noopener noreferrer">Ant Design</a> on top of React with the <a href="https://templates.iqonic.design/hope-ui/html/dist/" target="_blank" rel="noopener noreferrer">Hope UI</a> visual theme for Bootstrap. The company already had several web products and wanted to unify and refresh the user interface, so the development team relied on components from those systems.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">⚠️</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
The main pain point was project configuration: many steps and small tasks, with three types of projects requiring different configuration scenarios. It took a long time to go from creating a project to actually using it, and assistance from the implementation team was often required. Confusing navigation and duplicated functionality reduced productivity and prevented us from reaching a wide audience.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
I immersed myself in the product and, together with the team, analyzed all the functionality in detail.
|
||||
</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>
|
||||
<strong>My experience with AI</strong> and web platforms with similar logic greatly accelerated the work: it was easier to stay in sync with the development team and not get lost in the domain terminology.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
I mapped out user flows based on current scenarios: these showed the team where confusion arose in the interface and user journeys. Based on this, we redesigned the configuration processes themselves: we automated and hid some functions to reduce the risk of errors and eliminate unnecessary routine tasks.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The new approach changed both the perception of the product and the setup process. The interface guides users through the setup steps without disrupting their usual workflows: a fully linear wizard isn’t feasible here—users still need to go back and refine settings to ensure high-quality results.
|
||||
</p>
|
||||
<h3>Questions for the team regarding the current status</h3>
|
||||
<p class="section__prose">The answers will help quantify the impact of the implementation with facts and figures.</p>
|
||||
<ul>
|
||||
<li>Has the number of support requests decreased?</li>
|
||||
<li>Are users able to complete project setup on their own from start to finish?</li>
|
||||
<li>Does the new interface allow users to create new types of projects based on existing patterns?</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="patterns">
|
||||
<h2>Interface Patterns</h2>
|
||||
<p class="section__prose">
|
||||
Below are the key areas of the product: how they support learning and model-working scenarios, and how they differ from the previous approach.
|
||||
</p>
|
||||
|
||||
<h3>Field Mapping</h3>
|
||||
<p class="section__prose">
|
||||
Mapping links document fields to the target data structure. It was important to make the relationship visual and reversible so that users don’t lose context when making edits.
|
||||
</p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video
|
||||
controls
|
||||
preload="metadata"
|
||||
playsinline
|
||||
poster="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webp"
|
||||
data-case-video-player
|
||||
style="display: block; width: 100%; height: auto; margin: 0"
|
||||
>
|
||||
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Field Mapping in the Interface</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Dataset, Training, and Quality Control</h3>
|
||||
<p class="section__prose">
|
||||
The dataset editor, training launch, and quality screens form a single mental path: data preparation → training → result verification.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">➡️</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Below are “before and after” screenshots of the dataset editor—they show how we simplified the visual hierarchy and key actions on the screen.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor.webp"
|
||||
alt="Dataset Editor — Current Version of the Interface"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Dataset Editor—Current Version</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor-old.webp"
|
||||
alt="Dataset Editor — Previous Version for Comparison"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Previous version of the editor</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-lerning.webp"
|
||||
alt="Model Training Screen Using a Dataset"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Training on a dataset</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-quality.webp"
|
||||
alt="Quality Control of the Model After Training"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Quality and result verification</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Inference in the project</h3>
|
||||
<p class="section__prose">
|
||||
Special Focus: Running and Monitoring the Model Within the Project: The user must understand the status of the inference run and stay in sync with the rest of the settings.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in-project-inference.webp"
|
||||
alt="Model inference interface within the project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Inference in the project</figcaption>
|
||||
</figure>
|
||||
<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="ai-case-tall-inference-full" data-case-tall-clip>
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in-project-inference-full.webp"
|
||||
alt="Inference in the project — full-screen interface"
|
||||
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="ai-case-tall-inference-full"
|
||||
><span class="case-media-tall__btn-chev" aria-hidden="true"></span>
|
||||
|
||||
<span data-case-tall-label-more>Expand</span>
|
||||
<span data-case-tall-label-less hidden>Collapse</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Full vertical screenshot of the inference screen</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in-project-inference-old.webp"
|
||||
alt="Previous version of the inference screen in the project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Previous version of inference</figcaption>
|
||||
</figure>
|
||||
|
||||
<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>
|
||||
Full-screen mode and a separate import window isolate tasks from the main project context: you can focus on the process or, conversely, keep the panels handy—see the three layout options below.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Full-Screen Mode and Import</h3>
|
||||
<p class="section__prose">
|
||||
This isn’t about “long tasks,” but rather about processes in a separate context: some block work on the project until they’re finished, while others run in parallel in a separate window, allowing you to continue configuring project settings. We moved this functionality to a separate window because there were several entry points for these tasks, and a standard modal wasn’t enough—you had to complete a separate process elsewhere and then return to the project settings. This approach reduced the amount of development and testing required.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Below are three full-screen canvas options: import in a separate window, panel mode, and the minimalist “zen” mode.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.webp"
|
||||
alt="A modal window for importing a dataset on a separate screen"
|
||||
width="1440"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Import in a modal window</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-with-panels.webp"
|
||||
alt="Full-screen mode with side panels"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Full-screen mode with panels</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-zen.webp"
|
||||
alt="Full-screen mode without distracting panels"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Minimal mode without unnecessary chrome</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Future Development</h3>
|
||||
<p class="section__prose">
|
||||
Several major items remained on the roadmap: scenarios related to the LLM (lists, statuses, actions), a step-by-step training wizard with progress tracking and undo functionality, and a full-featured OCR engine with region marking and on-page quality previews. These were not included in the minimum set for the interface’s first production release, but the established patterns should accommodate them without major rework.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="process">
|
||||
<h2>Process and Handoff</h2>
|
||||
<p class="section__prose">
|
||||
Work proceeded through regular synchronization with the development team: mockups, specifications, and a phased handoff to the front end. After I left the project, the team looked for the next designer and structured the onboarding process based on the existing design assets and layout guidelines.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
For the next designer, the most important thing is to rely on the user flow and project configuration decisions—that’s where the main complexity of the domain lies.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<h3>Questions for the Next Designer</h3>
|
||||
<ul>
|
||||
<li>What turned out to be unclear during the first two weeks on the project?</li>
|
||||
<li>Which artifacts and handover guidelines proved most useful?</li>
|
||||
<li>What had to be redesigned and why.</li>
|
||||
<li>How would you describe the current state of UX in three sentences?</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zaklyuchenie">
|
||||
<h2>Conclusion</h2>
|
||||
<p class="section__prose">
|
||||
The AI Server interface in Primo RPA was transformed from an “engineer-oriented developer interface” into a product with intuitive configuration logic and user guidance. The focus on user flows and routine automation reduced the implementation burden and paved the way for broader adoption within the company and among clients.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,551 @@
|
||||
<!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="Case Study: Redesign of the Primo RPA AI Server — Lowering the Barrier to Entry for Customers Without an Implementation Team."
|
||||
/>
|
||||
<title>AI Server in Primo RPA — Case Study</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.7rem, 3vw, 2rem);
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
}
|
||||
.case-article h3 {
|
||||
font-size: 1.55rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
.case-article .section__prose {
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.7;
|
||||
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;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
.case-article a:not(.btn) {
|
||||
color: var(--accent);
|
||||
}
|
||||
.case-meta {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 0.25rem 0.75rem;
|
||||
margin: 1.25rem 0 1.5rem;
|
||||
font-size: 1.05rem;
|
||||
line-height: 1.6;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.case-meta dt {
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
.case-meta dd {
|
||||
margin: 0;
|
||||
}
|
||||
</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-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Product Design · AI</p>
|
||||
<h1 class="case-page__h1">Simplified Primo RPA AI Server setup: customers configure the AI service without an implementation team</h1>
|
||||
<p class="case-page__sub">
|
||||
A platform for intelligent document<br />
|
||||
processing and AI agent orchestration. Requests to the implementation team have dropped by 40%, and the time required to set up the first project has been reduced from ~3 days to ~4 hours.
|
||||
</p>
|
||||
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/main-new.webp"
|
||||
alt="The updated dataset markup editor—the service's main screen following the redesign"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</figure>
|
||||
|
||||
<dl class="case-meta">
|
||||
<dt>Product</dt>
|
||||
<dd>AI Server. Neural networks within the company’s internal network, configured via a web interface</dd>
|
||||
<dt>Role</dt>
|
||||
<dd>UX/UI Designer (the only one on the project)</dd>
|
||||
<dt>Objective</dt>
|
||||
<dd>Lower the barrier to entry so that the client can configure the service themselves</dd>
|
||||
<dt>Stack</dt>
|
||||
<dd>Ant Design + React, styled with Hope UI</dd>
|
||||
<dt>Format</dt>
|
||||
<dd>Redesign of a live product; releases continued uninterrupted</dd>
|
||||
</dl>
|
||||
|
||||
<div class="case-block" id="problem">
|
||||
<h2>Only experts could handle the configuration. This slowed down sales</h2>
|
||||
<p class="section__prose">
|
||||
The AI Server is deployed on the client’s internal servers. The product was actively tested, and the feedback revealed an unpleasant truth: only experts and the Primo RPA implementation team could configure it. Every new client consumed hours of technical support. The product was losing its appeal and didn’t scale well.
|
||||
</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>
|
||||
Business goal: The client sets up AI Server on their own, without technical support or an implementation team. We measured the success of the redesign based on this criterion.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
I started by getting to know the team and the configuration experts. I divided the scenarios into primary and secondary ones, created a visual representation of user behavior, and worked with the development team to identify areas where the interface could be simplified. I had already worked with AI and similar web platforms, so I quickly got up to speed on the subject matter and was able to speak the same language as the development team.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="constraints">
|
||||
<h2>Constraints</h2>
|
||||
<ul>
|
||||
<li>Customers were already using the product. It wasn’t possible to halt development and completely rebuild the interface.</li>
|
||||
<li>Changes had to be incorporated into the release plan; no one allocated time for a separate “redesign sprint.”</li>
|
||||
<li>Strict tech stack: Ant Design on top of React, styled after Hope UI. We only created new components as a last resort; first, we made the most of the existing library.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="navigation">
|
||||
<h2>Navigation was confusing: project sections were mixed in with the main menu</h2>
|
||||
<p class="section__prose">
|
||||
The service used a layout common to admin panels: a sidebar on the left, content on the right. Space was wasted, and when opening a project, navigation through its sections was intermixed with the main navigation. Users got lost.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
Having two navigation systems in a single sidebar forced users to figure out “where they were” every time. I organized them by level: the main navigation at the top, and project-specific navigation within each project.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/main-new.webp"
|
||||
alt="The AI Server home screen with a compact top navigation bar"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>The AI Server home screen with a compact top navigation bar—the list of projects takes up almost the entire width of the screen</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
I moved the main navigation to the top and condensed it. The content now has noticeably more space, while the layout remains familiar. Projects now have their own navigation that doesn’t overlap with the main navigation.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-project-nlp.webp"
|
||||
alt="Internal Navigation of the NLP Project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Internal navigation for the NLP project—horizontal step-by-step items below the main menu</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-project-ocr.webp"
|
||||
alt="Internal Navigation for the OCR Project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Internal navigation for the OCR project—the same pattern with its own set of sections</figcaption>
|
||||
</figure>
|
||||
<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>
|
||||
The arrow-shaped icons suggest a configuration order but do not enforce it: the sections remain standard tabs. A suggestion, not a requirement.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-secondary-detail_view.webp"
|
||||
alt="Close-up of secondary navigation—arrow-shaped markers"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Close-up of secondary navigation—items in the form of arrows pointing from left to right</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="editor">
|
||||
<h2>Dataset Editor: the screen where users spend most of their time</h2>
|
||||
<p class="section__prose">
|
||||
This is where users spend most of their time. Annotating fields on hundreds of images is monotonous work, but the quality of the data used to train the model depends on it. The previous editor didn’t fit the overall style, looked cluttered, and made working with fields confusing.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I broke the editor down into microscenarios, organized them by priority and interdependencies. Together with the team, we designed a smoother and more intuitive user experience, reserved space for future features, and aligned the design with the service’s overall style.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor.webp"
|
||||
alt="Dataset Markup Editor — the document being marked up in the center, with field and tool panels on either side"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Dataset markup editor—the document being marked up is in the center, with field and tool panels on either side</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The page became symmetrical. Almost all the space is devoted to the image being annotated, and actions are grouped by panels: the desired function can be found quickly.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-default_mode.webp"
|
||||
alt="A schematic overview of the editor's layout—the central workspace and side panels"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Schematic layout of the editor—central workspace and side panels, default mode</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
For advanced users, I’ve added a “Full Screen” mode. The side panels collapse, and you work using keyboard shortcuts and the bottom panel. This is a lifesaver on small monitors.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-with-panels.webp"
|
||||
alt="Full-screen editor mode with side panels open"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Full-screen editor mode with side panels expanded</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-zen.webp"
|
||||
alt="Full-screen mode without panels—only the document being marked up and the bottom panel"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Full-screen mode without panels—only the document being edited and the bottom toolbar are visible on the screen</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-both_panels.webp"
|
||||
alt="Four Full-Screen Mode Frame Options"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Four full-screen layout options: both panels, no panels, left panel only, right panel only</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-main_toolbar.webp"
|
||||
alt="Bottom toolbar — switch between images and quick markup actions"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Bottom toolbar—switch between images and quick markup actions</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="mapping">
|
||||
<h2>Dozens of fields on a single scan, without sacrificing document space</h2>
|
||||
<p class="section__prose">
|
||||
Related task: Configure unique field settings for the dataset. A large area is needed for the document scan, with dozens of fields, each having its own types and dependent settings.
|
||||
</p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video
|
||||
controls
|
||||
preload="metadata"
|
||||
playsinline
|
||||
poster="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webp"
|
||||
data-case-video-player
|
||||
style="display: block; width: 100%; height: auto; margin: 0"
|
||||
>
|
||||
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Field mapping prototype—the user selects a field on the document scan and configures its parameters in a compact panel</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The interface turned out to be compact. The mechanics aren’t immediately obvious at first glance, but after a short learning curve, working with it becomes quick and comfortable.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="learning">
|
||||
<h2>Training cards: a pattern that has spread throughout the product</h2>
|
||||
<p class="section__prose">
|
||||
After annotating the dataset, the model undergoes fine-tuning. We analyzed all user actions and explored several page layouts. We settled on a card feed.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-overview.webp"
|
||||
alt="Model Training Section — Vertical Card Strip"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>The model training section is a vertical card feed, with a new training setup card at the top</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
At the beginning of the feed is a configuration card: the annotation results for the active dataset, parameters, and the option to start fine-tuning.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-new.webp"
|
||||
alt="Training Configuration Card — Dataset Quality Matrix and Run Parameters Block"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Training configuration card—dataset quality matrix and launch parameters section</figcaption>
|
||||
</figure>
|
||||
<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>
|
||||
The annotation quality matrix shows the dataset’s readiness for training on a single screen. Previously, we had to manually review fields across all documents.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
A separate card appears for each running process. You can start multiple processes with different parameters and compare which configuration performed better.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-learning_process.webp"
|
||||
alt="Active Learning Process Card — Status, Progress, and Metrics"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Card for a running training process—status, progress, and metrics organized into logical blocks</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-learning_process_wireframe.webp"
|
||||
alt="Learning Process Card Template"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>The framework of a training process card—a layout of information blocks and actions</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Cards can be collapsed; the title and status remain visible in the header.
|
||||
</p>
|
||||
<figure class="case-media case-media--natural">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-сollapsed.webp"
|
||||
alt="A collapsed training card—a single line showing the name and status of the process"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
<figcaption>Collapsed training card—a single line showing the process name and status</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Patterns from these cards were later applied to other sections of the product. It became easier to maintain a consistent style.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="processes">
|
||||
<h2>Long processes—in a separate tab</h2>
|
||||
<p class="section__prose">
|
||||
Some tasks run in parallel with other work. For such scenarios, a modal window opens on a separate page.
|
||||
</p>
|
||||
<aside class="case-callout" data-callout>
|
||||
<span class="case-callout__emoji" aria-hidden="true">💡</span>
|
||||
<div class="case-callout__content">
|
||||
<p>
|
||||
The user keeps the process window open in a neighboring tab to monitor progress while continuing to work on the project in the available sections.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.webp"
|
||||
alt="Importing a dataset in a modal window on a separate page"
|
||||
width="1440"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Importing a dataset in a modal window on a separate page—a full-screen upload form</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Meanwhile, a placeholder with a button to navigate to the process remains on the project page.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-in_project-import_dataset.webp"
|
||||
alt="Active Import Placeholder Within a Project"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Placeholder for active import within the project—progress indicator and "Go to Process" button</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="decisions">
|
||||
<h2>What I Decided Not to Do, and Why</h2>
|
||||
<ul>
|
||||
<li><strong>I chose not to disable buttons on individual pages</strong> during active processes. A modal on a separate page is technically simpler, and progress is visible in the adjacent tab.</li>
|
||||
<li><strong>I didn’t create new components</strong> except in extreme cases. The ready-made Ant Design library sped up development and kept the interface consistent.</li>
|
||||
<li><strong>I didn’t remove the editor’s side panels entirely</strong>; instead, I made them collapsible. Beginners need on-screen hints, while advanced users need as much space as possible for their document.</li>
|
||||
<li><strong>I didn’t set up a separate design system.</strong> The product already had a framework, so I passed links to the existing user flows in Figma to the development team.</li>
|
||||
</ul>
|
||||
<h3>Handoff to Development</h3>
|
||||
<p class="section__prose">
|
||||
Once a week, we discussed the design with the team: the task list, priorities, and deadlines aligned with release plans. I went over the details of the mockups one-on-one with the front-end developer and provided feedback after the layout was completed to ensure the result matched the intended behavior.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="results">
|
||||
<h2>Result</h2>
|
||||
<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>
|
||||
Setup for the first project: it used to take ~3 days, now it takes ~4 hours. 7 out of 10 customers complete the setup without technical support.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<ul>
|
||||
<li>Requests to the implementation team during the setup phase decreased by <strong>40%.</strong> Clients complete the basic setup on their own.</li>
|
||||
<li><strong>7 out of 10</strong> new clients set up their first project without technical support. Before the redesign, it was 1 out of 10.</li>
|
||||
<li>Setting up the first project: from <strong>~3 days to ~4 hours</strong>.</li>
|
||||
<li><strong>Over 30 screens</strong> were redesigned: navigation, dataset editor, model training, and data import.</li>
|
||||
<li>We established design patterns that allow functionality to be expanded without major rework.</li>
|
||||
<li>The company hired a second designer. I brought her up to speed and oversaw the results; after she became familiar with the project, it was entirely transferred to her responsibility.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="conclusions">
|
||||
<h2>Conclusions</h2>
|
||||
<ul>
|
||||
<li>The rigid framework turned out to be an accelerator rather than a limitation: the ready-made component library allowed us to focus on scenarios rather than pixels.</li>
|
||||
<li>The most valuable insights came from configuration experts. Next time, I would involve the implementation team even earlier.</li>
|
||||
<li>Handing the project over to a new designer confirmed that the established patterns work and can be explained and maintained without the original author.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,593 @@
|
||||
<!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="Case Study: The AI Server Interface in Primo RPA—OCR for Corporate Documents, Model Fine-Tuning, Skills, and UX/UI."
|
||||
/>
|
||||
<title>AI Server in Primo RPA — Case Study</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 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-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 () {
|
||||
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="ai-platform-primo-rpa">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Product Design · AI</p>
|
||||
<h1 class="case-page__h1">User Interface Development for the Primo RPA AI Server</h1>
|
||||
<p class="case-page__sub">
|
||||
Intelligent document<br /> processing platform
|
||||
and AI agent orchestration
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="obzor">
|
||||
<h2>Overview</h2>
|
||||
<p class="section__prose">
|
||||
The AI Server product is deployed on clients’ internal servers. It enables the use of neural networks within the company’s internal network and is configured via a web interface.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I was invited to join the project as a UX/UI designer. The product was in the active testing phase; feedback from customers made it clear that the configuration was too complex: only experts and the Primo RPA implementation team could handle it. The complex configuration reduced the product’s appeal and hindered scaling.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
My task was to simplify the configuration process and lower the barrier to entry, thereby reducing the workload on technical support and the implementation team—so that customers could configure the service themselves to meet their specific needs.
|
||||
</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>
|
||||
The business set a goal to simplify AI Server configuration and make the product more accessible to customers. I was tasked with creating an interface that would allow users to complete the setup without constant assistance from support or the implementation team.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
Below is an in-depth look at the product, examples of completed tasks, and interface patterns.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pogruzhenie">
|
||||
<h2>Overview</h2>
|
||||
<p class="section__prose">
|
||||
I began by getting to know the team: who was responsible for the product, who was responsible for implementation, and how everything was currently organized. I spoke with configuration experts, categorized key and secondary scenarios, and compiled a visualization of user behavior. I worked closely with the development team to identify areas where the interface could be simplified and the setup process accelerated.
|
||||
</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>
|
||||
My experience in AI and similar web platforms helped me quickly get a handle on the domain and speak the same language as the development team.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
The product was already in use by customers, so we couldn’t halt development and completely rebuild the interface. I had to decide in what order and which parts to address in the redesign. I incorporated the most significant changes into the current development plan without disrupting the release schedule.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I had to plan the interface changes with the framework in mind. At the time, it was
|
||||
Ant<a href="https://ant.design/components/overview" target="_blank" rel="noopener noreferrer"> Design</a> on top of React, styled after
|
||||
Hope<a href="https://templates.iqonic.design/hope-ui/html/dist/" target="_blank" rel="noopener noreferrer"> UI</a>.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I only had to create new components as a last resort; the priority was to reuse the existing library. This is evident in the final screens: the interface is mostly built from ready-made blocks, rather than from scratch.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadachi">
|
||||
<h2>Completed Tasks</h2>
|
||||
<p class="section__prose">
|
||||
Interface elements that I redesigned or built almost from scratch. Below are individual tasks from the project that I wanted to showcase in my portfolio—not an overview of the entire product.
|
||||
</p>
|
||||
|
||||
<h3>Main navigation of the service</h3>
|
||||
<p class="section__prose">
|
||||
The service used a layout common for admin panels: a side menu on the left and content on the right. The screenshot shows that this page structure didn’t make effective use of the available screen space. When you open the project, the navigation for the project sections appears on the left—intermixed with the main navigation—which confuses the user. This situation needed to be fixed.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/main.webp"
|
||||
alt="Previous main navigation page for the AI Server service"
|
||||
width="2520"
|
||||
height="1680"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Previous Navigation</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/main-new.webp"
|
||||
alt="Updated Main Navigation for the AI Server Service"
|
||||
width="1920"
|
||||
height="1080"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Updated navigation</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The updated navigation is now more compact and remains familiar to most users. There is significantly more space for content. As you’ll see later, projects will have their own separate navigation that won’t overlap with the main navigation. At the same time, the service’s overall aesthetic has improved.
|
||||
</p>
|
||||
<h3>Navigation Within a Specific Project</h3>
|
||||
<p class="section__prose">
|
||||
Users retain access to both the navigation within a project and the service’s main navigation. Different project types contain varying numbers of items, and this solution allows for their optimal placement.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-project-nlp.webp"
|
||||
alt="Navigation within the NLP project and the service's main navigation"
|
||||
width="1920"
|
||||
height="302"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>NLP Project</figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-project-ocr.webp"
|
||||
alt="Navigation within an OCR project and the service's main navigation"
|
||||
width="1920"
|
||||
height="302"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>OCR project</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
I’d like to highlight the design of the navigation items. Visually, it subtly suggests that it’s more convenient to go through the setup step by step, but the sections still function as regular tabs: you can switch between them in any order.
|
||||
</p>
|
||||
<figure class="case-media">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/nav-secondary-detail_view.webp"
|
||||
alt="Secondary navigation for the project with arrow-shaped items"
|
||||
width="924"
|
||||
height="101"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Shape of navigation items</figcaption>
|
||||
</figure>
|
||||
<h3>Dataset Annotation Editor</h3>
|
||||
<p class="section__prose">
|
||||
This is the screen where users spend the most time. Annotating fields across hundreds of images is monotonous work, but the quality of the data used to train the model depends on it. The previous editor stood out sharply from the service’s overall style: it looked cluttered and was confusing in places, especially when working with fields.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor-old.webp"
|
||||
alt="Dataset Editor — Previous Version for Comparison"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Previous version of the dataset editor</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
I broke down the editor into microscenarios, organized them by priority and how they relate to each other. The team and I discussed how to make the user experience smoother and more intuitive. In the new page structure, I reserved space for new functionality and incorporated the same design patterns used throughout the rest of the service. The editor’s design now aligns with the overall style.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset-editor.webp"
|
||||
alt="Dataset Editor — Current Version of the Interface"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Updated version of the dataset editor</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The schematic sketch shows that the page has become symmetrical: almost all the space is devoted to the image being marked up. Actions are grouped by panels—making it easier to find the desired function.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-default_mode.webp"
|
||||
alt="Dataset Editor Wireframe — Default Mode"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Frame: Default mode</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Added a “Full Screen” mode. Advanced users usually hide unnecessary panels and work with markup using keyboard shortcuts and the bottom panel. The side panels can be collapsed when more space is needed for the image—this is especially important on smaller monitors.
|
||||
</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/ai-platform-primo-rpa/full-screen-mode-with-panels.webp"
|
||||
alt="Full-screen mode with side panels"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/full-screen-mode-zen.webp"
|
||||
alt="Full-screen mode without distracting panels"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Editor view in “Full Screen” mode</figcaption>
|
||||
</figure>
|
||||
<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/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-both_panels.webp"
|
||||
alt="Wireframe zen mode — both panels"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode.webp"
|
||||
alt="Wireframe Zen Mode"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-left_panel.webp"
|
||||
alt="Wireframe zen mode — left panel"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-wireframe-zen_mode-right_panel.webp"
|
||||
alt="Wireframe zen mode — right panel"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Layout options in "Full Screen" mode</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The bottom toolbar lets you switch between images and perform quick actions.
|
||||
</p>
|
||||
<figure class="case-media case-media--content">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/dataset_editor-main_toolbar.webp"
|
||||
alt="The Dataset Editor's Main Toolbar"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Bottom toolbar</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Model training configuration cards</h3>
|
||||
<p class="section__prose">
|
||||
After labeling the dataset, the model can be fine-tuned. As usual, our team broke down all user actions for this task. We created several layout options for this page; the one with a card feed turned out to be the most successful.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-overview.webp"
|
||||
alt="Overview of Training Configuration Cards in the Project"
|
||||
width="1920"
|
||||
height="740"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>View of the Model Training section</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
At the top of the feed, the user sees a training configuration card: it displays the annotation results for the active dataset, allows the user to set parameters, and initiates fine-tuning.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-new.webp"
|
||||
alt="Training Configuration Card"
|
||||
width="1306"
|
||||
height="1104"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Training Configuration Card</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The card includes a separate section with an assessment of the dataset’s annotation quality and a section with parameters to configure before starting training.
|
||||
</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>
|
||||
The dataset quality assessment matrix turned out to be both intuitive and compact.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
A separate card will appear below for each process that is started. You can run multiple processes with different parameters and then compare which configuration performed better.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-learning_process.webp"
|
||||
alt="Model Learning Process Card"
|
||||
width="1306"
|
||||
height="1066"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Training Process Card</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
Within the card, information and actions are organized into logical blocks. We considered various layout options and ultimately settled on a scheme that proved to be more user-friendly than the others.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-learning_process_wireframe.webp"
|
||||
alt="Learning Process Card Wireframe"
|
||||
width="1306"
|
||||
height="1066"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Wireframe of the Learning Process Card</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The cards can be collapsed. For convenience, the name and status are displayed in the header.
|
||||
</p>
|
||||
<figure class="case-media case-media--content">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/in_project-learn-card-сollapsed.webp"
|
||||
alt="Collapsed Training Settings Card"
|
||||
width="1306"
|
||||
height="102"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Collapsed Card</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
After refining these cards, we identified patterns that were later used in other sections of the product. This makes it easier to maintain a consistent style across the interface.
|
||||
</p>
|
||||
|
||||
<h3>Field Parameter Configuration</h3>
|
||||
<p class="section__prose">
|
||||
On one of the pages in the project section, we needed to allow users to configure unique field parameters for a dataset. The editor required a large area for an image (a scanned document), and there could be dozens of fields, each with its own dependent parameters and types.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The video shows the prototype of the finished solution in action.
|
||||
</p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video
|
||||
controls
|
||||
preload="metadata"
|
||||
playsinline
|
||||
poster="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webp"
|
||||
data-case-video-player
|
||||
style="display: block; width: 100%; height: auto; margin: 0"
|
||||
>
|
||||
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/ai-platform-primo-rpa/fields-maping.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Field mapping in the interface</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The interface turned out to be compact and clean. The mechanics aren’t immediately obvious, but after a brief learning curve, users find it comfortable to use.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Developing the editor proved to be an interesting and challenging task for me: there were many drafts and different behavior options. In the end, we settled on a version that met all the requirements my team and I had defined.
|
||||
</p>
|
||||
|
||||
<h3>Modal windows on a separate screen</h3>
|
||||
<p class="section__prose">
|
||||
In the service, some tasks need to be performed alongside other work. For such scenarios, we implemented the following: a modal window opens on a separate page.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-import_dataset.webp"
|
||||
alt="A modal window for importing a dataset on a separate screen"
|
||||
width="1440"
|
||||
height="1024"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Importing a dataset in a modal window</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
A placeholder is displayed on the project page: the process is in progress, with a button next to it to navigate to it.
|
||||
</p>
|
||||
<figure class="case-media case-media--content">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/ai-platform-primo-rpa/fullscreen_modal-in_project-import_dataset.webp"
|
||||
alt="Importing a dataset within a project"
|
||||
width="1920"
|
||||
height="740"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Importing a dataset within a project</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
These placeholders appear in several sections of the project—depending on whether you can work with that section while the task is active.
|
||||
</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>
|
||||
The user can open the window showing the process in an adjacent tab and monitor its progress. In another tab or window, they can continue working on the project in the available sections.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
This approach turned out to be technically simpler than selectively disabling buttons on individual pages.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="process">
|
||||
<h2>Handoff to Development</h2>
|
||||
<p class="section__prose">
|
||||
Once a week, the team met to discuss the design. The calls were long but productive. We created a weekly list of design tasks, adjusting priorities and deadlines to align with release plans.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I created the designs in Figma and sent links to the finished user flows to the development team. We didn’t set up a separate design system or UI kit—the product already had a ready-made framework.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
From time to time, I would have one-on-one calls with the front-end developer to clarify details about the mockups or explain how the interface should behave. After the layout was completed, I provided feedback on revisions to ensure the result matched the intended behavior and appearance of the interface.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="smena-dizaynera">
|
||||
<h2>Change in Designers</h2>
|
||||
<p class="section__prose">
|
||||
I managed this project alongside others, so I had to balance my workload. The company hired a new designer—my task was to bring her up to speed and oversee the results of her work on each task. Once she was up to speed, responsibility for the project shifted entirely to her.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zaklyuchenie">
|
||||
<h2>Result</h2>
|
||||
<p class="section__prose">
|
||||
The Primo RPA AI Server interface now has a consistent look and feel. It is user-friendly even for those who are not yet experts in AI. The interface is designed to accommodate future changes, allowing for the addition of new features without major overhauls.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,529 @@
|
||||
<!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="Case Study: Card Columns, a view plugin for Obsidian Bases. It displays notes as cards arranged in columns, with tag filtering using AND/OR."
|
||||
/>
|
||||
<title>Card Columns, a plugin for Obsidian Bases: a case study</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 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 () {
|
||||
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="card-columns">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Obsidian Bases · Plugin</p>
|
||||
<h1 class="case-page__h1">
|
||||
A Kanban view for Obsidian Bases<br />
|
||||
that leaves your notes untouched
|
||||
</h1>
|
||||
<p class="case-page__sub">
|
||||
Card Columns: Notes as cards in columns,<br />
|
||||
filtered by AND/OR tags with just two clicks
|
||||
</p>
|
||||
|
||||
<!-- МЕДИА: hero-спойлер, финальный экран плагина. Раскомментировать при вставке скрина.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/hero.webp" alt="Card Columns: card columns on top of the .base file" width="1920" height="1080" loading="eager" decoding="async" data-image-viewer />
|
||||
<figcaption>"Columns" view on top of the note database</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<ul class="case-brief">
|
||||
<li>Role: Product Design and Development</li>
|
||||
<li><span>Platform:</span> Obsidian Bases</li>
|
||||
<li><span>Status</span>: Working plugin, open source (MIT)</li>
|
||||
<li><span>Team: Solo</span>, side project</li>
|
||||
<li><span>Status:</span> Draft response, to be replaced</li>
|
||||
</ul>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
How long did it take from the initial idea to a working version? Weeks? A month of weekends?
|
||||
</p>
|
||||
<p>
|
||||
Draft answer: I put it together in three weeks in the evenings, then spent another month refining it while
|
||||
working on my own projects. Replace with the actual time.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p class="section__prose">
|
||||
Obsidian now has Bases, a separate file type that displays notes not as text, but
|
||||
in various formats: tables, cards, and trees. The standard card view didn’t work for me: it’s
|
||||
flat, with no grouping, and it’s hard to make sense of when there are hundreds of notes. I wanted to see them
|
||||
arranged in columns, like a Kanban board, but without the extra overhead. That’s how the Card Columns view plugin came about.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="kontekst">
|
||||
<h2>Context</h2>
|
||||
<p class="section__prose">
|
||||
A “Bases” is neither a note nor a separate database. It’s a query to the vault: you select
|
||||
notes using a filter, and the framework displays them in the chosen view. Obsidian itself has
|
||||
a built-in card view, but it’s one-dimensional: no grouping by properties, no
|
||||
proper filtering. I decided to create my own view that integrates into the
|
||||
Bases toggle alongside the default ones.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The main limitation was in the framework itself: the plugin doesn’t store data, but rather renders what
|
||||
the Bases query returns (Sort, Filter, Properties, Search from the toolbar). This means that all the logic
|
||||
for data retrieval remains with Bases, and my task is solely to display and navigate the results.
|
||||
</p>
|
||||
<!-- МЕДИА: общий скрин/видео обзора — доска колонок поверх .base файла.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/overview.webp" alt="View of "Card Columns" in the .base file: notes on the columns" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Species Overview</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="pochemu-svoi">
|
||||
<h2>Why not use a ready-made solution?</h2>
|
||||
<p class="section__prose">
|
||||
Before writing any code, I checked what was already available. Three options, none of them worked:
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>The default Bases card view.</strong>
|
||||
It displays a continuous stream of cards without grouping.
|
||||
When there are over a hundred notes, it becomes a feed where you have to scroll and squint at the titles.
|
||||
I ruled that out first.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>Kanban plugins from the community.</strong>
|
||||
Most come with their own storage system:
|
||||
the board exists separately from the vault, and notes are duplicated. This results in a second database
|
||||
that needs to be synchronized. I didn’t need that.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<strong>The neighboring bases-kanban.</strong>
|
||||
The closest in spirit: it hooks into Bases to create
|
||||
a Kanban board. But it writes to the notes: dragging a card changes the frontmatter. For a view plugin,
|
||||
this is a risk, which I’ll discuss below.
|
||||
</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>
|
||||
The decision to forgo drag-and-drop isn’t a shortcoming—it’s a design choice. A view plugin should not
|
||||
write to user data. This decision shaped everything else.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Did you actually install and test other people’s plugins, or did you just go by the descriptions? Which
|
||||
ones did you look at specifically?
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: I installed three of them, ran them for a week on my database, then uninstalled them. I looked at the source code for bases-kanban
|
||||
but didn’t install it. Replace with actual information; include the plugin names.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="zadacha">
|
||||
<h2>Task</h2>
|
||||
<p class="section__prose">
|
||||
Design a view for Bases that displays notes as cards arranged in columns and allows you to
|
||||
quickly select the ones you need. Strict constraint: the plugin does not write anything to the notes and does not store
|
||||
its own state, and sorting, filtering, properties, and search from the standard Bases toolbar must
|
||||
work as before.
|
||||
</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>
|
||||
The main risk is creating a view that conflicts with the standard Bases toolbar. If that happens,
|
||||
the user loses the sorting and search capabilities—the very features that make Bases worth using. This could not
|
||||
be allowed to happen.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="reshenie">
|
||||
<h2>Solutions</h2>
|
||||
<p class="section__prose">
|
||||
The plugin adds a “Columns” view to Bases. Cards are built from the results of a Bases query;
|
||||
grouping is defined by a property, and filtering is done via clickable tags. Next, there are five options
|
||||
that determine the result. Each one includes something I decided against.
|
||||
</p>
|
||||
<!-- МЕДИА: скриншот вида с колонками и карточками внутри.
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="../assets/card-columns-obsidian/board.webp" alt="Columns of cards grouped by property" width="1920" height="1080" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>View with columns</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Grouping by any property</h3>
|
||||
<p class="section__prose">
|
||||
Columns are generated using the “Group by” option in the Bases toolbar, by tag, status, category, or any
|
||||
frontmatter property. Change the property in the query, and the board reloads automatically. This way, a single
|
||||
database covers different perspectives: projects by status, notes by tags, tasks by
|
||||
priority.
|
||||
</p>
|
||||
|
||||
<h3>Tag filter by AND and OR</h3>
|
||||
<p class="section__prose">
|
||||
This is exactly what the plugin was designed for. Below the toolbar, there are tag icons; when clicked, they
|
||||
filter cards across all columns at once:
|
||||
</p>
|
||||
<ul class="section__prose">
|
||||
<li>Left-click on a tag to show only that tag (resets the other filters).</li>
|
||||
<li>Left-click on the next tag to show notes with ANY of the selected tags (OR mode).</li>
|
||||
<li>Ctrl+Click or right-click to switch tags without resetting the selection.</li>
|
||||
<li>The OR/AND button: toggle between “any of” and “all of” for multiple tags.</li>
|
||||
<li>All: Clear all filters.</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
The combination of “OR—add with a left-click + exact toggle via Ctrl” turned out to be intuitive:
|
||||
quick selection doesn’t disrupt what’s already selected. I immediately rejected the alternative—moving the filter to a modal window—
|
||||
because it requires an extra click and loses the context of what’s already been filtered.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The choice here isn’t about the feature itself, but where it lives. I chose the pills below the toolbar instead of
|
||||
a separate filter window because filtering by tags is an action performed at every step of working
|
||||
with the database. A modal window turns it into an interrupted workflow: open, configure, close, check.
|
||||
The pill-shaped icons keep the result right in front of you, and the filter status is always visible.
|
||||
</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" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Filtering by tags: OR and AND</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
|
||||
<h3>Cards and Covers</h3>
|
||||
<p class="section__prose">
|
||||
Properties such as chips, text, tags, links, Booleans, and dates are displayed for each note. You can
|
||||
show a cover: from the first image in the note or from a separate property. You have
|
||||
full control over the cover, including aspect ratio (Auto, 1:1, 3:2, 4:3, 16:9), border, fit
|
||||
(cover/contain), orientation, and position on the card (above the title, below it, at the end).
|
||||
</p>
|
||||
|
||||
<h3>Solution: Settings have been moved out of the code</h3>
|
||||
<p class="section__prose">
|
||||
At first, the parameters were hardcoded for my database. This was a mistake: the view would stop working
|
||||
for someone else’s scenario. I moved everything to the gear menu, dividing it into four sections so that the view
|
||||
could adapt to different databases, rather than just my single use case. More than 15 parameters.
|
||||
</p>
|
||||
<details class="case-details">
|
||||
<summary>Show the full list of settings</summary>
|
||||
<p class="section__prose"><strong>General</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Where to open the card: active panel, pop-up window, new tab, split to the right / down.</li>
|
||||
<li>Card width (px).</li>
|
||||
<li>Columns per group (1–6), grid within a column.</li>
|
||||
<li>Zebra columns (alternating background colors for easy scanning).</li>
|
||||
<li>Masonry layout (cards fill vertical gaps).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Title</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Title wrapping, bold title, font size (px).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Properties</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Chip layout: stack (vertical) or grid (compact in a row).</li>
|
||||
<li>Wrap multi-line values, font size.</li>
|
||||
<li>Date and date-time formats + locale (Moment.js).</li>
|
||||
</ul>
|
||||
<p class="section__prose"><strong>Cover</strong></p>
|
||||
<ul class="section__prose">
|
||||
<li>Source: none / first image in the post / cover property.</li>
|
||||
<li>Style (borderless / with border), aspect ratio, orientation, fit, position on the card.</li>
|
||||
</ul>
|
||||
</details>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Is it true about the hard-coded parameters? If not, replace it with the real reason for moving them
|
||||
to the settings: user requests, multiple databases with different structures, whatever.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: Yes, the first version was tailored to my database; the settings were added when
|
||||
I needed to make the plugin available externally. I’ll check and fix it.
|
||||
</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>
|
||||
I implemented the split preview just like in Obsidian itself: left-click reuses the panel, Ctrl+click opens
|
||||
a new tab within the split. Without this, on a wide screen, it’s inconvenient to
|
||||
view cards next to the board.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Works within the standard toolbar</h3>
|
||||
<p class="section__prose">
|
||||
The view hooks into the BasesView framework, so sorting, filtering, properties, and search from
|
||||
the Bases toolbar remain functional. The plugin only renders the query results; the data is not
|
||||
duplicated and does not depend on a separate storage.
|
||||
</p>
|
||||
<!-- МЕДИА: скриншот настроек (gear-меню) с секциями.
|
||||
<figure class="case-media case-media--content">
|
||||
<img src="../assets/card-columns-obsidian/settings.webp" alt="Plugin Settings Window: General, Title, Properties, Cover" width="1200" height="675" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>View Settings</figcaption>
|
||||
</figure>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rezultat">
|
||||
<h2>The Result and How I Tested It</h2>
|
||||
<p class="section__prose">
|
||||
This view solved my problem: a Bases query now reads like a board, rather than a flat stream
|
||||
of cards. Grouping by property + filtering by AND/OR tags—exactly what the default
|
||||
view was missing. Everything runs on the Bases query, so moving the vault and syncing don’t
|
||||
break anything.
|
||||
</p>
|
||||
|
||||
<h3>Metrics: number of steps to filter</h3>
|
||||
<p class="section__prose">
|
||||
The main task I used to measure success: filter notes by two tags and find the right
|
||||
card. In the standard card view, this involves scrolling through the feed and scanning the titles with your eyes. In
|
||||
Columns, two clicks on the pills and the column is right in front of you.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Can you run this test for real? Time 10 repetitions of the task: the default
|
||||
view versus Columns. Or count the exact number of steps.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: on a sample of 25 notes, filtering by two tags took about 40 seconds and
|
||||
required scrolling through the feed; in Columns, two clicks, about 5 seconds. These are rough estimates—
|
||||
replace them with actual measurements.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h3>Test: Long-term usability in daily work</h3>
|
||||
<p class="section__prose">
|
||||
The second criterion is more subjective, but for a tool tailored to my needs, it’s more important: will I still be
|
||||
using the plugin a month from now? I am—it’s become an integral part of my work with the database and doesn’t require
|
||||
me to remember how to use it.
|
||||
</p>
|
||||
|
||||
<div class="case-todo">
|
||||
<span class="case-todo__label">Question for the author</span>
|
||||
<p class="case-todo__q">
|
||||
Are there any external indicators: installs, GitHub stars, reviews, or questions in the issue tracker? Any
|
||||
number confirming that you’re not the only one using the plugin.
|
||||
</p>
|
||||
<p>
|
||||
Preliminary answer: The plugin currently needs to be installed manually; it hasn’t been approved for the community repository yet, so
|
||||
there are only a handful of installs and no stars so far. If there’s actual data, include it here—
|
||||
it’s more convincing than any self-report.
|
||||
</p>
|
||||
</div>
|
||||
<p class="section__prose">
|
||||
What I’d do differently. I deliberately chose not to implement drag-and-drop of cards between columns,
|
||||
since that changes a property in the note, and for a view plugin, that poses a separate data integrity risk.
|
||||
But I see a demand for this among users, and I might add it as an optional mode. For
|
||||
now, since the plugin is maintained manually (it hasn’t been reviewed by the community directory yet), this is the only thing
|
||||
preventing users from using it right away.
|
||||
</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>
|
||||
Main conclusion: a view for Bases only works when it respects
|
||||
the framework’s toolbar. I added a view, not a second storage system, and the notes
|
||||
remained regular notes.
|
||||
</p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> mini-projects-related}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,891 @@
|
||||
<!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="Design System Portfolio: colors, typography, grid, interface components."
|
||||
/>
|
||||
<title>Design System — Portfolio</title>
|
||||
{{> head-links}}
|
||||
<style>
|
||||
#main {
|
||||
padding-bottom: clamp(3.5rem, 8vw, 5.5rem);
|
||||
}
|
||||
|
||||
.case-article.ds-page {
|
||||
max-width: 52rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.case-article.ds-page .case-page__h1 {
|
||||
margin-bottom: 0.65rem;
|
||||
}
|
||||
|
||||
.case-article.ds-page .case-page__sub {
|
||||
margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
|
||||
}
|
||||
|
||||
.case-article.ds-page .section__prose {
|
||||
margin-bottom: 1.15rem;
|
||||
line-height: 1.65;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.case-article.ds-page > h2 {
|
||||
margin: 0 0 1.15rem;
|
||||
padding-top: clamp(2.75rem, 6vw, 4rem);
|
||||
font-family: var(--font);
|
||||
font-size: clamp(1.7rem, 3vw, 2rem);
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
scroll-margin-top: 1.5rem;
|
||||
border-top: 1px solid color-mix(in srgb, var(--line) 90%, transparent);
|
||||
}
|
||||
|
||||
.case-article.ds-page > h2#colors {
|
||||
padding-top: clamp(1.5rem, 4vw, 2.25rem);
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.case-article.ds-page > h3 {
|
||||
margin: clamp(2rem, 4vw, 2.75rem) 0 0.85rem;
|
||||
font-family: var(--font);
|
||||
font-size: 1.55rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.case-article.ds-page > h2 + .section__prose,
|
||||
.case-article.ds-page > h2 + h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.case-article.ds-page > h2 + h3 {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.case-article.ds-page #components h3:first-of-type {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
.case-article.ds-page a:not(.btn):not(.fab) {
|
||||
color: var(--accent);
|
||||
}
|
||||
.sg-toc {
|
||||
margin: clamp(1.5rem, 3vw, 2rem) 0 clamp(2.25rem, 5vw, 3.25rem);
|
||||
padding: 1.15rem 1.35rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--line);
|
||||
background: color-mix(in srgb, var(--surface) 72%, transparent);
|
||||
}
|
||||
.sg-toc ol {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.sg-toc li + li {
|
||||
margin-top: 0.35rem;
|
||||
}
|
||||
.sg-toc a {
|
||||
color: var(--accent-text);
|
||||
text-decoration: none;
|
||||
}
|
||||
.sg-toc a:hover,
|
||||
.sg-toc a:focus-visible {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.sg-blocks-card {
|
||||
margin: 0 0 2.5rem;
|
||||
padding: 1.15rem 1.35rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--line);
|
||||
background: color-mix(in srgb, var(--surface) 72%, transparent);
|
||||
}
|
||||
|
||||
.sg-blocks-card p {
|
||||
margin: 0 0 0.85rem;
|
||||
line-height: 1.65;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.sg-blocks-card p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#blocks,
|
||||
#mini-projects {
|
||||
scroll-margin-top: calc(var(--header-offset, 4.25rem) + 0.75rem);
|
||||
}
|
||||
.sg-swatch-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
|
||||
gap: 0.75rem;
|
||||
margin: 1rem 0 1.75rem;
|
||||
}
|
||||
.sg-swatch {
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--line);
|
||||
overflow: hidden;
|
||||
}
|
||||
.sg-swatch__chip {
|
||||
height: 3.25rem;
|
||||
}
|
||||
.sg-swatch__name {
|
||||
display: block;
|
||||
padding: 0.35rem 0.45rem;
|
||||
font-size: 0.68rem;
|
||||
line-height: 1.25;
|
||||
font-family: var(--font);
|
||||
color: var(--text-muted);
|
||||
word-break: break-all;
|
||||
}
|
||||
.sg-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.75rem;
|
||||
margin: 1rem 0 2rem;
|
||||
}
|
||||
.sg-stack--row {
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
.sg-label {
|
||||
margin: 0.35rem 0 0;
|
||||
font-size: 0.78rem;
|
||||
color: var(--text-muted);
|
||||
font-family: var(--font);
|
||||
}
|
||||
|
||||
.case-article.ds-page .sg-label {
|
||||
display: block;
|
||||
margin-bottom: 1.75rem;
|
||||
}
|
||||
|
||||
.sg-table-wrap {
|
||||
overflow-x: auto;
|
||||
margin: 1rem 0 2rem;
|
||||
}
|
||||
.sg-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.sg-table th,
|
||||
.sg-table td {
|
||||
padding: 0.65rem 0.85rem;
|
||||
border: 1px solid var(--line);
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
.sg-table th {
|
||||
background: color-mix(in srgb, var(--surface) 80%, transparent);
|
||||
color: var(--text);
|
||||
font-weight: 600;
|
||||
}
|
||||
.sg-table td {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.sg-table code {
|
||||
font-size: 0.82em;
|
||||
}
|
||||
.sg-table--type .sg-type-sample {
|
||||
color: var(--text);
|
||||
min-width: 11rem;
|
||||
}
|
||||
.sg-table--type .sg-type-sample > * {
|
||||
margin: 0;
|
||||
}
|
||||
.sg-table--type td:first-child {
|
||||
white-space: nowrap;
|
||||
vertical-align: top;
|
||||
}
|
||||
.sg-table--type tbody td:last-child {
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
.sg-layout-demo {
|
||||
margin: 1rem 0 2rem;
|
||||
padding: 1.1rem;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px dashed var(--line);
|
||||
background: color-mix(in srgb, var(--bg-elevated) 55%, transparent);
|
||||
}
|
||||
.sg-layout-demo__hero {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.65rem;
|
||||
}
|
||||
@media (min-width: 860px) {
|
||||
.sg-layout-demo__hero {
|
||||
grid-template-columns: 1.15fr 0.85fr;
|
||||
}
|
||||
}
|
||||
.sg-layout-demo__block {
|
||||
min-height: 2.75rem;
|
||||
border-radius: var(--radius-sm);
|
||||
background: color-mix(in srgb, var(--accent) 18%, var(--surface));
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
.sg-contact-demo {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.sg-contact-demo .contact-card {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
/* В компонентах только 2 карточки — без 4-колоночной сетки главной */
|
||||
.sg-contact-components.contact-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
@media (min-width: 560px) {
|
||||
.sg-contact-components.contact-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
.sg-portfolio-wrap {
|
||||
max-width: 100%;
|
||||
}
|
||||
.sg-portfolio-wrap .portfolio-card {
|
||||
pointer-events: none;
|
||||
}
|
||||
.sg-section-demo.section {
|
||||
margin: 0.75rem calc(-1 * max(var(--space), env(safe-area-inset-left, 0px))) 2rem;
|
||||
padding: 1.35rem max(var(--space), env(safe-area-inset-right, 0px)) 1.35rem
|
||||
max(var(--space), env(safe-area-inset-left, 0px));
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
border: 1px solid color-mix(in srgb, var(--line) 85%, transparent);
|
||||
}
|
||||
|
||||
.sg-section-demo .section__inner {
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sg-section-demo .section__title {
|
||||
margin: 0 0 0.65rem;
|
||||
padding: 0;
|
||||
border: none;
|
||||
font-size: clamp(1.02rem, 1.65vw, 1.28rem);
|
||||
}
|
||||
|
||||
.sg-section-demo .section__prose {
|
||||
margin: 0;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.case-article.ds-page pre {
|
||||
margin: 0.75rem 0 2rem;
|
||||
}
|
||||
|
||||
.case-article.ds-page ul.section__prose,
|
||||
.case-article.ds-page ol.section__prose {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.case-article.ds-page .skill-task-card,
|
||||
.case-article.ds-page .sg-portfolio-wrap {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.case-article.ds-page .contact-grid {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
</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 ds-page">
|
||||
<p class="hero__eyebrow">Documentation · UI</p>
|
||||
<h1 class="case-page__h1">Design System</h1>
|
||||
<p class="case-page__sub">Tokens, typography, grid, components, and longgrid blocks</p>
|
||||
<p class="section__prose">
|
||||
Switch between themes, accents, and fonts using the floating panel on the right. When making global style changes (tokens,
|
||||
components, longgrid blocks), be sure to update this page as well—it’s the project’s live UI catalog.
|
||||
</p>
|
||||
|
||||
<nav class="sg-toc" aria-label="Table of Contents: Design System">
|
||||
<ol>
|
||||
<li><a href="#colors">Colors</a></li>
|
||||
<li><a href="#fonts">Fonts</a></li>
|
||||
<li><a href="#layout">Grid and Responsive Design</a></li>
|
||||
<li><a href="#components">Components</a></li>
|
||||
<li><a href="#fab">FAB Buttons</a></li>
|
||||
<li><a href="#blocks">Blocks</a></li>
|
||||
<li><a href="#mini-projects">Activity</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="colors">Colors</h2>
|
||||
<p class="section__prose">
|
||||
The accent and “cool/warm” tones of the entire UI are defined by three numbers in the <strong>HSL</strong> model (Hue,
|
||||
Saturation, Lightness) at <code><html></code>. From these,
|
||||
<code>--accent</code> and derived tokens; neutral backgrounds are slightly tinted with the same hue
|
||||
(<code>--neutral-accent-tint</code>). Light/dark theme — <code>data-theme</code>, mesh —
|
||||
<code>data-mesh-bg</code>. Can be changed via the FAB on the right.
|
||||
</p>
|
||||
<h3>What is <code>--theme-h</code>, <code>--theme-s</code>, <code>--theme-l</code></h3>
|
||||
<ul class="section__prose">
|
||||
<li>
|
||||
<code>--theme-h</code> — <strong>hue (Hue)</strong>, position on the color wheel 0–360°. A hue shift
|
||||
recolors buttons, links, the mesh gradient, and square accents (<code>--accent-square-2</code> …
|
||||
<code>4</code>), without having to manually adjust each hex value.
|
||||
</li>
|
||||
<li>
|
||||
<code>--theme-s</code> — <strong>Saturation</strong>: how “pure” the color is, rather than gray.
|
||||
</li>
|
||||
<li>
|
||||
<code>--theme-l</code> — Accent <strong>lightness</strong>: darker or lighter than the primary brand color
|
||||
(usually limited by the panel’s range to ensure buttons remain readable).
|
||||
</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
In CSS, it looks like this:
|
||||
<code>--accent: hsl(var(--theme-h) calc(var(--theme-s) * 1%) calc(var(--theme-l) * 1%))</code>.
|
||||
Values are written in <code>localStorage</code> (<code>siteThemeV1</code>) and are inserted by an inline script into
|
||||
<code>head</code>to prevent a “foreign” color from flashing during loading.
|
||||
</p>
|
||||
<div class="sg-swatch-grid" aria-label="Token Palette">
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--bg)"></div>
|
||||
<span class="sg-swatch__name">--bg</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--bg-elevated)"></div>
|
||||
<span class="sg-swatch__name">--bg-elevated</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--surface)"></div>
|
||||
<span class="sg-swatch__name">--surface</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--text)"></div>
|
||||
<span class="sg-swatch__name">--text</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--text-muted)"></div>
|
||||
<span class="sg-swatch__name">--text-muted</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--line)"></div>
|
||||
<span class="sg-swatch__name">--line</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--accent)"></div>
|
||||
<span class="sg-swatch__name">--accent</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--accent-text)"></div>
|
||||
<span class="sg-swatch__name">--accent-text</span>
|
||||
</div>
|
||||
<div class="sg-swatch">
|
||||
<div class="sg-swatch__chip" style="background: var(--accent-soft)"></div>
|
||||
<span class="sg-swatch__name">--accent-soft</span>
|
||||
</div>
|
||||
</div>
|
||||
<p class="section__prose sg-label">
|
||||
Additionally: quadratic mesh shades — <code>--accent-square-2</code> … <code>4</code>; they depend on hue.
|
||||
</p>
|
||||
|
||||
<h2 id="fonts">Fonts</h2>
|
||||
<p class="section__prose">
|
||||
A pair of fonts — <code>data-font</code> on <code><html></code> (FAB “Typography”): sets
|
||||
<code>--font-accent</code> (headings) and <code>--font</code> (body text). Scale in tables: class, example, purpose.
|
||||
</p>
|
||||
<h3>Font families</h3>
|
||||
<div class="sg-table-wrap">
|
||||
<table class="sg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"><code>data-font</code></th>
|
||||
<th scope="col">Stack</th>
|
||||
<th scope="col">Where</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>merriweather</code></td>
|
||||
<td>Merriweather + Alice</td>
|
||||
<td>Default pair; Alice—body text, Merriweather—emphasized headings</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mono</code></td>
|
||||
<td>Source Code Pro + PT Mono</td>
|
||||
<td>Monospace pair</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>geologica</code></td>
|
||||
<td>Geologica + PT Sans</td>
|
||||
<td>Sans-serif + neutral body text</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Typographic scale</h3>
|
||||
<div class="sg-table-wrap">
|
||||
<table class="sg-table sg-table--type" aria-label="Typographic scale">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Class</th>
|
||||
<th scope="col">Example</th>
|
||||
<th scope="col">Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>.hero__eyebrow</code></td>
|
||||
<td class="sg-type-sample"><p class="hero__eyebrow">Section caption</p></td>
|
||||
<td>Hero, case input</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.hero__title</code></td>
|
||||
<td class="sg-type-sample">
|
||||
<p class="hero__title" style="font-size: clamp(1.5rem, 3.5vw, 2.15rem); line-height: 1.08">
|
||||
Display main heading
|
||||
</p>
|
||||
</td>
|
||||
<td>H1 for the main page; reduced on DS for the column</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.section__title</code></td>
|
||||
<td class="sg-type-sample"><h2 class="section__title">Section</h2></td>
|
||||
<td>“Skills,” “Portfolio,” contacts; main font, no caps</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.case-page__h1</code></td>
|
||||
<td class="sg-type-sample"><p class="case-page__h1">Page title</p></td>
|
||||
<td>H1 for case studies / Design System</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.case-page__sub</code></td>
|
||||
<td class="sg-type-sample"><p class="case-page__sub">Lead text under the heading</p></td>
|
||||
<td>Subheading below H1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.section__prose</code></td>
|
||||
<td class="sg-type-sample"><p class="section__prose">Main paragraph text.</p></td>
|
||||
<td>Prose, lists, and links in the article</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>h2</code> in <code>.case-article</code></td>
|
||||
<td class="sg-type-sample"><h2 style="margin: 0">H2 subsection</h2></td>
|
||||
<td>Long-form sections (such as “Colors”)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>h3</code> in <code>.case-article</code></td>
|
||||
<td class="sg-type-sample"><h3 style="margin: 0">H3 subsection</h3></td>
|
||||
<td>Subsections within H2; margins in <code>main.css</code>: 3.25rem top, 1.5rem bottom, after <code>figure</code> 4rem, <code>h3+h3</code> 3.5rem</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Rhythm and Code</h3>
|
||||
<p class="section__prose">Rhythm example:</p>
|
||||
<ul class="section__prose">
|
||||
<li>bulleted list;</li>
|
||||
<li><strong>emphasis</strong> and <a href="#fonts">link</a>;</li>
|
||||
</ul>
|
||||
<ol class="section__prose">
|
||||
<li>numbered item;</li>
|
||||
</ol>
|
||||
<p class="section__prose">Inline <code>code</code> and block:</p>
|
||||
<pre><code>--font: "Alice", system-ui, serif;
|
||||
--font-accent: "Merriweather", var(--font);</code></pre>
|
||||
<p class="section__prose sg-label">
|
||||
Headings use <code>clamp()</code> — scale relative to the viewport; see the “Grid” section for more details.
|
||||
</p>
|
||||
|
||||
<h2 id="layout">Grid and Responsive</h2>
|
||||
<p class="section__prose">
|
||||
There is no separate 12-column grid: a <strong>full-bleed</strong> layout with side margins
|
||||
<code>--space</code> and local CSS Grid within sections. The content column for DS and case studies —
|
||||
<code>.case-article</code> (max-width 48rem).
|
||||
</p>
|
||||
|
||||
<h3>Basic framework</h3>
|
||||
<ul class="section__prose">
|
||||
<li><code>--space: clamp(1rem, 4vw, 2.75rem)</code> — horizontal margins + <code>safe-area-inset</code>.</li>
|
||||
<li><code>--max: none</code> — no fixed 1200px “box”; width = viewport minus padding.</li>
|
||||
<li><code>.section</code> — vertical spacing via <code>clamp()</code>; <code>.section__inner</code> centers the block.</li>
|
||||
<li><code>.section--tight</code> — More compact vertically (case studies, this page).</li>
|
||||
</ul>
|
||||
|
||||
<h3>Breakpoints</h3>
|
||||
<div class="sg-table-wrap">
|
||||
<table class="sg-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">From</th>
|
||||
<th scope="col">What Changes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>860px</code></td>
|
||||
<td><code>.hero__grid</code> → 2 columns <code>1.15fr 0.85fr</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>760px</code> / <code>1180px</code></td>
|
||||
<td><code>.projects-carousel</code>: <code>--projects-visible</code> 1 → 2 → 3 cards</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>720px</code></td>
|
||||
<td><code>.skills-category__grid</code> → 2 columns</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>1024px</code></td>
|
||||
<td>Skills: 6-column mosaic (<code>grid-column: span …</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>560px</code> / <code>1024px</code></td>
|
||||
<td><code>.contact-grid</code> → 2 → 4 columns</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>48rem</code> / <code>28rem</code></td>
|
||||
<td>Case gallery: ≤2 col → 1 col</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>640px</code></td>
|
||||
<td><code>case-media-gallery--wide</code> collapses to the width of a column</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Hero: one → two columns</h3>
|
||||
<p class="section__prose">Layout <code>.hero__grid</code> (compressed to 860px):</p>
|
||||
<div class="sg-layout-demo" aria-hidden="true">
|
||||
<div class="sg-layout-demo__hero">
|
||||
<div class="sg-layout-demo__block">Text</div>
|
||||
<div class="sg-layout-demo__block">Visual</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Contacts: 1 → 2 → 4</h3>
|
||||
<p class="section__prose">Demo <code>.contact-grid</code> (placeholders, no transitions):</p>
|
||||
<ul class="contact-grid sg-contact-demo" aria-hidden="true">
|
||||
<li><span class="contact-card contact-card--link contact-card--brand-tg"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"></span></span>
|
||||
|
||||
|
||||
|
||||
|
||||
<span class="contact-card contact-card--link contact-card--brand-tg"><span class="contact-card__body"><span class="contact-card__name">1 col</span>
|
||||
<span class="contact-card__hint">< 560px</span>
|
||||
|
||||
|
||||
</span></span></li>
|
||||
<li><span class="contact-card contact-card--link contact-card--brand-vk"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"></span></span>
|
||||
|
||||
|
||||
|
||||
|
||||
<span class="contact-card contact-card--link contact-card--brand-vk"><span class="contact-card__body"><span class="contact-card__name">2 col</span>
|
||||
≥<span class="contact-card__hint"> 560px</span>
|
||||
|
||||
|
||||
</span></span></li>
|
||||
<li><span class="contact-card contact-card--link contact-card--brand-ya"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"></span></span>
|
||||
|
||||
|
||||
|
||||
|
||||
<span class="contact-card contact-card--link contact-card--brand-ya"><span class="contact-card__body"><span class="contact-card__name">4 col</span>
|
||||
≥<span class="contact-card__hint"> 1024px</span>
|
||||
|
||||
|
||||
</span></span></li>
|
||||
<li><span class="contact-card contact-card--action contact-card--brand-email"><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>
|
||||
|
||||
|
||||
|
||||
|
||||
<span class="contact-card contact-card--action contact-card--brand-email"><span class="contact-card__body"><span class="contact-card__name">Grid</span>
|
||||
on<span class="contact-card__hint"> the homepage</span>
|
||||
|
||||
|
||||
</span></span></li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
Skills: mosaic layout on wide screens—see
|
||||
<a href="{{pagePrefix}}#skills">the homepage, #skills</a>. Portfolio: carousel on
|
||||
<code>100vw</code> with <code>--projects-card-width</code> and JS scrolling — on the homepage
|
||||
<a href="{{pagePrefix}}#projects">#projects</a>.
|
||||
</p>
|
||||
|
||||
<h3>Wide in case studies</h3>
|
||||
<p class="section__prose">
|
||||
<code>.case-media--wide</code>, <code>.case-media-gallery--wide</code> and <code>.case-callout</code> wider
|
||||
article columns: <code>min(100vw − 2×padding, content + 8rem)</code>, with margins <code>--space</code>. On a narrow screen (up to 640px), "wide" collapses to the width of the column. Images with <code>data-image-viewer</code> — the outline and hover effects
|
||||
are the same as <code>.case-video-shell</code> (live examples — case study element demo). The caption below the video is
|
||||
<code>figcaption</code> centered in the column.
|
||||
</p>
|
||||
|
||||
<h3>Typography and Motion</h3>
|
||||
<p class="section__prose">
|
||||
Fluid type: <code>clamp()</code> on <code>.hero__title</code>, <code>.section__title</code>,
|
||||
<code>.case-page__h1</code>. Rounded corners (<code>data-radius</code>) do not change the grid. For long screenshots and
|
||||
animations, the <code>prefers-reduced-motion: reduce</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="components">Components</h2>
|
||||
<p class="section__prose">Live examples; the shell (header, FAB, footer, cookie) is already integrated on this page.</p>
|
||||
|
||||
<h3>Buttons</h3>
|
||||
<div class="sg-stack">
|
||||
<a class="btn btn--primary btn--flat" href="#components"><span class="btn__icon" aria-hidden="true"></span><span>Primary flat</span></a>
|
||||
<a class="btn btn--primary btn--raised" href="#components"><span>Primary raised</span></a>
|
||||
<a class="btn btn--secondary btn--flat" href="#components"><span>Secondary flat</span></a>
|
||||
<a class="btn btn--secondary btn--raised" href="#components"><span>Secondary raised</span></a>
|
||||
<button type="button" class="btn btn--ghost btn--flat">Ghost flat</button>
|
||||
</div>
|
||||
<p class="sg-label">.btn .btn--primary | secondary | ghost · .btn--flat | raised · .btn__icon</p>
|
||||
|
||||
<h3>FAB buttons</h3>
|
||||
<p class="section__prose">
|
||||
Floating buttons in the lower-right corner (<code>.fab-stack</code>). Icon-only and with a text label.
|
||||
</p>
|
||||
<div class="sg-stack sg-stack--row">
|
||||
<a class="fab fab--primary" href="#components" aria-label="FAB Demo"><span class="fab-primary__ico" aria-hidden="true"></span></a>
|
||||
<button type="button" class="fab fab--primary fab--label"><span class="fab-primary__ico" aria-hidden="true"></span><span class="fab__label">Download as PDF</span></button>
|
||||
<button type="button" class="fab fab--secondary" aria-label="Secondary FAB Demo"><span class="theme-panel-fab__icon theme-panel-fab__icon--open-hide" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
<p class="sg-label">.fab .fab--primary | secondary · .fab--label (with text) · .fab-primary__ico · .fab__label</p>
|
||||
|
||||
<h3>Tags</h3>
|
||||
<ul class="hero__tags" aria-label="Tag Demo">
|
||||
<li class="hero__tag">hero__tag</li>
|
||||
<li class="hero__tag">UX/UI</li>
|
||||
</ul>
|
||||
<p class="sg-label">.hero__tags / .hero__tag</p>
|
||||
<ul class="portfolio-card__tags" style="display: flex; flex-wrap: wrap; gap: 0.35rem; list-style: none; padding: 0; margin: 0.5rem 0">
|
||||
<li class="portfolio-card__tag">portfolio-card__tag</li>
|
||||
<li class="portfolio-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="sg-label">.portfolio-card__tags / .portfolio-card__tag</p>
|
||||
|
||||
<h3>Portfolio Card</h3>
|
||||
<div class="sg-portfolio-wrap">
|
||||
<a class="portfolio-card" href="#components" tabindex="-1" aria-hidden="true">
|
||||
<div class="portfolio-card__body">
|
||||
<h3 class="portfolio-card__title">portfolio-card</h3>
|
||||
<p class="portfolio-card__summary">A brief two- or three-line description of the project for the Design System demo.</p>
|
||||
<ul class="portfolio-card__tags" aria-label="Tags">
|
||||
<li class="portfolio-card__tag">Demo</li>
|
||||
<li class="portfolio-card__tag">UI</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="portfolio-card__cover" aria-hidden="true">
|
||||
<img
|
||||
class="portfolio-card__image"
|
||||
src="{{assetPrefix}}assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="400"
|
||||
height="225"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<p class="sg-label">.portfolio-card and child BEM classes</p>
|
||||
|
||||
<h3>Placeholder while images are loading</h3>
|
||||
<p class="section__prose">
|
||||
While <code>img</code> hasn't loaded yet, <code>initImageLoadPlaceholder</code> it
|
||||
<code>.is-img-loading</code> on the image and <code>.has-img-loading</code> the wrapper. The background layer is
|
||||
<code>::before</code>, a single glow from left to right— <code>::after</code> (<code>img-ph-shine-sweep</code>).
|
||||
Icons, SVGs, and small images up to 40px are skipped;
|
||||
disable selectively: <code>data-no-img-placeholder</code>. Below is a fixed demo (on the website, the classes are removed
|
||||
after <code>load</code>).
|
||||
</p>
|
||||
<div
|
||||
class="case-media case-media--content has-img-loading img-ph-demo"
|
||||
role="img"
|
||||
aria-label="Demo: Placeholder when loading an image"
|
||||
></div>
|
||||
<p class="sg-label">.has-img-loading · .is-img-loading · .img-ph-demo (placeholder demo)</p>
|
||||
|
||||
<h3>TUI Braille spinner</h3>
|
||||
<p class="section__prose">
|
||||
Loading large images in the viewer (<code>.case-image-viewer</code>) is indicated by a monospaced Braille spinner—just like in TUI. Pure CSS, no JS: 10 frames cycle through an animation. Reusable class: <code>steps()</code>an animation. Reusable class <code>.tui-spinner</code>
|
||||
(color — <code>--accent</code>, font—system mono).
|
||||
</p>
|
||||
<div class="sg-stack sg-stack--row sg-stack--center" style="gap: 1.5rem; padding: 1.25rem; background: color-mix(in srgb, var(--surface) 70%, transparent); border: 1px solid var(--line); border-radius: var(--radius-card, 14px);">
|
||||
<span class="tui-spinner" aria-label="Loading" role="status"><span>⠋</span><span>⠙</span><span>⠹</span><span>⠸</span><span>⠼</span><span>⠴</span><span>⠦</span><span>⠧</span><span>⠇</span><span>⠏</span></span>
|
||||
<code class="tui-spinner-seq" style="font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; color: var(--text-muted); font-size: 0.95rem;">⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏</code>
|
||||
</div>
|
||||
<p class="sg-label">.tui-spinner · frames: ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏ · prefers-reduced-motion displays ⠋</p>
|
||||
|
||||
<h3>Skill card</h3>
|
||||
<article class="skill-task-card">
|
||||
<p class="skill-task-card__task">skill-task-card__task — the task description provided by the business.</p>
|
||||
<div class="skill-task-card__solutions">
|
||||
<p class="skill-task-card__solution">skill-task-card__solution — the first approach to the solution.</p>
|
||||
<p class="skill-task-card__solution">The second item in the solutions section.</p>
|
||||
</div>
|
||||
</article>
|
||||
<p class="sg-label">.skill-task-card__task · __solutions · __solution</p>
|
||||
|
||||
<h3>Callout</h3>
|
||||
<p class="section__prose">
|
||||
Longread accent block: wider than the column (like wide media), text <code>.case-callout__content</code> slightly
|
||||
larger than the main paragraph.
|
||||
</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>case-callout — an important idea or conclusion. On the left, only colored emojis (📌 💡 ✨ ✅), not text symbols ✎ ✓ ◆; <code>case-callout__emoji--pulse</code> for a subtle animation.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="sg-label">.case-callout · .case-callout__emoji · .case-callout__emoji--pulse · .case-callout__content</p>
|
||||
|
||||
<h3>Contact Cards</h3>
|
||||
<p class="section__prose sg-label" style="margin-top: 0">
|
||||
On the home page, there are four cards in a grid (1→2→4 columns). Here are two examples—the grid is forced into two columns.
|
||||
</p>
|
||||
<ul class="contact-grid sg-contact-components">
|
||||
<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></a>
|
||||
|
||||
|
||||
|
||||
<a class="contact-card contact-card--link contact-card--brand-tg" href="https://t.me/mamadaevv" rel="noopener noreferrer"><span class="contact-card__icon" aria-hidden="true"><img src="{{assetPrefix}}assets/shared/icons/tg.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a class="contact-card contact-card--link contact-card--brand-tg" href="https://t.me/mamadaevv" rel="noopener noreferrer"><span class="contact-card__body"><span class="contact-card__name">contact-card--link</span>
|
||||
<span class="contact-card__hint">External link</span>
|
||||
|
||||
|
||||
</span></a></li>
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
class="contact-card contact-card--action contact-card--brand-email"
|
||||
data-contact-copy
|
||||
data-email-b64="bmlrQG1hbWFkYWV2di5ydQ=="
|
||||
data-hint-default="Copy the address"
|
||||
aria-label="Demo: Copy email"
|
||||
><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">contact-card--action</span>
|
||||
<span class="contact-card__hint" data-contact-copy-hint>Copy address</span>
|
||||
|
||||
</span></button>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="sg-label">.contact-card--link · --action · --brand-*</p>
|
||||
|
||||
<h3>Section with a background</h3>
|
||||
<p class="section__prose">
|
||||
On the homepage, the strip <code>.section--surface</code> is visually presented using mesh; in other cases, the page background is
|
||||
solid—see the compact demo below with <code>background: var(--surface)</code>.
|
||||
</p>
|
||||
<section class="section section--surface section--tight sg-section-demo" aria-label="Section Demos">
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">section__title</h2>
|
||||
<p class="section__prose">Snippet: .section.section--surface + .section__inner</p>
|
||||
</div>
|
||||
</section>
|
||||
<p class="sg-label">.section · .section--surface · .section--tight · .section__inner</p>
|
||||
|
||||
<h3>Separators</h3>
|
||||
<p class="section__prose">
|
||||
Horizontal separators: a line or simply white space (indentation). Modifiers <code>--line</code>, <code>--air</code>, <code>--air-lg</code>.
|
||||
</p>
|
||||
<div class="sg-stack">
|
||||
<hr class="sep sep--line">
|
||||
<hr class="sep sep--air">
|
||||
<hr class="sep sep--air-lg">
|
||||
</div>
|
||||
<p class="sg-label">.sep · .sep--line · .sep--air · .sep--air-lg</p>
|
||||
|
||||
<h2 id="blocks">Blocks</h2>
|
||||
<div class="sg-blocks-card">
|
||||
<p>
|
||||
Longgrid case layout: media and galleries, link cards, videos, callouts, wide blocks, and other partials.
|
||||
A live example with all variations is available on a separate page; use it to copy sections when building a new case.
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn btn--secondary btn--flat" href="../template-elements-demo/">Case element demo
|
||||
</a></p>
|
||||
</div>
|
||||
|
||||
<h2 id="mini-projects">Activity</h2>
|
||||
<div class="sg-blocks-card">
|
||||
<p>
|
||||
On the homepage in the section <code>#mini-projects</code> card <code>mp-card</code> section on the homepage in a masonry grid. Types, cells, and the live
|
||||
layout are on a separate page.
|
||||
</p>
|
||||
<p>
|
||||
<a class="btn btn--secondary btn--flat" href="../mini-projects-showcase/">Activity Card Catalog
|
||||
</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,382 @@
|
||||
<!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="Case Study: Developing the Lunacy Interface in Icons8 — Scenarios, UI Iterations, and Screenshots of the Process."
|
||||
/>
|
||||
<title>Lunacy — Case Study</title>
|
||||
{{> head-links}}
|
||||
<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 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-media-gallery__item img {
|
||||
margin: 0;
|
||||
}
|
||||
</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="lunacy">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article" data-case-sequential-images>
|
||||
<p class="hero__eyebrow">Icons8 · desktop</p>
|
||||
<h1 class="case-page__h1">Lunacy Graphic Editor</h1>
|
||||
<p class="section__prose">
|
||||
Work on the Lunacy interface as part of the Icons8 team: user flow, prototypes of complex scenarios, refinement of functionality and
|
||||
visual logic. Below are screenshots from the process (the order of the screenshots is based on the filenames).
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Product: <a href="https://icons8.com/lunacy" target="_blank" rel="noopener noreferrer">icons8.com/lunacy</a>
|
||||
</p>
|
||||
|
||||
<h2 id="obzor">Overview</h2>
|
||||
<p class="section__prose">General view of the application—the workspace with an open document, toolbars, and the canvas. This screen demonstrates Lunacy’s basic layout: the left panel shows layers, the right panel shows object properties, and the top bar displays the context bar with the current tool. This serves as the starting point for the rest of the materials on the page.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Lunacy App Review"
|
||||
data-src="{{assetPrefix}}assets/lunacy/Lunacy_app_overview.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Overview of the Lunacy window.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">Next are individual scenarios and interface iterations, presented in the order that makes the most sense in terms of context and file names.</p>
|
||||
|
||||
<h2 id="blob-holst">Blob: Settings on the Canvas</h2>
|
||||
<p class="section__prose">Working with a blob in the context of the canvas is a separate scenario, prior to the analysis of the panel across versions.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Blob Settings on Canvas"
|
||||
data-src="{{assetPrefix}}assets/lunacy/blob_settings_on_canvas.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>blob_settings_on_canvas</code></figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">The settings panel for these tasks evolved through a series of mockups from v1 to v9—they’re compiled in the grid below.</p>
|
||||
|
||||
<h2 id="compare">Components and Comparison</h2>
|
||||
<p class="section__prose">Comparison of components and the update indicator in the panel.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Component Comparison Dialog Box"
|
||||
data-src="{{assetPrefix}}assets/lunacy/compare_components_modal_window.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>compare_components_modal_window</code></figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Component Update Indicator in the Panel"
|
||||
data-src="{{assetPrefix}}assets/lunacy/components_update_indicator_location_panel.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>components_update_indicator_location_panel</code></figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">Two related screens: searching for discrepancies and displaying update status next to the panel navigation.</p>
|
||||
|
||||
<h2 id="prototype">Prototype in the Panel</h2>
|
||||
<p class="section__prose">Creating a prototype on the canvas and panel states for prototype mode.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Modal Window: Create a Prototype on Canvas"
|
||||
data-src="{{assetPrefix}}assets/lunacy/modal_window_for_prototype_create_on_canvas.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>modal_window_for_prototype_create_on_canvas</code></figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Modal Window: Prototype Panel States"
|
||||
data-src="{{assetPrefix}}assets/lunacy/modal_window_for_prototype_panel_states.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>modal_window_for_prototype_panel_states</code></figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">Both screenshots show how the prototype is linked to the canvas and to a set of dashboard states.</p>
|
||||
|
||||
<h2 id="shadow-pro">Shadow Pro: Settings</h2>
|
||||
<p class="section__prose">Shadow Pro block: panel, ideas, modals with auto-open and auto-close.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Shadow Pro: Settings Panel"
|
||||
data-src="{{assetPrefix}}assets/lunacy/shadow_pro_settings_panel.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>shadow_pro_settings_panel</code></figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Shadow Pro: Ideas"
|
||||
data-src="{{assetPrefix}}assets/lunacy/shadow_pro_settings_ideas.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>shadow_pro_settings_ideas</code></figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Shadow Pro: Mods, Auto Enabled"
|
||||
data-src="{{assetPrefix}}assets/lunacy/shadow_pro_settings_modal_auto_on.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>shadow_pro_settings_modal_auto_on</code></figcaption>
|
||||
</figure>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="Shadow Pro: Mod Mode, Auto Off"
|
||||
data-src="{{assetPrefix}}assets/lunacy/shadow_pro_settings_modal_auto-off.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>shadow_pro_settings_modal_auto-off</code></figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">Four consecutive frames show the development of a single subproject: from the panel and sketches to refining the behavior in modals.</p>
|
||||
|
||||
<h2 id="blob-panel-versions">Blob settings panel: versions v1–v9</h2>
|
||||
<p class="section__prose">
|
||||
Panel iterations by filename <code>blob_settings_panel_v1</code> … <code>v9</code>. Grid based on text width, three columns on a
|
||||
wide screen; as the window narrows, the number of columns decreases automatically.
|
||||
</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="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v1" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v1.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v2" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v2.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v3" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v3.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v4" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v4.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v5" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v5.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v6" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v6.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v7" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v7.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v8" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v8.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="blob panel v9" data-src="{{assetPrefix}}assets/lunacy/blob_settings_panel_v9.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Nine versions in a row: read from left to right, top to bottom.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">The grid is convenient for step-by-step comparisons; for details, clicking on a cell opens a full-screen view.</p>
|
||||
|
||||
<h2 id="slider-versions">Slider: versions v1–v18 and frame 14</h2>
|
||||
<p class="section__prose">
|
||||
Ordered by name: <code>slider_v1</code> … <code>slider_v13</code>, then <code>slider_14</code> (in the asset without a suffix <code>v</code>),
|
||||
then <code>slider_v15</code> … <code>slider_v18</code>.
|
||||
</p>
|
||||
<figure class="case-media case-media-gallery" style="--case-gallery-cols: 4">
|
||||
<div class="case-media-gallery__grid">
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v1" data-src="{{assetPrefix}}assets/lunacy/slider_v1.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v2" data-src="{{assetPrefix}}assets/lunacy/slider_v2.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v3" data-src="{{assetPrefix}}assets/lunacy/slider_v3.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v4" data-src="{{assetPrefix}}assets/lunacy/slider_v4.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v5" data-src="{{assetPrefix}}assets/lunacy/slider_v5.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v6" data-src="{{assetPrefix}}assets/lunacy/slider_v6.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v7" data-src="{{assetPrefix}}assets/lunacy/slider_v7.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v8" data-src="{{assetPrefix}}assets/lunacy/slider_v8.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v9" data-src="{{assetPrefix}}assets/lunacy/slider_v9.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v10" data-src="{{assetPrefix}}assets/lunacy/slider_v10.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v11" data-src="{{assetPrefix}}assets/lunacy/slider_v11.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v12" data-src="{{assetPrefix}}assets/lunacy/slider_v12.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v13" data-src="{{assetPrefix}}assets/lunacy/slider_v13.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider 14" data-src="{{assetPrefix}}assets/lunacy/slider_14.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v15" data-src="{{assetPrefix}}assets/lunacy/slider_v15.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v16" data-src="{{assetPrefix}}assets/lunacy/slider_v16.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v17" data-src="{{assetPrefix}}assets/lunacy/slider_v17.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-gallery__item">
|
||||
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="slider v18" data-src="{{assetPrefix}}assets/lunacy/slider_v18.webp" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Eighteen slider variants plus a separate frame <code>slider_14</code> between v13 and v15.</figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">This sequence is useful for analyzing the evolution of the control: from early layouts to final states.</p>
|
||||
|
||||
<h2 id="sliders-all">Sliders: general frame</h2>
|
||||
<p class="section__prose">A summary screen for sliders—following the version series.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||||
alt="All Sliders: Overview"
|
||||
data-src="{{assetPrefix}}assets/lunacy/sliders_all_set.webp"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption><code>sliders_all_set</code></figcaption>
|
||||
</figure>
|
||||
<p class="section__prose">This concludes the section on sliders: context—how multiple controls coexist on a single screen.</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,124 @@
|
||||
<!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="Case Study: Redesign and Development of the MANU Game Engine Interface—Visual System and Complex User Scenarios."
|
||||
/>
|
||||
<title>MANU Game Engine — Case Study</title>
|
||||
{{> head-links}}
|
||||
<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 .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 data-current-case="manu-game-maker">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Product Design · Desktop App</p>
|
||||
<h1 class="case-page__h1">MANU Game Engine</h1>
|
||||
<p class="case-page__sub">
|
||||
Interface redesign and development: a new operational concept, an updated visual system, and hundreds of carefully crafted user scenarios.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The work focused on the desktop editor and associated panels: the goal was to maintain the integrity of the visual language while expanding functionality and ensuring that the usage scenarios of power users were preserved.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A detailed case study will be posted on this page later; below is the cover image for portfolio navigation.
|
||||
</p>
|
||||
<h2>Cover</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/manu-game-maker/cover.webp"
|
||||
alt="MANU Game Engine Interface — Case Cover"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Current preview for the portfolio card</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,643 @@
|
||||
<!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=""Activity" Section Card Catalog: Types, Cell Widths, and a Live Masonry Grid."
|
||||
/>
|
||||
<title>Activity — Card Catalog</title>
|
||||
{{> head-links}}
|
||||
<style>
|
||||
#main {
|
||||
padding-bottom: clamp(3.5rem, 8vw, 5.5rem);
|
||||
}
|
||||
|
||||
.case-article.mp-showcase-page {
|
||||
max-width: 56rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.case-article.mp-showcase-page .case-page__sub {
|
||||
margin-bottom: clamp(1.5rem, 4vw, 2.25rem);
|
||||
}
|
||||
|
||||
.case-article.mp-showcase-page .section__prose {
|
||||
margin-bottom: 1.1rem;
|
||||
line-height: 1.65;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.case-article.mp-showcase-page > h2 {
|
||||
margin: 0 0 1rem;
|
||||
padding-top: clamp(2.5rem, 5vw, 3.5rem);
|
||||
font-family: var(--font);
|
||||
font-size: clamp(1.15rem, 2vw, 1.35rem);
|
||||
font-weight: 700;
|
||||
color: var(--text);
|
||||
scroll-margin-top: 1.5rem;
|
||||
border-top: 1px solid color-mix(in srgb, var(--line) 90%, transparent);
|
||||
}
|
||||
|
||||
.case-article.mp-showcase-page > h2#intro {
|
||||
padding-top: clamp(1.25rem, 3vw, 2rem);
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.mp-showcase-toc {
|
||||
margin: 0 0 1.75rem;
|
||||
padding: 1rem 1.15rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
background: var(--surface);
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.mp-showcase-toc ol {
|
||||
margin: 0.35rem 0 0;
|
||||
padding-left: 1.2rem;
|
||||
}
|
||||
|
||||
.mp-showcase-toc a {
|
||||
color: var(--accent-text);
|
||||
}
|
||||
|
||||
.mp-showcase-specimens {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
margin: 1.25rem 0 0.5rem;
|
||||
}
|
||||
|
||||
.mp-showcase-specimen-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(14rem, 1fr) minmax(12rem, 1.15fr);
|
||||
gap: 1rem 1.75rem;
|
||||
align-items: start;
|
||||
padding-bottom: 2.25rem;
|
||||
margin-bottom: 2.25rem;
|
||||
border-bottom: 1px solid color-mix(in srgb, var(--line) 88%, transparent);
|
||||
}
|
||||
|
||||
.mp-showcase-specimen-row:last-child {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
@media (max-width: 719px) {
|
||||
.mp-showcase-specimen-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.mp-showcase-specimen__card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.45rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.mp-showcase-specimen__desc .section__prose {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mp-showcase-specimen__desc .section__prose strong {
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.mp-showcase-specimen__label {
|
||||
margin: 0;
|
||||
font-size: 0.78rem;
|
||||
line-height: 1.4;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.mp-showcase-specimen__card .mp-card {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
/* На главной тоже, но в узкой колонке демо center давал пустоту над заголовком */
|
||||
.mp-showcase-specimen__card .mp-card--horizontal .mp-card__body {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.mp-showcase-grid-section {
|
||||
padding-top: clamp(2.75rem, 6vw, 4.5rem);
|
||||
}
|
||||
|
||||
.mp-showcase-grid-section .section__title {
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.mp-showcase-grid-section .section__prose {
|
||||
margin-bottom: clamp(1.5rem, 3vw, 2.25rem);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-table {
|
||||
width: 100%;
|
||||
margin: 1rem 0 0.5rem;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-table th,
|
||||
.mp-showcase-cells-table td {
|
||||
padding: 0.55rem 0.65rem;
|
||||
border: 1px solid var(--line);
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-table th {
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
background: color-mix(in srgb, var(--surface) 88%, var(--accent));
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo {
|
||||
margin: 1.35rem 0 1.65rem;
|
||||
padding: 1.1rem 1.15rem 1.2rem;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-md);
|
||||
background: color-mix(in srgb, var(--surface) 90%, var(--accent));
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__variant {
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__variant:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__legend {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.85rem;
|
||||
font-size: 0.72rem;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__legend--6 {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__legend--4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__legend--2 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__legend span {
|
||||
padding: 0.2rem 0;
|
||||
border-radius: var(--radius-sm);
|
||||
background: color-mix(in srgb, var(--line) 35%, transparent);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__row-label {
|
||||
font-size: 0.82rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
margin: 0 0 0.55rem;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__grid {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
margin-bottom: 0.55rem;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__grid--6 {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__grid--4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__grid--2 {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__block {
|
||||
min-height: 2.35rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid color-mix(in srgb, var(--accent) 42%, var(--line));
|
||||
background: color-mix(in srgb, var(--accent) 14%, var(--surface));
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--accent-text);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__block--1 {
|
||||
grid-column: span 1;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__block--2 {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__block--3 {
|
||||
grid-column: span 3;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__block--4 {
|
||||
grid-column: span 4;
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__caption {
|
||||
margin: 0.85rem 0 0;
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.45;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.mp-showcase-cells-demo__row-label {
|
||||
margin: 0.65rem 0 0.35rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.mp-showcase-grid-section .mini-projects-grid {
|
||||
margin-top: 0;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
(function () {
|
||||
try {
|
||||
var raw = localStorage.getItem("siteThemeV1");
|
||||
if (!raw) return;
|
||||
var t = JSON.parse(raw);
|
||||
var d = document.documentElement;
|
||||
if (t.mode === "light" || t.mode === "dark") d.dataset.theme = t.mode;
|
||||
if (t.radius === "soft" || t.radius === "medium" || t.radius === "strong") d.dataset.radius = t.radius;
|
||||
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;
|
||||
if (t.meshBg === "off") d.dataset.meshBg = "off";
|
||||
} catch (e) {}
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
{{> header-minimal}}
|
||||
{{> fab-stack-home-contact}}
|
||||
<main id="main">
|
||||
<section class="section section--tight">
|
||||
<div class="section__inner">
|
||||
<div class="case-article mp-showcase-page">
|
||||
<p class="hero__eyebrow">Design System · Activity</p>
|
||||
<h1 class="case-page__h1">Activity Cards</h1>
|
||||
<p class="case-page__sub">All card types and a live grid for selecting layouts on the homepage</p>
|
||||
<p class="section__prose">
|
||||
Layout and content page: the same classes and scripts are used here as in the section on the homepage. Change the font and theme in the panel on the right;
|
||||
narrow the window, and the grid will recalculate. The text in the card headers is just placeholder text; you can remove it when previewing.
|
||||
</p>
|
||||
|
||||
<nav class="mp-showcase-toc" aria-label="Catalog Table of Contents">
|
||||
<p><strong>Sections</strong></p>
|
||||
<ol>
|
||||
<li><a href="#types">Card Types</a></li>
|
||||
<li><a href="#cells">Width in Cells</a></li>
|
||||
<li><a href="#grid">Live Masonry Grid</a></li>
|
||||
<li><a href="#fixed-height">Fixed height</a></li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<h2 id="intro">How to Use</h2>
|
||||
<p class="section__prose">
|
||||
First, select <strong>a type</strong> (stack, horizontal, compact, decor), then <strong>data-mp-cells</strong> (1–4) and
|
||||
the order <code>li</code> in the list. Cards with <code>data-mp-extra</code> do not affect the height of the list until the “Show All” button is clicked.
|
||||
For more details, see <code>docs/mini-projects-cards.md</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="types">Card Types</h2>
|
||||
<p class="section__prose">
|
||||
On the left is an example of a text card; on the right is the type name and an explanation of the classes.
|
||||
</p>
|
||||
{{> mini-projects-showcase-specimens}}
|
||||
|
||||
<h2 id="cells">Width in Cells</h2>
|
||||
<p class="section__prose">
|
||||
Attribute <code>data-mp-cells</code> sets <code>li.mini-projects-grid__item</code> specifies the desired width from 1 to 4 cells.
|
||||
The script will not allow the card to be wider than the current row.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
For responsive width, use <code>data-mp-cells-sm</code> (for 4 cells per row, ≥ 880 px) and
|
||||
<code>data-mp-cells-xs</code> (for 2 cells, ≥ 520 px). The script selects the value based on the current number of cells in a row.
|
||||
</p>
|
||||
<div class="mp-showcase-attrs-table">
|
||||
<table class="mp-showcase-cells-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">The</th>
|
||||
<th scope="col">When to use</th>
|
||||
<th scope="col">Example</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>data-mp-cells</code></td>
|
||||
<td>Wide screen (6 cells, ≥ 1180 px)</td>
|
||||
<td><code>data-mp-cells="3"</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>data-mp-cells-sm</code></td>
|
||||
<td>Medium screen (4 cells, ≥ 880 px)</td>
|
||||
<td><code>data-mp-cells-sm="2"</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>data-mp-cells-xs</code></td>
|
||||
<td>Narrow screen (2 cells, ≥ 520 px)</td>
|
||||
<td><code>data-mp-cells-xs="1"</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="section__prose" style="margin-top:0.55rem">
|
||||
<strong>Example:</strong> <code>data-mp-cells="3" data-mp-cells-sm="2"</code> — A card takes up 3 cells on a wide screen, 2 on a medium screen, and 1 on a narrow screen.
|
||||
</p>
|
||||
<figure class="mp-showcase-cells-demo" aria-label="Chart showing the width of the cards in the cells">
|
||||
<div class="mp-showcase-cells-demo__variant">
|
||||
<div class="mp-showcase-cells-demo__legend mp-showcase-cells-demo__legend--6" aria-hidden="true">
|
||||
<span>123456</span>
|
||||
</div>
|
||||
<p class="mp-showcase-cells-demo__row-label">≥ 1180 px — 6 cells</p>
|
||||
<div class="mp-showcase-cells-demo__grid mp-showcase-cells-demo__grid--6">
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--3">3</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--3">3</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--3">3</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--4">4</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mp-showcase-cells-demo__variant">
|
||||
<div class="mp-showcase-cells-demo__legend mp-showcase-cells-demo__legend--4" aria-hidden="true">
|
||||
<span>1234</span>
|
||||
</div>
|
||||
<p class="mp-showcase-cells-demo__row-label">≥ 880 px — 4 cells</p>
|
||||
<div class="mp-showcase-cells-demo__grid mp-showcase-cells-demo__grid--4">
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--3">3</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--4">4</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mp-showcase-cells-demo__variant">
|
||||
<div class="mp-showcase-cells-demo__legend mp-showcase-cells-demo__legend--2" aria-hidden="true">
|
||||
<span>12</span>
|
||||
</div>
|
||||
<p class="mp-showcase-cells-demo__row-label">≥ 520 px — 2 cells</p>
|
||||
<div class="mp-showcase-cells-demo__grid mp-showcase-cells-demo__grid--2">
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--2">2</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
<div class="mp-showcase-cells-demo__block mp-showcase-cells-demo__block--1">1</div>
|
||||
</div>
|
||||
</div>
|
||||
<figcaption class="mp-showcase-cells-demo__caption">
|
||||
The number in the block = the value <code>data-mp-cells</code>. The card occupies that many cells in a row. On a narrow screen, there are fewer cells—cards with a width greater than the number of cells are carried over to the next row. As <code>data-mp-cells-sm</code> / <code>data-mp-cells-xs</code> the card changes its width when the view is narrowed.
|
||||
</figcaption>
|
||||
</figure>
|
||||
<table class="mp-showcase-cells-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">List width</th>
|
||||
<th scope="col">Cells per row</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>≥ 1180px</td>
|
||||
<td>6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>≥ 880px</td>
|
||||
<td>4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>≥ 520px</td>
|
||||
<td>2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>already</td>
|
||||
<td>1 (entire row)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="section__prose">
|
||||
A pair on six cells <code>3 + 3</code> or a trio <code>2 + 2 + 2</code> usually looks neater than a random set.
|
||||
Decor (<code>mp-card--decor</code>) fills in the gaps in the grid.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="grid" class="section section--surface mp-showcase-grid-section" aria-labelledby="grid-title">
|
||||
<div class="section__inner">
|
||||
<h2 id="grid-title" class="section__title">Live masonry grid</h2>
|
||||
<p class="section__prose">
|
||||
A demo of the “Activity” block from the homepage: here, all card types are in a single live grid. Each card’s caption shows the type of
|
||||
layout and <code>data-mp-cells</code>. Change the window width and font in the theme panel, watch how the grid
|
||||
rearranges itself, and apply the best layout to the homepage.
|
||||
</p>
|
||||
{{> mini-projects-showcase-grid}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="fixed-height" class="section section--surface mp-showcase-grid-section" aria-labelledby="fixed-height-title">
|
||||
<div class="section__inner">
|
||||
<h2 id="fixed-height-title" class="section__title">Fixed Height</h2>
|
||||
<p class="section__prose">
|
||||
Attribute <code>data-mp-height="…"</code> sets <code>li.mini-projects-grid__item</code> sets a fixed card height in pixels. Text is truncated with an ellipsis if it doesn’t fit.
|
||||
</p>
|
||||
<ol
|
||||
id="mini-projects-fixed-height-grid"
|
||||
class="mini-projects-grid mp-showcase-grid"
|
||||
data-mini-projects-list
|
||||
>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="4" data-mp-cells-sm="4" data-mp-cells-xs="2" data-mp-height="600">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[4→4→2] height=600 · stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[4→4→2] height=600 · stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">website</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">4 → 4 → 2. data-mp-cells-sm="4" data-mp-cells-xs="2". Height 600px.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2" data-mp-height="600" data-mp-height-sm="400">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[2] height=600 · stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[2] height=600 · stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">note</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Two cells, height 600px.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2" data-mp-height="400">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[2] height=400 · stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[2] height=400 · stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Utility</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Two cells, 400px high.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2" data-mp-height="400">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[2] height=400 · stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[2] height=400 · stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">template</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Two cells, 400px tall.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2" data-mp-height="400">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[2] height=400 · stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[2] height=400 · stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Two cells, 400px tall.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-mp-cells-xs="1">
|
||||
<a class="mp-card mp-card--link mp-card--compact" href="#" aria-label="[3→2→1] · compact · link">
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[3→2→1] · compact · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">3 → 2 → 1. data-mp-cells-sm="2" data-mp-cells-xs="1". Auto-height.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-mp-cells-xs="1">
|
||||
<a class="mp-card mp-card--link mp-card--compact" href="#" aria-label="[3→2→1] · compact · link">
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[3→2→1] · compact · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">document</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">3 → 2 → 1. data-mp-cells-sm="2" data-mp-cells-xs="1".</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,124 @@
|
||||
<!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="Case Study: A mobile app for a network of clinics—appointment scheduling, medical services, navigation, and quick actions."
|
||||
/>
|
||||
<title>Mobile App for a Network of Clinics — Case Study</title>
|
||||
{{> head-links}}
|
||||
<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 .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 data-current-case="mobile-clinic-app">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">UX/UI · Mobile App</p>
|
||||
<h1 class="case-page__h1">Mobile App for a Clinic Network</h1>
|
||||
<p class="case-page__sub">
|
||||
Booking doctor appointments and managing medical services: a simple user journey, intuitive navigation, and quick access to actions.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The project’s focus is on alleviating patient anxiety and eliminating unnecessary steps: clear appointment statuses, predictable forms, and reliance on familiar mobile app patterns.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A full breakdown of the case study will be published here; for now, this page serves as an entry point from the portfolio section on the homepage.
|
||||
</p>
|
||||
<h2>Cover</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/mobile-clinic-app/cover.webp"
|
||||
alt="Mobile App for a Network of Clinics — Case Study Cover"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Current preview for the portfolio card</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,150 @@
|
||||
<!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="Case Study: A Column-Based Plugin for Obsidian — Design and UX of a Note-Taking Plugin."
|
||||
/>
|
||||
<title>Column View for Obsidian — Case Study</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-case}}
|
||||
{{> fab-stack}}
|
||||
<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">Column View — a plugin for Obsidian</h1>
|
||||
<p class="case-page__sub">Design and development of an interface for multi-column note management</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
</p>
|
||||
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
</p>
|
||||
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
</p>
|
||||
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
</p>
|
||||
|
||||
<h3>Usage Filter</h3>
|
||||
<figure class="case-media">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/obsidian-plugin-columns-view/filter use.webp" data-case-video-player style="display: block; width: 100%; height: auto">
|
||||
<source src="{{assetPrefix}}assets/obsidian-plugin-columns-view/filter use.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/obsidian-plugin-columns-view/filter use.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Filtering notes in a columnar view.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Display Configuration</h3>
|
||||
<figure class="case-media">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/obsidian-plugin-columns-view/view configure.webp" data-case-video-player style="display: block; width: 100%; height: auto">
|
||||
<source src="{{assetPrefix}}assets/obsidian-plugin-columns-view/view configure.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/obsidian-plugin-columns-view/view configure.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>Column and display settings.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2 id="result">Result</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,262 @@
|
||||
<!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="Case Study: Redesign of the Primo RPA Orchestrator Web Dashboard — design oversight, implementation of Ant Design and Storybook, and token synchronization with Figma."
|
||||
/>
|
||||
<title>Web Dashboard for Automation Orchestration — Case Study</title>
|
||||
{{> head-links}}
|
||||
<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">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<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">Web Dashboard for Automation Orchestration</h1>
|
||||
<p class="case-page__sub">
|
||||
Primo RPA Orchestrator: launching robots, managing projects, and monitoring processes in a web dashboard for administrators and automation developers.
|
||||
</p>
|
||||
|
||||
<div class="case-block" id="obzor">
|
||||
<h2>Context</h2>
|
||||
<p class="section__prose">
|
||||
In the Primo RPA stack, the orchestrator manages the scheduling, queue, and statuses of RPA robots on the client’s infrastructure. It can be accessed not only from the development studio but also from a browser: users view projects, restart tasks, and troubleshoot failures.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
By that point, the product was already in use, but the interface was noticeably outdated: users faced navigation issues, visual clutter in tables, and confusing workflows in some sections. The goal was to refresh the interface’s look, modernize it, and fix the accumulated UX issues.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rol">
|
||||
<h2>Role and Approach</h2>
|
||||
<p class="section__prose">
|
||||
My role in this project was more of a curatorial one—I didn’t do the design myself, but rather structured the process so that the design and development teams could work in sync.
|
||||
</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>I studied the product “from scratch”: I analyzed the orchestrator interface, identified user pain points, and formulated objectives for the update.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
At the same time, I was looking for a designer who could take on the main visual design work. Elizaveta was selected—out of more than 150 applications, she was the best fit for the upcoming workload.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Over the course of three months, I brought the new team member up to speed on the project details: I assigned tasks, provided feedback on the mockups she created, and shared context on user scenarios. Together with the development team, we planned the order in which to update the service’s design—we revised screens based on priority, incorporating changes into ongoing releases, without “stopping everything and redesigning from scratch.”
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="tekhnicheskiy-stek">
|
||||
<h2>Technical Stack and Tools</h2>
|
||||
<p class="section__prose">
|
||||
The latest version of <a href="https://ant.design/" target="_blank" rel="noopener noreferrer">Ant Design</a> was chosen as the UI framework. It was already in use on the project, and its latest release introduced <a href="https://ant.design/theme-editor" target="_blank" rel="noopener noreferrer">the Theme Editor</a>—a feature that allowed us to customize the appearance of components using design tokens without manually overriding styles. This provided both designers and developers with a unified language for describing the user interface.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
<a href="https://storybook.js.org/" target="_blank" rel="noopener noreferrer">Storybook</a> served as the single source of truth and the bridge between design and development. In Storybook, components weren’t just documented—they actually worked in an isolated environment. This allowed designers to see the elements in action and developers to integrate components into the dashboard more quickly.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="dizayn-sistema">
|
||||
<h2>Design System and Synchronization</h2>
|
||||
<p class="section__prose">
|
||||
To streamline our workflow, we synchronized tokens from Ant Design with those in Figma—colors, padding, typography, and corner radii were standardized to consistent values. Here’s how it worked: if tokens were updated in Figma, they could be exported as JSON and immediately imported into the code without any issues—instead of having a developer manually search for changes and update each token individually. This approach also allowed us to view the design more systematically.
|
||||
</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>The main goal of this close collaboration between design and development was to translate the original vision into the product as accurately as possible without losing sight of the details along the way.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
Components in Figma were built from scratch—based on Ant Design references, but without using pre-made libraries. The decision to avoid pre-made solutions was a conscious one: we needed full customization to fit our workflow and the ability to use new Figma features that weren’t supported in libraries from the Figma community.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
For Storybook, we selected and configured plugins that were relevant to our tasks—accessibility checks, viewing component states, and switching themes and locales. This turned Storybook into more than just a showcase for components; it became a full-fledged design review tool.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="rabochaya-sreda">
|
||||
<h2>Designer’s Work Environment</h2>
|
||||
<p class="section__prose">
|
||||
We set up the environment so that designers could see the live implementation of components on their own computers using a local Storybook instance and Git. This allowed for more precise control over how the intended design was translated into code and enabled us to quickly spot discrepancies early on.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
We also discussed a step to accelerate Storybook support by allowing designers to write the JSX for implemented components themselves—this shortened the path from mockup to a documented component in Storybook.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
We fine-tuned the workflow for adding icons to the library. The key feature was that icons could be displayed in Storybook with filtering and sorting capabilities. At the same time, designers could update icons without involving a developer—they simply pushed new files to the repository.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
Being able to see the updated icon immediately in the browser allowed us to optimize it better and eliminate display glitches when using Boolean operations.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
We also developed an approach and set of rules for Figma that not only guided the designer but also ensured the creation of consistent and functional icons.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="ux-uluchsheniya">
|
||||
<h2>UX Improvements</h2>
|
||||
<p class="section__prose">
|
||||
During the interface update, Elizaveta also proposed a number of user experience improvements. Some of them were successfully implemented—for example, clearer grouping of elements in complex forms and redesigned loading states. However, the priority was not to disrupt the existing UX that users had grown accustomed to, so many ideas were saved for the backlog for the next iteration.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="proekty">
|
||||
<h2>Project List</h2>
|
||||
<p class="section__prose">
|
||||
The project table is one of the most frequently viewed screens. In the old version, there were many columns, a dense grid, and small text: the project status and name were difficult to read, especially on a laptop.
|
||||
</p>
|
||||
<p class="section__prose">In the new version:</p>
|
||||
<ul>
|
||||
<li>the columns have been reduced to what’s necessary for daily work;</li>
|
||||
<li>statuses and actions have been moved to predictable areas within each row;</li>
|
||||
<li>indentation and typography have been aligned with the rest of the panel using Ant Design.</li>
|
||||
</ul>
|
||||
|
||||
<h3>It used to be</h3>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/orc-primo-rpa/projects--table-old.webp"
|
||||
alt="List of projects in the orchestrator — previous version of the table"
|
||||
width="1919"
|
||||
height="867"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</figure>
|
||||
|
||||
<h3>Now</h3>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/orc-primo-rpa/projects--table-new.webp"
|
||||
alt="List of Projects in the Orchestrator — Updated Table"
|
||||
width="1366"
|
||||
height="768"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
<div class="case-block" id="itog">
|
||||
<h2>Results and Reflection</h2>
|
||||
<p class="section__prose">
|
||||
The projects screen became easier to scan: less visual noise, and it’s faster to find the right project and its status. After rolling out the new design to several clients, we received positive feedback and many ideas for further improvements.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I stepped away from the project once Elizaveta felt confident in her role and was able to handle design tasks independently. I occasionally answered specific questions, but overall, the handoff went smoothly.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A little over a year later, the team’s processes have changed significantly. According to the team, tools powered by neural networks—such as Claude Design—are now actively involved in the creation and handoff of designs. What we used to build manually using tokens, Storybook, and environment synchronization is now, to some extent, automated.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
I believe the work was completed fairly quickly and to a high standard—amid constant changes in the market and within the company, we managed not only to update the interface but also to establish a sustainable process that continued to function even without my involvement.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,133 @@
|
||||
<!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="Case Study: This website was developed using an AI IDE."
|
||||
/>
|
||||
<title>This Website — Developed with AI IDE — Case Study</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 data-current-case="site-with-ai-ide">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Development · AI IDE</p>
|
||||
<h1 class="case-page__h1">This website</h1>
|
||||
<p class="case-page__sub">Website Development Using AI IDE</p>
|
||||
|
||||
<p class="section__prose">
|
||||
<!-- Здесь будет введение -->
|
||||
</p>
|
||||
|
||||
<h2 id="context">Context</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Контекст проекта -->
|
||||
</p>
|
||||
|
||||
<h2 id="task">Task</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Описание задачи -->
|
||||
</p>
|
||||
|
||||
<h2 id="solution">Solution</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Что было сделано -->
|
||||
</p>
|
||||
|
||||
<h2 id="result">Result</h2>
|
||||
<p class="section__prose">
|
||||
<!-- Итоги -->
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> mini-projects-related}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,124 @@
|
||||
<!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="Case Study: A Task-Assignment Service Concept—Transparency in Processes and Teamwork."
|
||||
/>
|
||||
<title>Task Distribution Service Concept — Case Study</title>
|
||||
{{> head-links}}
|
||||
<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 .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 data-current-case="task-distribution-concept">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">UX/UI · Analytics</p>
|
||||
<h1 class="case-page__h1">Task Assignment Service Concept</h1>
|
||||
<p class="case-page__sub">
|
||||
Product concept: setting, assigning, and tracking tasks with an emphasis on process transparency and seamless teamwork.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
The goal of the concept is to show how the team views the workflow without “black boxes”: who is working on what, where the bottlenecks are, and which statuses are critical for the next step.
|
||||
</p>
|
||||
<p class="section__prose">
|
||||
A detailed case study will be posted here later; the page is already linked to a portfolio entry on the website.
|
||||
</p>
|
||||
<h2>Cover</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img
|
||||
src="{{assetPrefix}}assets/task-distribution-concept/cover.webp"
|
||||
alt="Task Distribution Service Concept — Case Cover"
|
||||
width="1200"
|
||||
height="675"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
data-image-viewer
|
||||
/>
|
||||
<figcaption>Current preview for the portfolio card</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
@@ -0,0 +1,594 @@
|
||||
<!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="Task interface for the operations department: tabs, filters, view modes, Figma prototypes, and research scenarios."
|
||||
/>
|
||||
<title>Task Tracker for a Back-Office System — Case Study</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 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);
|
||||
}
|
||||
</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="task-tracker">
|
||||
{{> header-case}}
|
||||
{{> fab-stack}}
|
||||
<main id="case-main" class="section section--tight">
|
||||
<div class="section__inner case-article">
|
||||
<p class="hero__eyebrow">Test Assignment · Back Office</p>
|
||||
<h1 class="case-page__h1">Task Tracker for an Internal Back-Office System</h1>
|
||||
<h2 id="zadanie">Assignment</h2>
|
||||
<p class="section__prose">
|
||||
Implement an interface for planning and assigning tasks to employees in the operations department who work in a back-office system. There are a large number of diverse tasks that can be grouped into the following categories: Type-1, Type-2, Type-3, Type-4, Type-5, Type-6, Type-7. Each task has its own automatically assigned priority. Users have access only to tasks from specific categories.
|
||||
</p>
|
||||
<p class="section__prose">The following needs to be implemented:</p>
|
||||
<ul>
|
||||
<li>
|
||||
Main screen:
|
||||
<ul>
|
||||
<li>where the user can view all open general tasks and select some for themselves.</li>
|
||||
<li>A personal to-do list displaying both manually selected tasks and automatically assigned ones.</li>
|
||||
<li>For a selected task, there is the option to assign it to another employee or return it to the general list.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>A screen where users can see what tasks each person is working on.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="vvedenie">Introduction</h2>
|
||||
<p class="section__prose">
|
||||
Since I personally have extensive experience working with task trackers, I’m drawing on my own experience and that of my colleagues, while taking the project requirements into account.
|
||||
</p>
|
||||
|
||||
<h2 id="referensy">References</h2>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/refs.webp" alt="References" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<ul>
|
||||
<li>Task trackers (Trello, Monday, YouTrack, etc.)</li>
|
||||
<li>Services for visual database management (Notion, Airtable, etc.)</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="reshenie">Solution</h2>
|
||||
|
||||
<h3 id="skrinkast">Screencast</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/task-tracker/full_preview.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/task-tracker/full_preview.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/task-tracker/full_preview.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-(Factoring)?page-id=0%3A1&node-id=20%3A1291&viewport=-5744%2C876%2C1.35&scaling=contain&starting-point-node-id=20%3A1291"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media"><img src="{{assetPrefix}}assets/task-tracker/tab_all-tasks.webp" alt="Figma Prototype Preview" width="1200" height="800" loading="lazy" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-(Factoring)?page-id=0%3A1&node-id=20%3A1291&viewport=-5744%2C876%2C1.35&scaling=contain&starting-point-node-id=20%3A1291"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Figma Prototype</span>
|
||||
<span class="case-link-card__meta">Interactive scenario based on tasks and views</span>
|
||||
<span class="case-link-card__url">figma.com/proto/.../STENN-(Factoring)</span>
|
||||
|
||||
|
||||
</span></a></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>It is assumed that an employee cannot create tasks but can view and partially edit them; therefore, an administrator or manager configures which tasks will be available to the employee.</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3 id="tabs">Tabs</h3>
|
||||
<p class="section__prose">On the <strong>All Tasks</strong> tab, the employee can view all available tasks.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/tab_all-tasks.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The "<strong>My tasks</strong>" tab displays only those tasks assigned to the current employee. Tasks are grouped by status (the status is hidden in the task card).
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/tab_my-tasks.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<p class="section__prose">The <strong>“Task by Assignee”</strong> tab displays all tasks broken down by assignee.</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/tab_tasks-by-assign.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<p class="section__prose">Options for the current tab are located on the right-hand side.</p>
|
||||
<figure class="case-media case-media--natural">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/actions_for_page.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" />
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
All changes are saved when you leave the tab and when you close the entire <strong>Tasks</strong> page. These settings are individual, and each employee can customize the page as they see fit.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Group—allows you to create additional groupings based on task properties (category, priority, assignee, status, creation date, modification date).</li>
|
||||
<li>View—allows you to change the display of current tasks to a different view: board, list, or table.</li>
|
||||
<li>Filter—allows you to hide tasks based on their properties.</li>
|
||||
<li>
|
||||
Sort—allows you to determine the order in which tasks are displayed based on their properties. If sorting by status (High, Medium, Low) is enabled, you can choose either alphabetical order or reverse order, or you can create your own order. Dates and numbers are sorted in ascending or descending order.
|
||||
</li>
|
||||
<li>
|
||||
Search on page — allows you to display only those tasks whose title or description contains a specific search word or phrase. (Search functionality can be improved by adding search operators if research demonstrates the need.)
|
||||
</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
The page uses lazy loading for tasks. As you scroll down, new tasks will load. The number of tasks is displayed in the headers; this can be helpful for estimating how far you need to scroll to see everything. There may be a large number of tasks, in which case it might make sense to add pagination as well.
|
||||
</p>
|
||||
|
||||
<h3 id="views">Display Options (Views)</h3>
|
||||
<p class="section__prose">
|
||||
Different views of the same tasks can be useful for various contexts in which the <strong>Tasks</strong> page is used, as well as to accommodate employees’ personal preferences, which increases their efficiency. An employee who isn’t annoyed by the interface works more productively and contributes more.
|
||||
</p>
|
||||
<figure class="case-media case-media--natural">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/dropdown_menu_for_views.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" />
|
||||
</figure>
|
||||
<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>When you change the view, the icon next to the <strong>“View”</strong> option also changes.</p>
|
||||
</div>
|
||||
</aside>
|
||||
<p class="section__prose">
|
||||
The <strong>Board</strong> view makes it easier to use the drag-and-drop feature (see below). It’s also visually easier to determine the number of tasks in a category, which I imagine could be helpful. When tasks are grouped by completion status, moving cards from left to right creates a natural horizontal flow of tasks from point A to point B.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/view_board.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The <strong>List</strong> view allows you to see more information in a smaller screen area. At the same time, this view is visually and functionally simpler than the table view, which means less cognitive load on the user. Also, all task titles start at the far left, making it easy <em>to scan</em> the list.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/view_list.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<p class="section__prose">
|
||||
The <strong>Table</strong> view allows you to work with all task fields immediately, without having to open the task in a modal window or a separate page. The table allows you to customize the width and order of columns, which can be convenient in certain use cases.
|
||||
</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/view_table.webp" alt="Untitled" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<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>Sections can be collapsed to fit only the necessary amount of content on the screen. (It might even make sense to save the collapsed/expanded state after switching views, tabs, or reloading the page.)</p>
|
||||
</div>
|
||||
</aside>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/task-tracker/expand-collapse_group.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/task-tracker/expand-collapse_group.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/task-tracker/expand-collapse_group.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-(Task-Tracker)?page-id=0%3A1&node-id=39%3A700&viewport=-1875%2C-125%2C0.55&scaling=min-zoom&starting-point-node-id=20%3A1291&hide-ui=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media"><img src="{{assetPrefix}}assets/task-tracker/view_board.webp" alt="Preview of the "Board" View Prototype" width="1200" height="800" loading="lazy" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-(Task-Tracker)?page-id=0%3A1&node-id=39%3A700&viewport=-1875%2C-125%2C0.55&scaling=min-zoom&starting-point-node-id=20%3A1291&hide-ui=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Prototype in Figma</span>
|
||||
<span class="case-link-card__meta">Display options: Board, List, Table</span>
|
||||
<span class="case-link-card__url">figma.com/proto/.../STENN- (Task Tracker)</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
|
||||
<h3 id="drag">Drag & Drop</h3>
|
||||
<p class="section__prose">
|
||||
In all views, you can drag and drop elements (cards, list items, and table rows and columns). This promotes more productive work and feels natural to the user. For example, if you need to distribute tasks among employees (for an admin or manager), change the status of multiple tasks at once, or do so within a short period of time.
|
||||
</p>
|
||||
<p class="section__prose"><strong>Board view</strong></p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/task-tracker/drag-drop-item_board-view.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/task-tracker/drag-drop-item_board-view.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/task-tracker/drag-drop-item_board-view.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-Task-Tracker?node-id=108%3A970&viewport=2248%2C341%2C0.33&scaling=contain&starting-point-node-id=108%3A1968&show-proto-sidebar=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media" aria-hidden="true"><img src="{{assetPrefix}}assets/task-tracker/view_board.webp" alt="" width="1200" height="800" loading="lazy" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-Task-Tracker?node-id=108%3A970&viewport=2248%2C341%2C0.33&scaling=contain&starting-point-node-id=108%3A1968&show-proto-sidebar=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Figma prototype</span>
|
||||
<span class="case-link-card__meta">Drag & Drop, Board view</span>
|
||||
<span class="case-link-card__url">figma.com/proto/.../STENN-Task-Tracker</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
<p class="section__prose"><strong>List view</strong></p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/task-tracker/drag-drop-item_list-view.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/task-tracker/drag-drop-item_list-view.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/task-tracker/drag-drop-item_list-view.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-Task-Tracker?node-id=108%3A970&viewport=2248%2C341%2C0.33&scaling=contain&starting-point-node-id=108%3A2607&show-proto-sidebar=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media" aria-hidden="true"><img src="{{assetPrefix}}assets/task-tracker/view_list.webp" alt="" width="1200" height="800" loading="lazy" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN-Task-Tracker?node-id=108%3A970&viewport=2248%2C341%2C0.33&scaling=contain&starting-point-node-id=108%3A2607&show-proto-sidebar=1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Prototype in Figma</span>
|
||||
<span class="case-link-card__meta">Drag & Drop, List view</span>
|
||||
<span class="case-link-card__url">figma.com/proto/.../STENN-Task-Tracker</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
<p class="section__prose"><strong>Advanced interactive prototype in ProtoPie</strong></p>
|
||||
<p class="section__prose">
|
||||
A schematic representation of how Drag & Drop works. This type of prototype helps designers better understand the nuances that need to be considered in the user flow, as well as when preparing specifications for developers. Also, by testing this prototype, you may realize that the feature needs to work completely differently and decide to redesign it right away. This saves overall development time.
|
||||
</p>
|
||||
<figure class="case-media" style="margin: 0.85rem 0 1.2rem">
|
||||
<div class="case-video-shell">
|
||||
<video controls preload="metadata" playsinline poster="{{assetPrefix}}assets/task-tracker/drag-drop-action_example.webp" data-case-video-player style="display: block; width: 100%; height: auto; margin: 0">
|
||||
<source src="{{assetPrefix}}assets/task-tracker/drag-drop-action_example.webm" type="video/webm" />
|
||||
<source src="{{assetPrefix}}assets/task-tracker/drag-drop-action_example.mp4" type="video/mp4" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://cloud.protopie.io/p/e7a45bd3f2?touchHint=false&ui=false&scaleToFit=false&cursorType=arrow&mockup=false&bgColor=%23F5F5F5&playSpeed=1&playerAppPopup=true"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media" aria-hidden="true"><img src="https://www.google.com/s2/favicons?domain=cloud.protopie.io&sz=128" alt="" width="24" height="24" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://cloud.protopie.io/p/e7a45bd3f2?touchHint=false&ui=false&scaleToFit=false&cursorType=arrow&mockup=false&bgColor=%23F5F5F5&playSpeed=1&playerAppPopup=true"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Prototype | drag_drop | ProtoPie Cloud</span>
|
||||
<span class="case-link-card__meta">Interactive</span> <span class="case-link-card__title">prototype</span><span class="case-link-card__meta"> in the ProtoPie cloud</span>
|
||||
cloud<span class="case-link-card__url">.protopie.io/...</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
<p class="section__prose">
|
||||
In the prototype, only the blue card can be moved, and not all positions work correctly. You can view the recording, which is available on the same prototype page.
|
||||
</p>
|
||||
|
||||
<h2 id="stil">Style</h2>
|
||||
<p class="section__prose">
|
||||
The visual style can be anything you like without changing <em>the framework</em> itself<em>.</em> For example, it could be a bit more colorful with more expressive fonts.
|
||||
</p>
|
||||
<p class="section__prose">Light-colored theme</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/light_theme_color.webp" alt="Light-colored theme" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://www.figma.com/file/aFvwvTZuksD0JTo6yFXyUz/STENN-(Task-Tracker)?node-id=174%3A5703"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media" aria-hidden="true"><img src="https://www.google.com/s2/favicons?domain=www.figma.com&sz=128" alt="" width="24" height="24" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://www.figma.com/file/aFvwvTZuksD0JTo6yFXyUz/STENN-(Task-Tracker)?node-id=174%3A5703"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Figma Frame</span>
|
||||
<span class="case-link-card__meta">Light-colored theme</span>
|
||||
<span class="case-link-card__url">figma.com/file/.../STENN- (Task-Tracker)</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
<p class="section__prose">Neutral dark theme</p>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/task-tracker/dark_theme.webp" alt="Neutral Dark Theme" width="1200" height="800" loading="lazy" decoding="async" data-image-viewer />
|
||||
</figure>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN--Task-Tracker-?node-id=135-5400&t=BzGQOTE0ty7u2E50-1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media" aria-hidden="true"><img src="https://www.google.com/s2/favicons?domain=www.figma.com&sz=128" alt="" width="24" height="24" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://www.figma.com/proto/aFvwvTZuksD0JTo6yFXyUz/STENN--Task-Tracker-?node-id=135-5400&t=BzGQOTE0ty7u2E50-1"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Frame in Figma</span>
|
||||
<span class="case-link-card__meta">Neutral dark theme</span>
|
||||
<span class="case-link-card__url">figma.com/proto/.../STENN--Task-Tracker-</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
|
||||
<h2 id="issledovaniya">Research</h2>
|
||||
<p class="section__prose">
|
||||
During the Figma prototyping phase, you can conduct interviews with several employees—for example, 5 people. First, add real tasks from the current system to the prototype; about 20 should be enough. Next, you can hold a video call with the respondent’s screen shared or meet in person to present a few tasks and ask some questions. During the session, the respondent can interact with the prototype, but if something doesn’t work, the interviewer can note the attempt and explain that this feature isn’t working yet, as well as ask what the respondent expects to see next.
|
||||
</p>
|
||||
<h3 id="zadania">Tasks</h3>
|
||||
<ol>
|
||||
<li>Find your current tasks on the <strong>Tasks</strong> page under the <strong>All Tasks</strong> tab</li>
|
||||
<li>Assign tasks to yourself to work on</li>
|
||||
<li>Find a task related to a specific topic (the interviewer provides an example) that they have already completed</li>
|
||||
<li>Show tasks that belong only to a specific category and must be completed by the end of the week</li>
|
||||
<li>Request that the priority of several tasks be changed at once</li>
|
||||
<li>Rate the visual appeal of the interface on a scale of 1 to 10</li>
|
||||
<li>Rate your overall impression of the proposed concept on a scale of 1 to 10</li>
|
||||
<li>Suggest additional features that would be useful</li>
|
||||
</ol>
|
||||
<h3 id="analitika">Analytics</h3>
|
||||
<p class="section__prose">To assess the relevance of the implemented features, the following metrics must be collected.</p>
|
||||
<ul>
|
||||
<li>
|
||||
Number of page views for the "<strong>Tasks"</strong> page <code>page_views_tasks</code> with the option to break them down
|
||||
<ul>
|
||||
<li>
|
||||
by tabs
|
||||
<ul>
|
||||
<li>All tasks <code>all_tasks_tab</code></li>
|
||||
<li>My tasks <code>my_tasks_tab</code></li>
|
||||
<li>Tasks by Assignment <code>tasks_by_assign</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
by role
|
||||
<ul>
|
||||
<li>Admin <code>admin</code></li>
|
||||
<li>Manager <code>manager</code></li>
|
||||
<li>User <code>user</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
by search attempts
|
||||
<ul>
|
||||
<li>Search Used <code>search used</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
Number <strong>of</strong> enabled custom settings <code>custom_settings</code> with the option to group
|
||||
<ul>
|
||||
<li>
|
||||
by tabs
|
||||
<ul>
|
||||
<li>All tasks <code>all_tasks_tab</code></li>
|
||||
<li>My tasks <code>my_tasks_tab</code></li>
|
||||
<li>Tasks by Assignment <code>tasks_by_assign</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
by role
|
||||
<ul>
|
||||
<li>Admin <code>admin</code></li>
|
||||
<li>Manager <code>manager</code></li>
|
||||
<li>User <code>user</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
by type
|
||||
<ul>
|
||||
<li>Group <code>group</code></li>
|
||||
<li>Filter <code>filter</code></li>
|
||||
<li>Sort <code>sort</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
Number of included species <strong>View Used</strong> <code>view_used</code> with the option to break down
|
||||
<ul>
|
||||
<li>
|
||||
by tabs
|
||||
<ul>
|
||||
<li>All tasks <code>all_tasks_tab</code></li>
|
||||
<li>My tasks <code>my_tasks_tab</code></li>
|
||||
<li>Tasks by Assignment <code>tasks_by_assign</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
by role
|
||||
<ul>
|
||||
<li>Admin <code>admin</code></li>
|
||||
<li>Manager <code>manager</code></li>
|
||||
<li>User <code>user</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="section__prose">
|
||||
Then, over the next six months (or sooner, depending on user activity), we’ll be able to see the results and conduct a study (in the form of interviews) on the features that are used least frequently and those that have received complaints, in order to gather high-quality data and get a complete picture of what’s happening.
|
||||
</p>
|
||||
|
||||
<h2 id="dop">Additional details</h2>
|
||||
<p class="section__prose">
|
||||
When creating mockups in Figma, the following were used: auto-layout features; interactive components; plugins (<a href="https://www.figma.com/community/plugin/735098390272716381/Iconify">Iconify</a>, <a href="https://www.figma.com/community/plugin/917796239623005893/Fitter">Fitter</a>, <a href="https://www.figma.com/community/plugin/1021879782774011952">Protofly</a>, <a href="https://www.figma.com/community/plugin/889676455045507628/Shadow-Maker">Shadow Maker</a>, <a href="https://www.figma.com/community/plugin/986289377230504703">Dark Side</a>, etc.); and the Community file (<a href="https://www.figma.com/community/file/831142089959745518">+40 Types of Cursor</a>). About 60% of the layers are named and organized for easier workflow. An 8pt grid is used, with additional sizes of 2pt and 4pt. Color styles are available for light and dark themes. The design adapts to changing window sizes (no mobile version).
|
||||
</p>
|
||||
<div class="case-links-grid">
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://www.figma.com/file/aFvwvTZuksD0JTo6yFXyUz/STENN-(Task-Tracker)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__media" aria-hidden="true"><img src="https://www.google.com/s2/favicons?domain=www.figma.com&sz=128" alt="" width="24" height="24" decoding="async" /></span></a>
|
||||
|
||||
|
||||
<a
|
||||
class="case-link-card case-link-card--favicon"
|
||||
href="https://www.figma.com/file/aFvwvTZuksD0JTo6yFXyUz/STENN-(Task-Tracker)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
><span class="case-link-card__body"><span class="case-link-card__title">Source file in Figma</span>
|
||||
<span class="case-link-card__meta">STENN Project (Task-Tracker)</span>
|
||||
<span class="case-link-card__url">figma.com/file/.../STENN- (Task-Tracker)</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-related}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
<!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="A demo page for the case study featuring all the developed elements: link cards and media blocks." />
|
||||
<title>Case Study Elements Demo — 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">Demo · template</p>
|
||||
<h1 class="case-page__h1">Case Study Example: Demo Elements</h1>
|
||||
<p class="case-page__sub">Text blocks and elements for quickly building a longread</p>
|
||||
<p class="section__prose case-page__code">The media for the demo is located in <code>public/assets/</code> (the page builder does not copy them). See <code>public/assets/README.md</code>.</p>
|
||||
|
||||
<h2>Context</h2>
|
||||
<p class="section__prose">
|
||||
This section shows an example of a text block for the introduction. Here, you can briefly describe the product, the audience, and the project’s limitations.
|
||||
The text is neutral: the goal is to quickly sketch out the structure and check the page’s visual rhythm.
|
||||
</p>
|
||||
|
||||
<h2>Task</h2>
|
||||
<p class="section__prose">
|
||||
We need to put together a demo longread with the main UI elements: link cards, media blocks, and examples of content layout.
|
||||
It’s also important to check how the blocks behave on narrow and wide screens.
|
||||
</p>
|
||||
|
||||
<h2>Solution</h2>
|
||||
<p class="section__prose">Below are some ready-made examples that you can copy into real-world projects.</p>
|
||||
|
||||
<h3>Link Cards</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></a>
|
||||
|
||||
|
||||
<a class="case-link-card" href="https://www.examples.com/" target="_blank" rel="noopener noreferrer"><span class="case-link-card__body"><span class="case-link-card__title">Source with preview</span>
|
||||
<span class="case-link-card__meta">Short caption: what the user will see when they click the link</span>
|
||||
www.examples.com
|
||||
|
||||
|
||||
|
||||
|
||||
</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></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__body"><span class="case-link-card__title">Source with favicon</span>
|
||||
<span class="case-link-card__meta">Option for simpler links without a screenshot</span>
|
||||
<span class="case-link-card__url">www.examples.com/docs</span>
|
||||
|
||||
|
||||
</span></a></div>
|
||||
|
||||
<h3>Image: 50% of the original size (no preview)</h3>
|
||||
<figure class="case-media case-media--natural">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/hello.gif" alt="Full-size demo GIF" loading="lazy" decoding="async" />
|
||||
<figcaption>Image at reduced actual size, centered.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Image: width of the content (with preview)</h3>
|
||||
<figure class="case-media case-media--content">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/wallpaper-1.jpg" alt="Demo images based on content width" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>Image matches the width of the content. Clicking opens the viewer.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Image: slightly wider than the content (with preview)</h3>
|
||||
<figure class="case-media case-media--wide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/wallpaper-1.jpg" alt="The demo image is wider than the content" loading="lazy" decoding="async" data-image-viewer />
|
||||
<figcaption>The image extends slightly beyond the content column.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Long screenshot: collapsed height and button inside the preview</h3>
|
||||
<p class="section__prose">
|
||||
Block <code>data-case-tall-media</code>: width is specified by the <code>data-case-tall-width="wide"</code> (like a “wide” image) or <code>content</code> (per column). When collapsed, the top part of the frame is visible; at the bottom of the preview, there’s a solid “fog.” An “Expand” / “Collapse” button with a chevron icon appears above the bottom of the frame, inside the border; when expanded, the fog disappears; when collapsed, the page scrolls back to the preview. The preview height is set <code>.case-media-tall__clip</code> via <code>--case-tall-max</code> (default <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="Demo: Long vertical screenshot of the interface"
|
||||
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>Expand</span>
|
||||
<span data-case-tall-label-less hidden>Collapse</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Long image <code>img-long.webp</code> (source PNG next to it in <code>public/assets/template-elements-demo/</code>).</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Gallery: grid based on content width</h3>
|
||||
<p class="section__prose">
|
||||
The number of columns on a wide screen is set via <code>figure</code>: the <code>style="--case-gallery-cols: 3"</code>. Below these thresholds, the grid collapses to two or one column. Clicking on a thumbnail opens the general case 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="Demo Thumbnail 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="Demo Thumbnail 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="Demo Thumbnail 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="Demo Thumbnail 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="Demo Thumbnail 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="Demo Thumbnail 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="Demo Thumbnail 7" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Grid in an article column; in this example, three columns on a desktop.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Gallery: Full-page grid with side margins</h3>
|
||||
<p class="section__prose">
|
||||
The <code>case-media-gallery--wide</code> — same logic for extending beyond a column as in the single-column <code>case-media--wide</code>. Here, there are four columns on a wide screen (<code>--case-gallery-cols: 4</code>).
|
||||
</p>
|
||||
<figure class="case-media case-media-gallery case-media-gallery--wide" style="--case-gallery-cols: 4">
|
||||
<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 shot, frame 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 shot, take 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 shot, take 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 shot, take 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 shot, take 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 shot, shot 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 shot, shot 7" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
</div>
|
||||
<figcaption>Width is the same as for a `wide` image; on a narrow screen, the `wide` wrapper collapses to 100% of the column width (see media queries).</figcaption>
|
||||
</figure>
|
||||
|
||||
<h3>Slider: one image, arrows, and dots</h3>
|
||||
<p class="section__prose">
|
||||
Block <code>.case-media-slider</code> displays slides one at a time: navigation using “prev/next” arrows,
|
||||
paging using dots (the active one is highlighted in accent color). Keyboard support (←/→, Home/End on dots),
|
||||
touch/mouse swipe, and lazy loading of adjacent frames via <code>data-src</code>. Clicking on the active
|
||||
slide opens the general case 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="Slider, Frame 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="Slider, Frame 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="Slider, Frame 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="Slider, Frame 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="Previous image">
|
||||
<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="Next image">
|
||||
<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="Selecting an Image">
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 1"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 2"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 3"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 4"></button>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<p class="section__prose">
|
||||
The same slider, but with the modifier <code>case-media--wide</code> — extends beyond the content column,
|
||||
like single wide images. The previous/next buttons and dots behave the same way.
|
||||
</p>
|
||||
<figure class="case-media case-media-slider case-media--wide" 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-wide-1.webp" alt="Wide slider, frame 1" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-2.webp" alt="Wide slider, frame 2" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-3.webp" alt="Wide slider, frame 3" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-4.webp" alt="Wide slider, frame 4" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-5.webp" alt="Wide Slider, Frame 5" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-6.webp" alt="Wide slider, frame 6" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-7.webp" alt="Wide slider, frame 7" 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="Previous image">
|
||||
<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="Next image">
|
||||
<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="Selecting an Image">
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 1"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 2"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 3"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 4"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 5"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 6"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 7"></button>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<p class="section__prose">
|
||||
Slider with horizontal (wide) frames of the same size—all images
|
||||
<code>1024×800</code>.
|
||||
</p>
|
||||
<figure class="case-media case-media-slider case-media--natural" data-case-media-slider style="--slider-natural-w: 1024px">
|
||||
<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-wide-1.webp" alt="Wide Slider, Frame 1" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-2.webp" alt="Wide Slider, Frame 2" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-3.webp" alt="Wide Slider, Frame 3" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-4.webp" alt="Wide Slider, Frame 4" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-5.webp" alt="Wide slider, frame 5" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-6.webp" alt="Wide Slider, Frame 6" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-wide-7.webp" alt="Wide Slider, Frame 7" 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="Previous image">
|
||||
<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="Next image">
|
||||
<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="Selecting an Image">
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 1"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 2"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 3"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 4"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 5"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 6"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 7"></button>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<p class="section__prose">
|
||||
The same slider, but with vertical frames of the same size—all images
|
||||
<code>600×800</code>.
|
||||
</p>
|
||||
<figure class="case-media case-media-slider case-media--natural" data-case-media-slider style="--slider-natural-w: 600px">
|
||||
<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-portrait-1.webp" alt="Vertical slider, frame 1" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-portrait-2.webp" alt="Vertical slider, frame 2" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-portrait-3.webp" alt="Vertical slider, frame 3" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-portrait-4.webp" alt="Vertical slider, frame 4" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-portrait-5.webp" alt="Vertical slider, frame 5" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-portrait-6.webp" alt="Vertical slider, frame 6" loading="lazy" decoding="async" data-image-viewer />
|
||||
</div>
|
||||
<div class="case-media-slider__slide">
|
||||
<img src="{{assetPrefix}}assets/template-elements-demo/slider-portrait-7.webp" alt="Vertical slider, frame 7" 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="Previous image">
|
||||
<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="Next image">
|
||||
<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="Selecting an Image">
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 1"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 2"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 3"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 4"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 5"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 6"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 7"></button>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<p class="section__prose">
|
||||
A separate example: a toggle for the frame-switching animation mode—
|
||||
<code>slide</code> (slide), <code>fade</code> (crossfade), and <code>none</code> (no transition).
|
||||
The mode is set by the attribute <code>data-slider-anim</code> on the shape.
|
||||
</p>
|
||||
<figure class="case-media case-media-slider" data-case-media-slider data-slider-anim="fade">
|
||||
<div class="case-media-slider__anim-switch" data-slider-anim-switch role="group" aria-label="Slider Animation Mode">
|
||||
<button type="button" data-mode="slide" aria-pressed="false">Slide</button>
|
||||
<button type="button" data-mode="fade" aria-pressed="true">Fade</button>
|
||||
<button type="button" data-mode="none" aria-pressed="false">None</button>
|
||||
</div>
|
||||
<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="Animation example, frame 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="Animation example, frame 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="Animation example, frame 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="Animation example, frame 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="Previous image">
|
||||
<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="Next image">
|
||||
<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="Selecting an Image">
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 1"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 2"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Image 3"></button>
|
||||
<button type="button" class="case-media-slider__dot" data-slider-dot aria-label="Go to Figure 4"></button>
|
||||
</div>
|
||||
</figure>
|
||||
|
||||
<h3>Callout: Important paragraph with an emoji</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>This is an example of a highlighted callout block. The emoji is aligned to the left and pulses to visually emphasize an important point.</p>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<h3>Video: Card with a shadow and fixed small corners</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" />
|
||||
Your browser does not support video.
|
||||
</video>
|
||||
</div>
|
||||
<figcaption>An example of a case-style video card.</figcaption>
|
||||
</figure>
|
||||
|
||||
<h2>Result</h2>
|
||||
<p class="section__prose">
|
||||
The template is ready to be copied into a new case study: all that’s left is to replace the fish with the actual text and insert the project’s real links and media.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> projects-section-mp}}{{> projects-section}}
|
||||
{{> contact-section}}
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
{{> nav-more-floating}}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,844 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru" data-theme="dark" data-radius="medium">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Nikolai Mamadaev's Resume — Product Designer with over 10 years of experience."
|
||||
/>
|
||||
<title>Resume — Nikolai Mamadaev</title>
|
||||
{{> head-links}}
|
||||
<style>
|
||||
.resume-doc {
|
||||
max-width: 52rem;
|
||||
margin: 0 auto;
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-card);
|
||||
padding: clamp(1.5rem, 3vw, 2.5rem);
|
||||
}
|
||||
.resume-header {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.resume-photo {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
border-radius: var(--radius-sm);
|
||||
object-fit: cover;
|
||||
flex-shrink: 0;
|
||||
order: 1;
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (max-width: 32rem) {
|
||||
.resume-header {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.resume-photo {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
}
|
||||
.resume-doc h2 {
|
||||
margin: 2rem 0 1rem;
|
||||
font-size: clamp(0.95rem, 1.35vw, 1.1rem);
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
letter-spacing: 0.04em;
|
||||
border-top: 1px solid var(--line);
|
||||
padding-top: 1rem;
|
||||
}
|
||||
.resume-doc h2:first-of-type {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
.resume-doc .section__prose + .section__prose {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
.resume-doc .section__prose a {
|
||||
color: var(--accent);
|
||||
}
|
||||
#skills,
|
||||
#about {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
.resume-meta {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5rem 1.5rem;
|
||||
margin: 0.75rem 0 1.5rem;
|
||||
font-size: 0.92rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
@media (max-width: 32rem) {
|
||||
.resume-meta {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.resume-meta dt {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
letter-spacing: 0.03em;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
.resume-meta dd {
|
||||
margin: 0;
|
||||
}
|
||||
.resume-meta a {
|
||||
color: var(--accent);
|
||||
}
|
||||
.resume-exp {
|
||||
margin: 1.5rem 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.resume-exp__header {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.resume-exp__company {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
color: var(--text);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
.resume-exp__meta-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-muted);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.resume-exp__meta-row a {
|
||||
color: var(--accent);
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid var(--accent);
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.resume-exp__meta-row a:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
.resume-exp__sep {
|
||||
color: var(--line);
|
||||
}
|
||||
.resume-exp__period {
|
||||
font-size: 0.8rem;
|
||||
color: var(--text-muted);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.resume-exp__desc {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.92rem;
|
||||
margin: 0.5rem 0;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.resume-exp__section {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.resume-exp__cols {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 10rem;
|
||||
gap: 0 1.5rem;
|
||||
}
|
||||
@media (max-width: 48rem) {
|
||||
.resume-exp__cols {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.resume-exp__section-title {
|
||||
font-weight: 600;
|
||||
font-size: 0.92rem;
|
||||
color: var(--text);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.resume-exp__label {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
letter-spacing: 0.03em;
|
||||
margin: 0.75rem 0 0.35rem;
|
||||
}
|
||||
.resume-exp ul {
|
||||
margin: 0;
|
||||
padding-left: 1.25rem;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.resume-exp li + li {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.resume-skills {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.resume-skill {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.55;
|
||||
}
|
||||
.resume-skill__title {
|
||||
font-weight: 600;
|
||||
color: var(--text);
|
||||
min-width: 8rem;
|
||||
flex-shrink: 0;
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.02em;
|
||||
margin: 0;
|
||||
}
|
||||
.resume-skill__desc {
|
||||
color: var(--text-muted);
|
||||
margin: 0;
|
||||
}
|
||||
.resume-about {
|
||||
margin: 1.5rem 0;
|
||||
font-size: 0.92rem;
|
||||
color: var(--text-muted);
|
||||
line-height: 1.55;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{{> header-minimal}}
|
||||
{{> fab-stack-resume}}
|
||||
<main id="main" class="section section--surface section--tight">
|
||||
<div class="section__inner resume-doc">
|
||||
<div class="resume-header">
|
||||
<img class="resume-photo" src="{{assetPrefix}}assets/index/me_static.webp" alt="Nikolai Mamadaev" width="120" height="120" />
|
||||
<div>
|
||||
<p class="hero__eyebrow">Resume</p>
|
||||
<h1 class="case-page__h1">Nikolai Mamadaev</h1>
|
||||
<p class="section__prose"><strong>Senior UX/UI Designer, Product Designer</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<dl class="resume-meta">
|
||||
<div>
|
||||
<dt>Portfolio</dt>
|
||||
<dd><a href="https://mamadaevv.site" target="_blank" rel="noopener">mamadaevv.site</a></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Salary Range</dt>
|
||||
<dd>250,000 – 310,000 rubles</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Work Format</dt>
|
||||
<dd>Remote</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Email</dt>
|
||||
<dd><a href="mailto:nik@mamadaevv.site">nik@mamadaevv.site</a></dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>Social Media</dt>
|
||||
<dd><a href="https://t.me/mamadaevv" target="_blank" rel="noopener noreferrer">@mamadaevv</a></dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<h2 id="experience">Work Experience</h2>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Astratech</p>
|
||||
<p class="resume-exp__meta-row"><span>January 2026 — Present</span></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Development and support of digital systems and tools to improve employee productivity.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Worked on interface design</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Successfully completed assigned tasks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Figma</li>
|
||||
<li>HTML/CSS</li>
|
||||
<li>AI/LLM</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--line">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Primo RPA</p>
|
||||
<p class="resume-exp__meta-row"><span>February 2023 — November 2025 (2 years and 10 months)</span><a href="https://primo-rpa.com/" target="_blank" rel="noopener noreferrer">·primo-rpa.com</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">A Russian enterprise-grade RPA platform: a suite of desktop robot development environments and web services for management, analytics, and ML. I worked as a lead designer on the entire product line, consisting of 6 products.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">AI Server Platform (SaaS)</p>
|
||||
<p class="resume-exp__desc">A control panel for training, running, testing, and other operations involving neural networks deployed within the company’s internal network.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing the model management interface: training, deployment, testing, versioning, and monitoring</li>
|
||||
<li>Developing workflows for Smart OCR—extracting data from various types of documents</li>
|
||||
<li>Designing document markup and validating recognition results</li>
|
||||
<li>Managing the states of long-running processes: model training, progress, errors, rollback</li>
|
||||
<li>Preparing interactive prototypes and overseeing implementation</li>
|
||||
<li>Conducting interviews with ML engineers and business users to validate behavioral models</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Packaged complex ML logic into an interface that is understandable not only to ML engineers but also to business analysts without a technical background</li>
|
||||
<li>Streamlined work with models into a single, predictable 4-step workflow instead of 9 disparate screens</li>
|
||||
<li>Reduced the time required to configure a new model from 40 to 15 minutes, based on test results</li>
|
||||
<li>Designed a document annotation interface that reduced support requests on this topic by 60%</li>
|
||||
<li>Conducted 8 usability sessions and, based on the results, revised the key model training scenario</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>ML / neural networks</li>
|
||||
<li>Smart OCR</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Robot Automation Studio (Windows)</p>
|
||||
<p class="resume-exp__desc">An environment for developing and debugging robots for business process automation.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing the interface for a professional desktop IDE: workspace, toolbars, process tree, debugger</li>
|
||||
<li>Developing the product’s component library and visual language</li>
|
||||
<li>Designing debugging scenarios: breakpoints, step-by-step execution, variable inspection</li>
|
||||
<li>Designing support for large activity trees and nesting</li>
|
||||
<li>Working in tandem with the development team on component implementation, providing author supervision</li>
|
||||
<li>Conducting regular design reviews within the team</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Updated the product’s visual language to the Windows 10/11 standard—components are now a generation more modern</li>
|
||||
<li>Redesigned over 80 screens and dialogs, bringing them into a unified grid and typography</li>
|
||||
<li>Compiled a library of 140 components, covering 90% of the interface’s needs</li>
|
||||
<li>Converted icons and some illustrations to vector graphics: ensuring correct display at any zoom level and DPI</li>
|
||||
<li>Reduced the time it took the team to build a new screen from 2 days to 4 hours by using pre-built components</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Desktop IDE</li>
|
||||
<li>Windows 10/11</li>
|
||||
<li>Component library</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Robot Automation Studio (Linux)</p>
|
||||
<p class="resume-exp__desc">An environment for developing and debugging robots for business process automation.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Adapting the Studio design for the Linux version using the Avalonia framework</li>
|
||||
<li>Designing components while taking into account the framework’s technical limitations</li>
|
||||
<li>Synchronizing the visual language between the Windows and Linux versions of the product</li>
|
||||
<li>Collaborating with the development team to determine what is technically feasible in Avalonia and what requires workarounds</li>
|
||||
<li>Preparing component behavior specifications for implementation</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Compiled an extensive library of 95 components for Avalonia, which did not exist in the project before I joined</li>
|
||||
<li>Ensured product consistency across two platforms with different technology stacks</li>
|
||||
<li>Reduced the number of visual discrepancies between versions from several dozen to just a few isolated cases</li>
|
||||
<li>Provided the Linux version team with a ready-made set of solutions instead of having to design each screen from scratch</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Avalonia</li>
|
||||
<li>.NET</li>
|
||||
<li>Linux</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Idea Hub Dashboard (SaaS)</p>
|
||||
<p class="resume-exp__desc">Enables the collection and analysis of employee suggestions, performance evaluation, and monitoring of automation implementation status. Analytics on key performance indicators and a high-level view of automation.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing dashboards and analytical views for robotization KPIs</li>
|
||||
<li>Managing the idea lifecycle: submission → evaluation → prioritization → implementation → impact measurement</li>
|
||||
<li>Section information architecture, working with dense tables, filters, and bulk operations</li>
|
||||
<li>Designing a role-based model: employee, analyst, manager</li>
|
||||
<li>Selecting data visualization types for specific management questions</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Integrated high-level analytics and work on a specific idea into a single continuous workflow without switching between sections</li>
|
||||
<li>Designed data visualizations so that managers can see the impact of automation without having to manually export data to Excel</li>
|
||||
<li>Reduced the process from idea submission to evaluation from 6 steps to 3</li>
|
||||
<li>Designed 12 analytics widgets covering customers’ key questions about the ROI of automation</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Analytics / Dashboards</li>
|
||||
<li>KPIs</li>
|
||||
<li>Data Visualization</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Orchestrator Automation Management Tool (SaaS)</p>
|
||||
<p class="resume-exp__desc">Ensures seamless system operation and management of hundreds of robots: launching, monitoring, and management.</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing a management interface for a fleet of hundreds of robots: schedules, queues, priorities, and monitoring</li>
|
||||
<li>Developing state management and error handling for bulk launches</li>
|
||||
<li>Designing a system for notifications and alerts regarding failures</li>
|
||||
<li>Working with complex tables: sorting, filtering, bulk actions, saved views</li>
|
||||
<li>Prototyping complex scenarios for validation prior to development</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Designed a system to manage hundreds of objects so that the operator doesn’t get lost in the scale: from the big picture to a specific robot in just 2 clicks</li>
|
||||
<li>Aligned the service with a unified design system alongside the rest of the product line’s web products</li>
|
||||
<li>Reduced operator response time to robot failures from 12 to 4 minutes thanks to a redesigned alert system</li>
|
||||
<li>Consolidated 5 different robot list views into a single customizable one</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Monitoring</li>
|
||||
<li>Schedules / Queues</li>
|
||||
<li>Notifications / Alerts</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Q&A Portal (WEB)</p>
|
||||
<p class="resume-exp__desc">A platform for posting questions and receiving answers from support</p>
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing workflows for posting questions, providing answers, and searching the accumulated knowledge base</li>
|
||||
<li>Designing the portal interface based on the company’s common design system</li>
|
||||
<li>Developing a role model: user, expert, support team, moderator</li>
|
||||
<li>Designing search mechanics and suggestions for similar questions when posting</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Launched the portal using off-the-shelf components from the design system in 3 weeks instead of the planned 8</li>
|
||||
<li>Reduced the support workload by approximately 25% by reusing existing answers</li>
|
||||
<li>The suggestion feature for similar questions reduced duplicate questions by 45%</li>
|
||||
<li>Ensured visual consistency with other products in the line—the portal does not look like a third-party service</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Web portal</li>
|
||||
<li>Design system</li>
|
||||
<li>Knowledge base</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<p class="resume-exp__section-title">Company-wide</p>
|
||||
<ul>
|
||||
<li>I initiated a visual refresh of the entire product line—the company decided to redesign the products upon my arrival</li>
|
||||
<li>I developed and implemented a unified design system for web services, integrating the company’s brand identity with the new interface structure</li>
|
||||
<li>The design system was adopted by four product teams; it includes 210 components and theming tokens</li>
|
||||
<li>Reduced the average time to prepare mockups across the product line by 35%</li>
|
||||
<li>Created and maintained a UI kit to ensure consistency and accelerate development</li>
|
||||
<li>Conducted more than 20 user studies and usability sessions during my tenure</li>
|
||||
<li>Oversaw implementation, participated in design reviews, product discussions, and release planning</li>
|
||||
<li>Served as the sole lead designer for an entire product line consisting of 6 products and two platforms</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--line">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Lunacy (Icons8)</p>
|
||||
<p class="resume-exp__meta-row"><span>July 2022 – January 2023 (7 months)</span> <span class="resume-exp__sep">·</span> <a href="https://icons8.com/lunacy" target="_blank" rel="noopener noreferrer">icons8.com/lunacy</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">A graphic editor for working on interface designs and other mockups. Similar to Sketch App and Figma.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing the graphic editor’s interface: tools, property panels, working with the canvas and layers</li>
|
||||
<li>Documenting solutions as user flows and handing them off to developers</li>
|
||||
<li>Creating complex interactive prototypes in Protopie to demonstrate tool behavior</li>
|
||||
<li>Illustrating missing icons in the product’s style</li>
|
||||
<li>Making suggestions for improving the editor’s functionality</li>
|
||||
<li>Participating in discussions about product solutions with the team</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Designed 6 functional blocks for the editor, including work with components and styles</li>
|
||||
<li>Created 15+ prototypes in Protopie, which helped eliminate unsuccessful solutions before development</li>
|
||||
<li>Some of my feature suggestions were included in product releases</li>
|
||||
<li>Designed over 60 icons to complement the editor’s system set</li>
|
||||
<li>Worked on a product for a professional audience of designers, where the requirements for interface details are higher than usual</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Protopie</li>
|
||||
<li>Graphics editor</li>
|
||||
<li>Icons / Illustrations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--line">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">MANU Video Game Maker</p>
|
||||
<p class="resume-exp__meta-row"><span>January 2019 — December 2021 (3 years)</span><a href="https://manu.co/" target="_blank" rel="noopener noreferrer">·manu.co</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">A game engine for creating video games without writing code.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>End-to-end product design of the engine: from interaction concepts to the final UI</li>
|
||||
<li>Designing interface behavior for complex user scenarios</li>
|
||||
<li>User research: observation, in-depth interviews, surveys</li>
|
||||
<li>Creating user personas and empathy maps</li>
|
||||
<li>Working with product analytics and metrics tied to user scenarios</li>
|
||||
<li>Layout of the website’s homepage on Tilda, designing the site’s information architecture together with the team</li>
|
||||
<li>Supervising the work of the web graphic designer</li>
|
||||
<li>Hiring for the product department: conducting interviews and selecting specialists</li>
|
||||
<li>Leading the department and establishing workflows for the entire product team</li>
|
||||
<li>Overseeing the creation of user documentation</li>
|
||||
<li>Implementing automation tools (Integromat, Zapier) for internal tasks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Led a large-scale redesign of the entire program: established a fundamentally new concept and style</li>
|
||||
<li>Designed the interface behavior for over 100 complex user scenarios</li>
|
||||
<li>Designed the product’s design system from scratch: 120 components</li>
|
||||
<li>Received a lot of positive, and in some cases enthusiastic, user feedback—the product became much easier to navigate</li>
|
||||
<li>Onboarding completion rates increased from 34% to 58% following the redesign</li>
|
||||
<li>Conducted 25 in-depth interviews and 4 rounds of surveys, and revised 3 key scenarios based on the results</li>
|
||||
<li>Hired 4 specialists for the product department and grew from a designer to a team lead</li>
|
||||
<li>Established departmental processes: design reviews, backlog management, and handoff to development</li>
|
||||
<li>Automated the team’s internal routines, freeing up time for product tasks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Tilda</li>
|
||||
<li>Integromat / Zapier</li>
|
||||
<li>User research</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--line">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Aegees Messenger</p>
|
||||
<p class="resume-exp__meta-row"><span>October 2017 — December 2018 (1 year and 3 months)</span><a href="https://aegees.com/" target="_blank" rel="noopener noreferrer">·aegees.com</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">A cross-platform messenger with secure storage and audio calls.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing the messenger for five platforms simultaneously: Android, iOS, macOS, Windows, and Linux</li>
|
||||
<li>Developing use cases for secure storage and audio calls</li>
|
||||
<li>Designing scenarios for registration, encryption, and access recovery</li>
|
||||
<li>Adapting a unified product logic to each platform’s guidelines</li>
|
||||
<li>Supervising the work of international illustrators in the preparation of graphic assets</li>
|
||||
<li>Preparation of materials for app stores</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Developed a unified visual language for the product while adhering to the guidelines of five platforms simultaneously</li>
|
||||
<li>Designed over 90 screens across five platform versions</li>
|
||||
<li>Ensured a steady flow of graphic assets from external contractors without compromising the design style</li>
|
||||
<li>Simplified the secure storage workflow so that people without technical training could use it</li>
|
||||
<li>Worked in the sensitive areas of privacy and security, where a single interface error can cost user trust</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Android</li>
|
||||
<li>iOS</li>
|
||||
<li>macOS</li>
|
||||
<li>Windows</li>
|
||||
<li>Linux</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--line">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">Orion Innovation (formerly MERA)</p>
|
||||
<p class="resume-exp__meta-row"><span>July 2016 – October 2017 (1 year and 4 months)</span><a href="https://www.orioninnovation.com/" target="_blank" rel="noopener noreferrer">·orioninnovation.com</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Software development for external clients.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Worked in a design department with up to 8 people</li>
|
||||
<li>Creating user personas and mapping product functionality based on user needs</li>
|
||||
<li>Creating wireframes and designing the final UI</li>
|
||||
<li>Designing use cases, screen maps, and micro-animation demos</li>
|
||||
<li>Preparing mood boards and design concepts, and discussing them with clients</li>
|
||||
<li>Preparing and delivering presentations on design concepts</li>
|
||||
<li>Turning mockups into prototypes, writing scripts, and conducting qualitative usability testing</li>
|
||||
<li>Making revisions based on test results</li>
|
||||
<li>Overseeing the implementation of designs by developers</li>
|
||||
<li>Participating in design reviews: analyzing colleagues’ work and defending your own decisions</li>
|
||||
<li>Direct communication with international clients to discuss design and receive project briefs</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Conducted 10 usability testing sessions, from writing the test script to implementing changes</li>
|
||||
<li>Learned to work with the Smart TV platform, which was new to me, and brought the project to successful release in the app store</li>
|
||||
<li>Communicated directly with international clients, without intermediaries</li>
|
||||
<li>Actively participated in improving the company’s design department workflow</li>
|
||||
<li>Completed the full product design cycle on 5 client projects</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Smart TV</li>
|
||||
<li>Usability testing</li>
|
||||
<li>Mood boards / design concepts</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--line">
|
||||
|
||||
<div class="resume-exp">
|
||||
<div class="resume-exp__header">
|
||||
<p class="resume-exp__company">SpaceshipApps Studio</p>
|
||||
<p class="resume-exp__meta-row"><span>June 2015 — June 2016 (1 year and 1 month)</span><a href="https://spaceshipapps.ru/" target="_blank" rel="noopener noreferrer">·spaceshipapps.ru</a></p>
|
||||
</div>
|
||||
<p class="resume-exp__desc">Mobile app and website development studio.</p>
|
||||
|
||||
<div class="resume-exp__section">
|
||||
<div class="resume-exp__cols">
|
||||
<div>
|
||||
<p class="resume-exp__label">Responsibilities:</p>
|
||||
<ul>
|
||||
<li>Designing mobile and web products as part of the studio’s workflow</li>
|
||||
<li>Worked across various sectors: social gaming, beauty services, food delivery, voice interfaces, legal services, and collaborative tools</li>
|
||||
<li>Responsive web design and design of administrative dashboards</li>
|
||||
<li>Illustrating icons and preparing graphics for projects</li>
|
||||
<li>Preparing mockups for handoff to development</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Achievements:</p>
|
||||
<ul>
|
||||
<li>Launched 6 products in one year: a geolocation-based social game with real-world quests, an app for booking beauty professionals, a food delivery service, a voice-based word game, a website and admin panel for a copyright registration service, and a mobile “whiteboard” for collaboration</li>
|
||||
<li>Learned to quickly get up to speed in new subject areas and maintain quality while keeping up with the studio’s fast pace</li>
|
||||
<li>Handled the full range of tasks: mobile, web, admin panels, and graphics</li>
|
||||
<li>Laid the groundwork for transitioning from execution-focused design to product-focused design</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<p class="resume-exp__label">Stack:</p>
|
||||
<ul>
|
||||
<li>Mobile</li>
|
||||
<li>Web</li>
|
||||
<li>Dashboards</li>
|
||||
<li>Graphics</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<h2 id="skills">Skills</h2>
|
||||
<div class="resume-skills">
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Design</p>
|
||||
<p class="resume-skill__desc">UX/UI, product design, information architecture, responsive design, design systems</p>
|
||||
</div>
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Research</p>
|
||||
<p class="resume-skill__desc">Interviews, surveys, usability testing, JTBD, empathy maps, conversion, retention, NPS</p>
|
||||
</div>
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Tools</p>
|
||||
<p class="resume-skill__desc">Figma, Protopie, Sketch, Adobe Creative Suite, Tilda, AI tools</p>
|
||||
</div>
|
||||
<div class="resume-skill">
|
||||
<p class="resume-skill__title">Management</p>
|
||||
<p class="resume-skill__desc">Team building, Agile, Kanban, project supervision, working with stakeholders</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr class="sep sep--air">
|
||||
|
||||
<h2 id="about">About Me</h2>
|
||||
<p class="section__prose resume-about">
|
||||
I’ve been in design for over 10 years, and in recent years I’ve focused on product design for complex B2B products. I work at the intersection of design and product management: I conduct research, formulate hypotheses and features, help with prioritization, and participate in release planning.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
I love diving into complex topics and making them understandable—which is why I feel right at home with products like IDEs, orchestration tools, and ML dashboards, where a typical designer might find the work boring or intimidating.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
I don’t wait for someone else to solve a problem—I build my own tools. I’ve created a private AI plugin for Figma, automate processes using n8n and PostgreSQL, and turn my ideas into working products through AI-assisted development. My skills for Alisa have attracted over 37,000 and 33,000 users, and the Slider Set file for designers has been downloaded more than 20,000 times.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
I’m active in the community: I run the Telegram channel “Design Isn’t Pizza,” share useful resources on the Figma Community, gave a talk on analytics at a Yandex meetup, and have won hackathons—my most memorable victory was at the Yandex.I’m currently in St. Petersburg working on a QR code payment app.
|
||||
</p>
|
||||
<p class="section__prose resume-about">
|
||||
English—B1. I work remotely and communicate smoothly with a distributed team.
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{> footer}}
|
||||
{{> cookie-notice}}
|
||||
<script>
|
||||
(function () {
|
||||
var printBtn = document.querySelector('[data-resume-print-btn]');
|
||||
if (!printBtn) return;
|
||||
|
||||
printBtn.addEventListener('click', function () {
|
||||
var doc = document.querySelector('.resume-doc');
|
||||
if (!doc) return;
|
||||
|
||||
var styles = [];
|
||||
document.querySelectorAll('link[rel="stylesheet"]').forEach(function (l) {
|
||||
styles.push('<link rel="stylesheet" href="' + l.href + '">');
|
||||
});
|
||||
document.querySelectorAll('style').forEach(function (s) {
|
||||
styles.push('<style>' + s.textContent + '</style>');
|
||||
});
|
||||
|
||||
var win = window.open('', '_blank');
|
||||
if (!win) return;
|
||||
win.document.write(
|
||||
'<!DOCTYPE html><html><head><meta charset="utf-8">' +
|
||||
styles.join('') +
|
||||
'<style>@media print{body{margin:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;}}</style>' +
|
||||
'</head><body>' + doc.outerHTML + '</body></html>'
|
||||
);
|
||||
win.document.close();
|
||||
win.onload = function () {
|
||||
setTimeout(function () { win.print(); }, 500);
|
||||
};
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="content-edit-fab-stack" aria-label="Content Edits" 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="Content Editing Mode"
|
||||
title="Edit Mode"
|
||||
>
|
||||
<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>
|
||||
@@ -1,12 +1,12 @@
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies for a comfortable experience. Read more in
|
||||
<a href="{{pagePrefix}}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>Accept</span>
|
||||
<span class="cookie-notice__accept-icon" aria-hidden="true">
|
||||
<img src="{{assetPrefix}}assets/shared/icons/сookie.svg" alt="" width="20" height="20" loading="eager" decoding="async" />
|
||||
</span>
|
||||
</button>
|
||||
</aside>
|
||||
<aside class="cookie-notice glass-neutral" hidden data-cookie-notice>
|
||||
<p class="cookie-notice__text">
|
||||
This site uses cookies to ensure a smooth user experience. For more information, see the
|
||||
<a href="{{pagePrefix}}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>Accept</span>
|
||||
|
||||
<span class="cookie-notice__accept-icon" aria-hidden="true"><img src="{{assetPrefix}}assets/shared/icons/сookie.svg" alt="" width="20" height="20" loading="eager" decoding="async" /></span>
|
||||
|
||||
</button>
|
||||
</aside>
|
||||
@@ -0,0 +1,62 @@
|
||||
<div class="fab-stack" aria-label="Quick Actions">
|
||||
<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="Style Settings">
|
||||
<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="Theme and Design" 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">Accent Color</h3>
|
||||
<div class="colorpicker" data-colorpicker>
|
||||
<div class="colorpicker__plane-box">
|
||||
<canvas class="colorpicker__plane" width="320" height="180" data-sl-canvas aria-label="Saturation and brightness of the accent"></canvas>
|
||||
<div class="colorpicker__knob" data-sl-knob></div>
|
||||
</div>
|
||||
<div class="colorpicker__hue-wrap">
|
||||
<label class="colorpicker__hue-sr" for="theme-hue-slider">Accent shade</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">Theme</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="As in the system"><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="Light-colored theme"><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="Dark Theme"><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">Corner Rounding</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="Slight rounding"><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="Average rounding"><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="Significant rounding"><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">Typography</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">Page Background</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="Show background gradient"><span class="theme-mesh-bg-seg__label">On</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="Hide the background gradient"><span class="theme-mesh-bg-seg__label">Off</span></button>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="fab fab--primary" href="{{pagePrefix}}#contact" aria-label="Contact Us">
|
||||
<span class="fab-primary__ico" aria-hidden="true"></span>
|
||||
</a>
|
||||
</div>
|
||||
{{> content-edit-fab-stack}}
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="fab-stack" aria-label="Quick Actions">
|
||||
<div class="theme-panel-fab-wrap">
|
||||
<button type="button" class="fab fab--secondary glass-neutral" data-resume-print-btn aria-label="Print Resume">
|
||||
<span class="fab-secondary__ico fab-secondary__ico--print" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
<a href="/assets/resume/Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf" download="Mamadaev_Nik__CV__Product_Designer_UX-UI.pdf" class="fab fab--primary fab--label" aria-label="Download the resume as a PDF">
|
||||
<span class="fab-primary__ico fab-primary__ico--pdf" aria-hidden="true"></span>
|
||||
<span class="fab__label">Download as PDF</span>
|
||||
</a>
|
||||
</div>
|
||||
{{> content-edit-fab-stack}}
|
||||
@@ -0,0 +1,3 @@
|
||||
<section class="section section--surface" aria-hidden="true">
|
||||
<div class="section__inner"></div>
|
||||
</section>
|
||||
@@ -0,0 +1,8 @@
|
||||
<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">{{i18n:footer.credit}}</span> ·<span class="footer__chunk footer__chunk--meta footer__attr"><span class="footer__sep" aria-hidden="true"> </span><a href="{{pagePrefix}}cases/design-system/">{{i18n:footer.designSystem}}</a><span class="footer__sep" aria-hidden="true">·
|
||||
</span><a href="{{pagePrefix}}cookie-policy/">{{i18n:footer.cookiePolicy}}</a></span> ·<span class="footer__chunk footer__chunk--lang"><span class="footer__sep" aria-hidden="true">
|
||||
</span>{{> lang-switch}}</span></div>
|
||||
</footer>
|
||||
@@ -0,0 +1 @@
|
||||
<link rel="stylesheet" href="/vendor/plyr/plyr.css" />
|
||||
@@ -0,0 +1,2 @@
|
||||
<script src="/js/skill-connectors.js" defer></script>
|
||||
<script type="module" src="/js/main.js"></script>
|
||||
@@ -1,7 +1,7 @@
|
||||
<a class="skip-link" href="#case-main">{{i18n:skip.case}}</a>
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="{{pagePrefix}}" aria-label="{{i18n:logo.aria}}">НМ</a>
|
||||
<a class="logo" href="{{pagePrefix}}" aria-label="{{i18n:logo.aria}}">{{i18n:logo.text}}</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="{{i18n:nav.aria}}">
|
||||
<a href="#contact">{{i18n:nav.contact}}</a>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="#" aria-label="{{i18n:logo.aria}}">НМ</a>
|
||||
<a class="logo" href="#" aria-label="{{i18n:logo.aria}}">{{i18n:logo.text}}</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="{{i18n:nav.aria}}" data-top-nav>
|
||||
<a href="#projects">{{i18n:nav.projects}}</a>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<header class="header" data-theme-picker>
|
||||
<div class="header__inner">
|
||||
<a class="logo" href="{{pagePrefix}}" aria-label="{{i18n:logo.aria}}">НМ</a>
|
||||
<a class="logo" href="{{pagePrefix}}" aria-label="{{i18n:logo.aria}}">{{i18n:logo.text}}</a>
|
||||
<div class="header__cluster">
|
||||
<nav class="nav" aria-label="{{i18n:nav.aria}}">
|
||||
<a href="{{pagePrefix}}">{{i18n:back.home}}</a>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<nav class="lang-switch" aria-label="{{i18n:lang.aria}}" data-lang-switch>
|
||||
<a class="lang-switch__btn" data-lang="ru" href="/">{{i18n:lang.ru}}</a>
|
||||
<a class="lang-switch__btn" data-lang="en" href="/en/">{{i18n:lang.en}}</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 b = links[i];
|
||||
var l = b.getAttribute("data-lang");
|
||||
b.setAttribute("href", (l === "en" ? "/en/" : "/") + base);
|
||||
if ((l === "en") === isEn) b.setAttribute("aria-current", "true");
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,52 @@
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">See also</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-assistant">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="{{casesPrefix}}ai-assistant-figma/"
|
||||
aria-label="AI Assistant — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">AI Assistant</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Figma plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">A Figma plugin with AI features.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="card-columns">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="{{casesPrefix}}card-columns-obsidian/"
|
||||
aria-label="Card Columns — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Card Columns</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Obsidian Plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">A plugin for displaying cards in columns in Obsidian.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3" data-mp-cells-sm="2" data-related-slug="site-with-ai-ide">
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="{{casesPrefix}}site-with-ai-ide/"
|
||||
aria-label="This website — Open a Case"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">This website</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Development with AI IDE</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Website development using AI IDE.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,190 @@
|
||||
<ol
|
||||
id="mini-projects-showcase-grid"
|
||||
class="mini-projects-grid mp-showcase-grid"
|
||||
data-mini-projects-list
|
||||
>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[2] stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[2] stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">website</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">A base pair in a row of six cells.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<div class="mp-card mp-card--stack">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">[2] stack</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">note</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Stack without an external link.</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<div class="mp-card mp-card--horizontal">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="360"
|
||||
height="203"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">[2] horizontal</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">utility</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Horizontal, two cells wide, without a link.</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<article class="mp-card mp-card--compact">
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">[2] compact</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">template</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">A two-cell text card.</p>
|
||||
</div>
|
||||
</article>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="1">
|
||||
<a class="mp-card mp-card--link mp-card--compact" href="#" aria-label="[1] compact · link">
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[1] compact · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">cli</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">A narrow column with a link.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="1">
|
||||
<article class="mp-card mp-card--compact">
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">[1] compact</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">document</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Compact, one cell wide.</p>
|
||||
</div>
|
||||
</article>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="2">
|
||||
<div class="mp-card mp-card--decor" aria-hidden="true">
|
||||
<span class="mp-card__decor-pattern" aria-hidden="true"></span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3">
|
||||
<a class="mp-card mp-card--link mp-card--stack" href="#" aria-label="[3] stack · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[3] stack · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Appendix</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
Half of a six-cell row. A longer description to check for line breaks and height after changing the font.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3">
|
||||
<a class="mp-card mp-card--link mp-card--horizontal" href="#" aria-label="[3] horizontal · link">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="360"
|
||||
height="203"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
[3] horizontal · link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">plugin</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Wide horizontal: preview and text in a single column.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<li class="mini-projects-grid__item" data-mp-cells="3">
|
||||
<div class="mp-card mp-card--horizontal">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="360"
|
||||
height="203"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">[3] horizontal</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">widget</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Three-cell Horizontal, without a link.</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
@@ -0,0 +1,217 @@
|
||||
<div class="mp-showcase-specimens" aria-label="Card Types">
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--stack</code> + <code>mp-card--link</code></p>
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--stack"
|
||||
href="#"
|
||||
aria-label="Stack with a link — example card"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Stack with a link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">website</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
A small script: drafts generated from keywords, without external APIs.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Stack with a link.</strong> Full-width preview, text at the bottom. For an external link:
|
||||
<code>mp-card--link</code> and <code>mp-card__ext</code> in the title (as in the "Experience" block).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--stack</code> without a link</p>
|
||||
<div class="mp-card mp-card--stack">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="560"
|
||||
height="315"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Stack without a link</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">note</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
A collection of databases and a rollup for a weekly overview, for personal use only.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Stack without a link.</strong> Same view. Wrapper <code>div</code> or <code>article</code>, without
|
||||
<code>mp-card--link</code>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--horizontal</code> + <code>mp-card--link</code></p>
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--horizontal"
|
||||
href="#"
|
||||
aria-label="Horizontal with a link — example card"
|
||||
>
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="360"
|
||||
height="203"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Horizontal with a link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">app</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
Local timer with short sounds and a feature to block unnecessary tabs.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Horizontal with a link.</strong> Thumbnail on the left, text on the right. On a narrow screen, the card
|
||||
stacks vertically.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--horizontal</code> No link</p>
|
||||
<div class="mp-card mp-card--horizontal">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="../assets/shared/placeholder.webp"
|
||||
alt=""
|
||||
width="360"
|
||||
height="203"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</div>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Horizontal without a link</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Template</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
Static website with a schedule and an application form on a separate service.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Horizontal without a link.</strong> Same layout; the card does not link to an external URL.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--compact</code> + <code>mp-card--link</code></p>
|
||||
<a
|
||||
class="mp-card mp-card--link mp-card--compact"
|
||||
href="#"
|
||||
aria-label="Compact with a link — example card"
|
||||
>
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">
|
||||
Compact with a link
|
||||
|
||||
<span class="mp-card__ext" aria-hidden="true"></span></h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">script</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
Prefixes, numbering, and a dry run before writing files to disk.
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Compact with a link.</strong> Text only, no <code>mp-card__media</code>. In the grid, often with
|
||||
<code>data-mp-cells="1"</code>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--compact</code> no link</p>
|
||||
<article class="mp-card mp-card--compact">
|
||||
<div class="mp-card__body">
|
||||
<h3 class="mp-card__title">Compact without a link</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">document</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">
|
||||
Markdown checklist before releasing minor UI changes.
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Compact without a link.</strong> A short note or checklist without an external link.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mp-showcase-specimen-row">
|
||||
<div class="mp-showcase-specimen__card">
|
||||
<p class="mp-showcase-specimen__label"><code>mp-card--decor</code></p>
|
||||
<div class="mp-card mp-card--decor" aria-hidden="true">
|
||||
<span class="mp-card__decor-pattern" aria-hidden="true"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mp-showcase-specimen__desc">
|
||||
<p class="section__prose">
|
||||
<strong>Decorative cell.</strong> A placeholder in the grid, with no project or link. Inside
|
||||
<code>span.mp-card__decor-pattern</code>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
<div id="nav-more-menu-floating" class="nav-more__floating" hidden data-nav-more-menu-floating aria-hidden="true"></div>
|
||||
@@ -0,0 +1,2 @@
|
||||
<script src="/js/skill-connectors.js" defer></script>
|
||||
<script type="module" src="/js/main.js"></script>
|
||||
@@ -0,0 +1,167 @@
|
||||
<section class="section section--surface" data-reveal>
|
||||
<div class="section__inner">
|
||||
<h2 class="section__title">See also</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="{{casesPrefix}}ai-platform-primo-rpa/" aria-label="AI Platform — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">An interface for training and using AI models in business processes: working with data, automation scenarios, and 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="{{casesPrefix}}lunacy/" aria-label="Lunacy Image Editor — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Worked on the Lunacy interface as part of the Icons8 team: user flow, complex prototypes, and improvements to functionality and interface logic.</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="{{casesPrefix}}manu-game-maker/" aria-label="MANU Game Engine — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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 Game Engine</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Desktop App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Redesign and development of the game engine’s user interface: a new operational concept, an updated visual system, and the development of hundreds of complex user scenarios.</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="{{casesPrefix}}mobile-clinic-app/" aria-label="Mobile app for a network of clinics — open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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">Mobile app for a network of clinics</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Mobile App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Design of a mobile app for scheduling doctor appointments and managing medical services. Focus on a simple user journey, intuitive navigation, and quick access to necessary actions.</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="{{casesPrefix}}orc-automation-panel/" aria-label="Web Panel for Automation Orchestration — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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="Project Type">
|
||||
<li class="mp-card__tag">Mentoring and Coaching</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Primo RPA orchestrator’s web dashboard: projects, deployment, and monitoring of RPA robots. Redesign of key screens for production without interrupting releases.</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="{{casesPrefix}}task-distribution-concept/" aria-label="The concept of a task-assignment service—open a case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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">Task Distribution Service Concept</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">UX/UI</li>
|
||||
<li class="mp-card__tag">Analytics</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">Product concept for a service to create, assign, and track tasks, with an emphasis on process transparency and seamless teamwork.</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="{{casesPrefix}}task-tracker/" aria-label="Task Tracker for the Back-Office System — Open a Case">
|
||||
<div class="mp-card__media" aria-hidden="true">
|
||||
<img
|
||||
class="mp-card__image"
|
||||
src="{{assetPrefix}}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">Task tracker for a back-office system</h3>
|
||||
<ul class="mp-card__tags" aria-label="Project Type">
|
||||
<li class="mp-card__tag">Product Design</li>
|
||||
<li class="mp-card__tag">Web App</li>
|
||||
</ul>
|
||||
<p class="mp-card__desc">An interface for planning and assigning tasks in the operations department: shared pool, personal to-do list, overview by assignee; tabs, filters, board/list/table views, and drag-and-drop functionality.</p>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,80 @@
|
||||
<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>
|
||||
Reference in new issue
Block a user