GH GambleHub

Картковий інтерфейс і візуальні блоки

1) Навіщо картки

Картки упаковують сутність (гра, матч, акція, стаття) з ключовими атрибутами і діями. Хороша картка:
  • швидко сканується,
  • дає один головний CTA,
  • адаптується до різних контейнерів/колонок,
  • передбачувана по поведінці (hover, press, фокус, контекстне меню).

2) Анатомія картки

Мінімальний склад:

1. Медіа-зона (обкладинка/логотип/прев'ю, 16:9/4:3/1:1).

2. Заголовок (1-2 рядки з усіченням).

3. Метадані (підзаголовок, тег/категорія, провайдер, час).

4. Бейджі статусу (новинка, live, акція, рейтинг).

5. СТА/швидкі дії (кнопка або іконки).

6. Вторинний текст (короткий, 2-3 рядки max).

7. Контроль (вибране,... контекст).

Ієрархія: медіа → заголовок → CTA → мета → вторинне. Деструктивні дії приховані або винесені в меню.

3) Сітки і розкладки

Grid (фіксований стовпець): 2-6 колонок; адаптив через auto-fit/auto-fill.
Responsive tiles: 'minmax (240px, 1fr)'- картки ростуть рівно до меж.
Masonry/варіюється висота: обережно; забезпечити порядок фокусу і читабельність.
List (в ряд): коли важлива горизонтальна економія і сортованість.

css
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px,1fr));
gap: 16px;
}
.card {
border-radius: 12px;
background: var(--bg-elevated);
box-shadow: var(--elev-2);
display: grid;
grid-template-rows: auto 1fr auto;
overflow: hidden;
}
.card__media { aspect-ratio: 16/9; object-fit: cover; }

4) Щільність і ритм

Поля/відступи: всередині 12-16 px; між блоками 8-12 px.
Висота рядка: 1. 3–1. 5; шрифти: заголовок 16-18 px, мета 12-14 px.
Кліпінг тексту: `line-clamp: 2–3`; обов'язково повний текст в tooltip/деталях.

5) Стани та інтерактивність

Hover/Focus/Active: тінь/підсвічування, але без «стрибків» макета;':focus-visible'завжди бачимо.
Selectable: чекбокс/рамка; не плутати з посилальною карткою.
Pressed: зменшення до 98% + тінь вниз (≤ 120 мс).
Busy/Loading: скелетон, а не «порожньо».

css
.card:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.card:hover { box-shadow: var(--elev-3); transform: translateY(-1px); transition: box-shadow. 16s, transform. 16s; }

6) Зображення та медіа

Aspect-ratio жорстко фіксований; на списках ігор - 16:9 або 4:3.
Лінива завантаження: `loading="lazy"` + `decoding="async"`.
Плейсхолдер/скелетон з домінуючим кольором постера.
Помилка завантаження: підставна картинка + іконка «image-off».

html
<img class = "card __ media" src ="..." alt = "Game name" loading =" lazy" onerror =" this. src='/fallback. png'">

7) Бейджі і мітки

Короткі (1-2 слова): New, Live, -20%, Top 10.
Не можна покладатися тільки на колір - додавайте іконку/текст.
Розташування: лівий верх медіа; кілька - в стеку з зазором 4-6 px.

css
.badge { display:inline-flex; gap:6px; align-items:center; padding:4px 8px; border-radius:8px; font-size:.75rem; }
.badge--live { background: var(--bg-danger); color: var(--on-danger); }

8) CTA і швидкі дії

Один primary на картку (наприклад, «Грати», «Зробити ставку»).
Допоміжні іконки (вибране, поділитися,...) - по hover/фокусу.
Деструктивні - через підтвердження або undo-панель.

html
<div class="card__actions">
<button class="btn btn--primary">Играть</button>
<button class =" icon" aria-label = "Add to Favorites" title =" B Favorites "> </button>
<button class="icon" aria-haspopup="menu" aria-expanded="false">⋯</button>
</div>

9) Доступність (A11y)

Вся картка-посилання -'< a>'зі зрозумілим'aria-label', інакше: заголовок як посилання, решта - статично.
Порядок Tab відповідає візуальному; фокус-кільце видно.
Зображення з'alt'; декоративні -'aria-hidden =» true»'.
Для статусів використовуйте'role = «status» '/' aria-live = «polite»'.
Контраст тексту і бейджів ≥ AA; сенс не тільки кольором.

10) Перформанс

Лінива завантаження медіа і списків; пагінація або інфініт-скролл з sentry-спостерігачем.
Віртуалізація для стрічкових/нескінченних видач (± 10k елементів).
Мінімізуйте reflow: анімуйте тільки'transform/opacity'.
Рендеріть картки скелетонами і замінюйте контентом після завантаження даних.

11) Скелетони, помилки, порожні

Скелетон повторює структуру картки (медіа/текст/кнопка), без агресивного shimmer; враховуйте'prefers-reduced-motion'.
Error-state: іконка + короткий текст («Не вдалося завантажити гру») + кнопка Retry.
Empty-state: іконка/ілюстрація, пояснення, «Що далі» (фільтр/пошук/підписки).

12) Управління контентом

Усічення: 'line-clamp'+ явні підказки (tooltip).
Довгі числа/суми: табличні цифри: `font-variant-numeric: tabular-nums;`.
Локалізація: резерв + 20-30% ширини для довгих лейблів.
Підтримка RTL: фліп бейджів/іконок і вирівнювання.

13) Темна тема і контраст

Тіні слабші, використовуйте межі («1px») з прозорістю.
Підтримуйте AAA для малих шрифтів; уникайте мерехтіння.
Медіа затемнюються тонкою вуаллю (overlay 8-12%), щоб текст читався.

css
.theme-dark. card { background: var(--bg-elevated-dark); box-shadow: var(--elev-1-dark); }
.theme-dark. card__media::after { content:""; position:absolute; inset:0; background: rgba(0,0,0,.12); }

14) Сортування, фільтри, пагінація

Панель фільтрів зверху/збоку; результат - сітка карток.
Пагінація видима; нескінченний скролл - тільки з «Назад до початку» і збереженням позиції.
Фільтри не «скидають» скролл; застосовуються швидко (≤ 100 мс) або з індикатором.

15) Специфіка iGaming

15. 1 Картка гри (slot/table)

Медіа: постер 16:9, логотип провайдера.
Метадані: провайдер, RTP, волатильність, категорії (- тільки інформативно, без обіцянок виграшу).
Бейджі: New, Popular, Tournament, Jackpot.
CTA: «Грати» + «Демо». Контекст «18 +» і відповідальна гра - видимі.

15. 2 Картка матчу/коефіцієнта

Живий бейдж Live; таймер/період.
Ключові коефіцієнти (2-3) з миттєвим hover/press і безпечним undo (якщо допущено).
Оновлення без мерехтінь; при зміні курсу - акуратне підсвічування.

15. 3 Картка турніру/івенту

Дати, призовий фонд, правила (посилання).
Статус («Реєстрація відкрита/закрита», «Йде»).
CTA «Приєднатися», «Правила»; прогрес участі (окуляри/місце).

16) Антипатерни

Вся картка клікабельна + всередині вторинні посилання (пастки фокусу/кліків).
Два primary-CTA поруч («Грати» і «Купити бонус») - конкуренція уваги.
Відсутність плейсхолдерів/скелетонів → «стрибаюча» сітка (CLS).
Нескінченні shimmer-ефекти; анімація тінню/blur (дорого).
Метадані «в стовпчик» дрібним сірим на сірому (немає контрасту).
Бейджі, що передають сенс тільки кольором.

17) Токени дизайн-системи (приклад)

json
{
"card": {
"radius": 12,
"gap": 12,
"mediaRatio": "16/9",
"px": "12 12 12 12",
"shadow": { "rest": "var(--elev-2)", "hover": "var(--elev-3)" }
},
"badge": { "radius": 8, "px": "4 8", "icon": 14 },
"grid": { "gap": 16, "min": 240, "max": 1 },
"motion": { "hoverMs": 160, "pressMs": 100, "fadeMs": 160 },
"a11y": { "contrastAA": true, "focusRingWidth": 2, "focusRingOffset": 2 }
}

18) Сніппети

React: універсальна картка

tsx type CardProps = {
title: string;
subtitle?: string;
mediaUrl?: string;
badges?: string[];
onPrimary?: () => void;
primaryLabel?: string;
onFav?: () => void;
children?: React. ReactNode;
};
export default function Card({
title, subtitle, mediaUrl, badges=[], onPrimary, primaryLabel='Открыть', onFav, children
}: CardProps){
return (
<article className="card group focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2">
<div className="relative">
{mediaUrl? <img className="w-full aspect-[16/9] object-cover" src={mediaUrl} alt={title}/>: <div className="aspect-[16/9] bg-neutral-200"/>}
<div className="absolute top-2 left-2 flex gap-1">
{badges. map(b => <span key={b} className="badge">{b}</span>)}
</div>
</div>
<div className="p-3 grid gap-2">
<h3 className="text-sm font-semibold line-clamp-2" title={title}>{title}</h3>
{subtitle && <p className="text-xs text-neutral-500 line-clamp-2">{subtitle}</p>}
{children}
<div className="flex items-center gap-8">
{onPrimary && <button className="btn btn--primary" onClick={onPrimary}>{primaryLabel}</button>}
{onFav && <button className="icon opacity-0 group-hover:opacity-100" aria-label="В избранное" onClick={onFav}></button>}
</div>
</div>
</article>
);
}

Інфініт-скролл sentry

js const sentry = document. querySelector('#sentry');
const io = new IntersectionObserver(entries=>{
if(entries. some(e=>e. isIntersecting)) loadMore();
}, { rootMargin: '200px' });
io. observe(sentry);

19) Метрики та експерименти

CTR primary-CTA и Time-to-Click.
Scroll-depth → click: кліки «над згином »/« під згином».
Картка → перегляд деталей → конверсія.
Видимість бейджів і їх вплив на CTR.
Skeleton visible time и CLS.
A/B: розмір карток, кількість метаданих, видимість швидких дій, тип сітки (list/grid).

20) QA-чек-лист

Доступність

  • Фокус-кільця видимі; порядок Tab логічний.
  • Alt-тексти і'aria-label'коректні; статус-бейджі з текстом.
  • Контраст тексту/фону ≥ AA.

Поведінка

  • Один primary-CTA; швидкі дії не перекривають основний сценарій.
  • Hover/press/selected помітні; контекстне меню працює.
  • Порожні/помилки/скелетони коректні; є Retry.

Перформанс

  • Лінива завантаження медіа; немає різких стрибків макета.
  • Віртуалізація великих списків; анімації'transform/opacity'.

Сітка

  • 'minmax (240px, 1fr)'і'gap'адаптивні; Masonry не ламає фокус/порядок читання.
  • RTL/локалізація не «ламають» обрізку і бейджі.

21) Документація в дизайн-системі

Компоненти: `Card`, `GameCard`, `MatchCard`, `TournamentCard`, `StatusBadge`, `SkeletonCard`.
Токени: радіус/тіні/відступи/шари, кольори бейджів, анімації.
Патерни: «Один CTA», «Скелетон замість спінера», «Інфініт-скролл + збереження позиції».
Do/Don't-галерея: перевантажена картка vs мінімальна, «клікабельна вся картка» vs явні елементи.

Коротке резюме

Картки працюють, коли у них є чітка ієрархія, один головний CTA, передбачувані стани, стійкі сітки і повага до перформансу і доступності. Зафіксуйте токени і патерни, використовуйте скелетони і ліниве завантаження, тримайте контент лаконічним - і карткові інтерфейси стануть швидкими, читабельними і конверсійними, особливо в сценаріях iGaming.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.