1159 lines
69 KiB
HTML
1159 lines
69 KiB
HTML
<!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="A demo page for the case study featuring all the developed elements: link cards and media blocks." />
|
||
<title>Case Study Elements Demo — template</title>
|
||
<script>
|
||
(function () {
|
||
var FONT_CSS = {
|
||
merriweather: "/assets/fonts/merriweather.css",
|
||
geologica: "/assets/fonts/geologica.css",
|
||
mono: "/assets/fonts/mono.css",
|
||
};
|
||
try {
|
||
var t = JSON.parse(localStorage.getItem("siteThemeV1") || "{}");
|
||
var d = document.documentElement;
|
||
var m = t.mode;
|
||
if (m !== "light" && m !== "dark" && m !== "system") m = "system";
|
||
var eff =
|
||
m === "system"
|
||
? window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
|
||
? "dark"
|
||
: "light"
|
||
: m;
|
||
d.dataset.theme = eff;
|
||
var h = typeof t.h === "number" ? t.h : typeof t.hue === "number" ? t.hue : null;
|
||
var s = typeof t.s === "number" ? t.s : typeof t.sat === "number" ? t.sat : null;
|
||
var l = typeof t.l === "number" ? t.l : typeof t.light === "number" ? t.light : null;
|
||
if (h !== null) d.style.setProperty("--theme-h", String(h));
|
||
if (s !== null) d.style.setProperty("--theme-s", String(s));
|
||
if (l !== null) {
|
||
var L = Number(l);
|
||
if (Number.isFinite(L)) d.style.setProperty("--theme-l", String(Math.min(70, Math.max(20, L))));
|
||
}
|
||
var hVal = h !== null ? h : 210;
|
||
var sVal = s !== null ? s : 90;
|
||
var lVal = l !== null ? Math.min(70, Math.max(20, Number(l))) : 40;
|
||
var H = (((hVal % 360) + 360) % 360) / 360;
|
||
var S = Math.min(100, Math.max(0, sVal)) / 100;
|
||
var Lv = Math.min(100, Math.max(0, lVal)) / 100;
|
||
var r, g, b;
|
||
if (S === 0) { r = g = b = Lv; }
|
||
else {
|
||
var q = Lv < 0.5 ? Lv * (1 + S) : Lv + S - Lv * S;
|
||
var p = 2 * Lv - q;
|
||
var hue2rgb = function(p, q, t) {
|
||
if (t < 0) t += 1; if (t > 1) t -= 1;
|
||
if (t < 1/6) return p + (q - p) * 6 * t;
|
||
if (t < 1/2) return q;
|
||
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
|
||
return p;
|
||
};
|
||
r = hue2rgb(p, q, H + 1/3);
|
||
g = hue2rgb(p, q, H);
|
||
b = hue2rgb(p, q, H - 1/3);
|
||
}
|
||
var lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||
d.style.setProperty("--on-accent", lum > 0.58 ? "hsl(220 14% 12%)" : "hsl(0 0% 98%)");
|
||
var rad = t.radius;
|
||
if (rad === "soft" || rad === "medium" || rad === "strong") {
|
||
d.dataset.radius = rad;
|
||
} else {
|
||
d.dataset.radius = "medium";
|
||
}
|
||
var f = t.font;
|
||
if (f === "onest") f = "geologica";
|
||
if (f === "anonymous") f = "mono";
|
||
if (f !== "merriweather" && f !== "mono" && f !== "geologica") f = "merriweather";
|
||
d.dataset.font = f;
|
||
var mb = t.meshBg;
|
||
if (mb === "off") {
|
||
d.dataset.meshBg = "off";
|
||
} else {
|
||
d.dataset.meshBg = "on";
|
||
}
|
||
var href = FONT_CSS[f];
|
||
if (href && !document.querySelector('link[data-theme-font="' + f + '"]')) {
|
||
var link = document.createElement("link");
|
||
link.rel = "stylesheet";
|
||
link.href = href;
|
||
link.setAttribute("data-theme-font", f);
|
||
document.head.appendChild(link);
|
||
}
|
||
} catch (e) {}
|
||
})();
|
||
</script>
|
||
|
||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon/favicon-32x32.png" />
|
||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon/favicon-16x16.png" />
|
||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/favicon/apple-touch-icon.png" />
|
||
<link rel="manifest" href="/assets/favicon/site.webmanifest" />
|
||
<link rel="preload" href="/assets/fonts/merriweather.css" as="style" />
|
||
<link rel="preload" href="/css/main.css" as="style" />
|
||
<link rel="preload" href="/js/skill-connectors.js" as="script" />
|
||
<link rel="modulepreload" href="/js/main.js" />
|
||
<link rel="stylesheet" href="/css/main.css" />
|
||
<script src="/js/skill-connectors.js" defer></script>
|
||
<script type="module" src="/js/main.js"></script>
|
||
|
||
|
||
<link rel="stylesheet" href="/vendor/plyr/plyr.css" />
|
||
|
||
<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>
|
||
<a class="skip-link" href="#main">Skip to main content</a>
|
||
|
||
<header class="header" data-theme-picker>
|
||
<div class="header__inner">
|
||
<a class="logo" href="../../" aria-label="Home">NM</a>
|
||
<div class="header__cluster">
|
||
<nav class="nav" aria-label="Page sections">
|
||
<a href="../../">Home</a>
|
||
</nav>
|
||
</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">
|
||
<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 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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../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="../../../assets/template-elements-demo/video-1.webp" data-case-video-player style="display: block; width: 100%; height: auto">
|
||
<source src="../../../assets/template-elements-demo/video-1.webm" type="video/webm" />
|
||
<source src="../../../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>
|
||
|
||
<section id="projects" class="section section--surface" data-reveal>
|
||
<div class="section__inner">
|
||
<h2 class="section__title">Portfolio</h2>
|
||
<ol class="mini-projects-grid" data-mini-projects-list>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="ai-platform-primo-rpa">
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../ai-platform-primo-rpa/" aria-label="AI platform — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/ai-platform-primo-rpa/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">Primo AI Server</h3>
|
||
<ul class="mp-card__tags" aria-label="Project type">
|
||
<li class="mp-card__tag">UX/UI</li>
|
||
<li class="mp-card__tag">Web App</li>
|
||
</ul>
|
||
<p class="mp-card__desc">Interface for training and using AI models in business processes: data work, automation scenarios, and Smart OCR.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="lunacy">
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../lunacy/" aria-label="Graphics editor Lunacy — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/lunacy/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">Lunacy</h3>
|
||
<ul class="mp-card__tags" aria-label="Project type">
|
||
<li class="mp-card__tag">UX/UI</li>
|
||
<li class="mp-card__tag">Desktop App</li>
|
||
</ul>
|
||
<p class="mp-card__desc">Work on the Lunacy interface at Icons8: user flows, complex prototypes, improved functionality and interface logic.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="manu-game-maker" hidden>
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../manu-game-maker/" aria-label="MANU game engine — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/manu-game-maker/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">MANU 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 evolution of the game engine interface: a new working concept, refreshed visual system, and hundreds of complex user scenarios worked through.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="mobile-clinic-app" hidden>
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../mobile-clinic-app/" aria-label="Mobile app for a clinic network — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/mobile-clinic-app/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">Mobile app for a clinic network</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 booking doctors and managing medical services. Focus on a simple user path, clear navigation, and quick access to the right actions.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="orc-automation-panel">
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../orc-automation-panel/" aria-label="Web panel for automation orchestration — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/orc-primo-rpa/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">Primo Orc</h3>
|
||
<ul class="mp-card__tags" aria-label="Project type">
|
||
<li class="mp-card__tag">Mentoring & coaching</li>
|
||
</ul>
|
||
<p class="mp-card__desc">Primo RPA orchestrator web console: projects, launch and control of RPA bots. Redesign of key screens for production without halting releases.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="task-distribution-concept" hidden>
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../task-distribution-concept/" aria-label="Task distribution service concept — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/task-distribution-concept/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">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">A product concept for a service to set, distribute and track tasks, with emphasis on process transparency and comfortable teamwork.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
<li class="mini-projects-grid__item" data-mp-cells="2" data-related-slug="task-tracker" hidden>
|
||
<a class="mp-card mp-card--link mp-card--reflect" href="../task-tracker/" aria-label="Task tracker for a back-office system — open case">
|
||
<div class="mp-card__media" aria-hidden="true">
|
||
<img
|
||
class="mp-card__image"
|
||
src="../../../assets/task-tracker/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
loading="lazy"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
<div class="mp-card__body">
|
||
<h3 class="mp-card__title">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">Interface for planning and distributing tasks in the operations department: shared pool, personal ToDo, per-assignee overview; tabs, filters, board / list / table views, drag & drop.</p>
|
||
</div>
|
||
</a>
|
||
</li>
|
||
</ol>
|
||
</div>
|
||
<script>
|
||
document.querySelectorAll('.mp-card--reflect').forEach(function (c) {
|
||
var i = c.querySelector('.mp-card__image');
|
||
if (i) c.style.setProperty('--card-cover', 'url("' + i.src + '")');
|
||
});
|
||
</script>
|
||
</section>
|
||
<section hidden class="section section--surface" aria-hidden="true">
|
||
<div class="section__inner">
|
||
<div class="projects__heading">
|
||
<h2 class="section__title projects__title">Portfolio</h2>
|
||
<div class="projects__controls" aria-label="Portfolio card navigation">
|
||
<button type="button" class="projects__nav-btn" data-projects-prev aria-label="Scroll left" aria-controls="projects-viewport">
|
||
<span class="projects__nav-ico projects__nav-ico--left" aria-hidden="true"></span>
|
||
</button>
|
||
<button type="button" class="projects__nav-btn" data-projects-next aria-label="Scroll right" aria-controls="projects-viewport">
|
||
<span class="projects__nav-ico projects__nav-ico--right" aria-hidden="true"></span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="projects-carousel">
|
||
<div id="projects-viewport" class="projects-carousel__viewport" data-projects-viewport>
|
||
<div class="projects-carousel__track">
|
||
<div class="projects-carousel__spacer" aria-hidden="true"></div>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../orc-automation-panel/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Web panel for automation orchestration</h3>
|
||
<p class="portfolio-card__summary">
|
||
Primo RPA orchestrator web console: projects, launch and control of RPA bots. Redesign of key screens for production without halting releases.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">UX/UI</li>
|
||
<li class="portfolio-card__tag">Web App</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/orc-primo-rpa/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../ai-platform-primo-rpa/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Platform for working with AI</h3>
|
||
<p class="portfolio-card__summary">
|
||
Interface for training and using AI models in business processes: data work, automation scenarios, and Smart OCR.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">UX/UI</li>
|
||
<li class="portfolio-card__tag">Web App</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/ai-platform-primo-rpa/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../task-tracker/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Task tracker for a back-office system</h3>
|
||
<p class="portfolio-card__summary">
|
||
Interface for planning and distributing tasks in the operations department: shared pool, personal ToDo, per-assignee overview; tabs, filters, board / list / table views, drag & drop.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">Product Design</li>
|
||
<li class="portfolio-card__tag">Web App</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/task-tracker/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../manu-game-maker/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">MANU game engine</h3>
|
||
<p class="portfolio-card__summary">
|
||
Redesign and evolution of the game engine interface: a new working concept, refreshed visual system, and hundreds of complex user scenarios worked through.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">Product Design</li>
|
||
<li class="portfolio-card__tag">Desktop App</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/manu-game-maker/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../lunacy/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Graphics editor Lunacy</h3>
|
||
<p class="portfolio-card__summary">
|
||
Work on the Lunacy interface at Icons8: user flows, complex prototypes, improved functionality and interface logic.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">UX/UI</li>
|
||
<li class="portfolio-card__tag">Desktop App</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/lunacy/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../mobile-clinic-app/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Mobile app for a clinic network</h3>
|
||
<p class="portfolio-card__summary">
|
||
Design of a mobile app for booking doctors and managing medical services. Focus on a simple user path, clear navigation, and quick access to the right actions.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">UX/UI</li>
|
||
<li class="portfolio-card__tag">Mobile App</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/mobile-clinic-app/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../task-distribution-concept/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Task distribution service concept</h3>
|
||
<p class="portfolio-card__summary">
|
||
A product concept for a service to set, distribute and track tasks, with emphasis on process transparency and comfortable teamwork.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">UX/UI</li>
|
||
<li class="portfolio-card__tag">Analytics</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/task-distribution-concept/cover.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<article class="projects-carousel__item">
|
||
<a class="portfolio-card portfolio-card--bleed" href="../obsidian-plugin-columns-view/">
|
||
<div class="portfolio-card__body">
|
||
<h3 class="portfolio-card__title">Columns view — plugin for Obsidian</h3>
|
||
<p class="portfolio-card__summary">
|
||
Interface for multi-column note work: convenient navigation, filtering and column-view settings right inside the Obsidian editor.
|
||
</p>
|
||
<ul class="portfolio-card__tags" aria-label="Key tags">
|
||
<li class="portfolio-card__tag">UX/UI</li>
|
||
<li class="portfolio-card__tag">Plugin</li>
|
||
</ul>
|
||
</div>
|
||
<div class="portfolio-card__cover" aria-hidden="true">
|
||
<img
|
||
class="portfolio-card__image"
|
||
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
|
||
data-defer-src="../../../assets/obsidian-plugin-columns-view/filter use.webp"
|
||
alt=""
|
||
width="400"
|
||
height="225"
|
||
decoding="async"
|
||
/>
|
||
</div>
|
||
</a>
|
||
</article>
|
||
<div class="projects-carousel__spacer" aria-hidden="true"></div>
|
||
</div>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
class="projects-carousel__edge-hit projects-carousel__edge-hit--left"
|
||
data-projects-edge-prev
|
||
aria-label="Scroll portfolio left"
|
||
></button>
|
||
<button
|
||
type="button"
|
||
class="projects-carousel__edge-hit projects-carousel__edge-hit--right"
|
||
data-projects-edge-next
|
||
aria-label="Scroll portfolio right"
|
||
></button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="contact" class="section section--surface section--footerish" data-reveal>
|
||
<div class="section__inner">
|
||
<h2 class="section__title">Contact</h2>
|
||
<ul class="contact-grid">
|
||
<li><a class="contact-card contact-card--link contact-card--brand-tg" href="https://t.me/mamadaevv" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../../assets/shared/icons/tg.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">Telegram</span><span class="contact-card__hint">I'll reply today</span></span></a></li>
|
||
<li><a class="contact-card contact-card--link contact-card--brand-whatsapp" href="https://wa.me/qr/E2AWW5ZHE3ANJ1" rel="noopener noreferrer"><span class="contact-card__corner" aria-hidden="true"></span><span class="contact-card__icon" aria-hidden="true"><img src="../../../assets/shared/icons/whatsapp.svg" alt="" width="24" height="24" loading="eager" decoding="async" /></span><span class="contact-card__body"><span class="contact-card__name">WhatsApp</span><span class="contact-card__hint">Stable connection</span></span></a></li>
|
||
|
||
<li><button type="button" class="contact-card contact-card--action contact-card--brand-email" data-contact-copy data-email-b64="bmlrQG1hbWFkYWV2di5zaXRl" data-hint-default="Copy address" aria-label="Copy email address to clipboard"><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">Email</span><span class="contact-card__hint" data-contact-copy-hint>Copy address</span></span></button></li>
|
||
</ul>
|
||
</div>
|
||
</section>
|
||
|
||
<footer class="footer">
|
||
<div class="footer__inner">
|
||
<span class="footer__chunk footer__chunk--date">© 2015–2026<span class="footer__sep" aria-hidden="true"> ·
|
||
</span></span>
|
||
<span class="footer__chunk footer__chunk--main">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>
|
||
<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>
|
||
</span></div>
|
||
</footer>
|
||
|
||
<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>
|
||
|
||
|
||
</body>
|
||
</html>
|
||
|
||
|
||
|