682 lines
29 KiB
TypeScript
682 lines
29 KiB
TypeScript
export type TobaccoStrength = 1 | 2 | 3;
|
||
|
||
export const strengthLabels: Record<TobaccoStrength, string> = {
|
||
1: "лёгкая",
|
||
2: "средняя",
|
||
3: "крепкая",
|
||
};
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* Авторские миксы кальянов */
|
||
/* Формат: название · крепость (1–5) · холодок (0–3) · вкусы · цена */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* Миксы «НЕОНа» */
|
||
/* Страница «Миксы НЕОНа» показывает витрину генераций AI-сомелье */
|
||
/* (те же миксы, что собирает вкладка «Автоподбор микса», — см. */
|
||
/* mixEngine.generateShowcaseMixes). Фирменные миксы бара хозяин */
|
||
/* добавляет в CRM — на сайте это блок «Миксы мастера». */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
import { CATEGORY_LABELS, FLAVORS } from "./flavors";
|
||
import { generateShowcaseMixes, getFlavor } from "../lib/mixEngine";
|
||
|
||
export type MixStrength = 1 | 2 | 3 | 4 | 5;
|
||
export type CoolingLevel = 0 | 1 | 2 | 3;
|
||
|
||
export type HookahMix = {
|
||
id: string;
|
||
name: string;
|
||
desc: string;
|
||
strength: MixStrength;
|
||
cooling: CoolingLevel; // 0 = нет холодка, 3 = максимальный
|
||
flavorTags: string[]; // напр. "ягоды", "цитрус", "мята"
|
||
price: string;
|
||
featured?: boolean;
|
||
/** состав витринного микса: вкусы движка в порядке «основа → добавка → оттенок» */
|
||
items: { flavorId: string }[];
|
||
};
|
||
|
||
export const mixStrengthLabels: Record<MixStrength, string> = {
|
||
1: "Лёгкая",
|
||
2: "Ниже среднего",
|
||
3: "Средняя",
|
||
4: "Выше средней",
|
||
5: "Крепкая",
|
||
};
|
||
|
||
export const mixCoolingLabels: Record<CoolingLevel, string> = {
|
||
0: "Без холодка",
|
||
1: "Лёгкая",
|
||
2: "Средний",
|
||
3: "Сильный",
|
||
};
|
||
|
||
const PRICE_BASE = "1 400 ₽";
|
||
const PRICE_STRONG = "1 800 ₽";
|
||
|
||
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* Авторские миксы — показываются в карусели на главной */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
export type SignatureMix = {
|
||
id: string;
|
||
name: string;
|
||
desc: string;
|
||
price: string;
|
||
strength: TobaccoStrength;
|
||
badge?: { label: string; hot?: boolean };
|
||
};
|
||
|
||
const BASE_PRICE = "1 400 ₽";
|
||
|
||
export const signatureMixes: SignatureMix[] = [
|
||
{
|
||
id: "neon-signature",
|
||
name: "НЕОН Signature Mix",
|
||
desc: "Виноград, мята и тропические ноты. Наш фирменный микс, с которого начинают гости.",
|
||
price: BASE_PRICE,
|
||
strength: 1,
|
||
badge: { label: "Хит", hot: true },
|
||
},
|
||
{
|
||
id: "berry-haze",
|
||
name: "Berry Haze",
|
||
desc: "Лесные ягоды и сливки. Десертный вкус с густым молочным дымом.",
|
||
price: BASE_PRICE,
|
||
strength: 1,
|
||
badge: { label: "Новинка", hot: true },
|
||
},
|
||
{
|
||
id: "citrus-punch",
|
||
name: "Citrus Punch",
|
||
desc: "Цитрус, лайм и лёгкое охлаждение. Яркий и освежающий, как неоновая вывеска.",
|
||
price: BASE_PRICE,
|
||
strength: 2,
|
||
},
|
||
{
|
||
id: "midnight-grape",
|
||
name: "Midnight Grape",
|
||
desc: "Тёмный виноград с мятой. Глубокий вечерний вкус для долгих разговоров.",
|
||
price: BASE_PRICE,
|
||
strength: 1,
|
||
},
|
||
{
|
||
id: "cyan-breeze",
|
||
name: "Cyan Breeze",
|
||
desc: "Арбуз, лёд и мята. Самый холодный микс в нашей карте. Свежесть до утра.",
|
||
price: BASE_PRICE,
|
||
strength: 1,
|
||
},
|
||
{
|
||
id: "violet-dream",
|
||
name: "Violet Dream",
|
||
desc: "Дыня, ежевика и лаванда. Мягкий микс с цветочным шлейфом.",
|
||
price: BASE_PRICE,
|
||
strength: 1,
|
||
},
|
||
{
|
||
id: "dark-mango",
|
||
name: "Dark Mango",
|
||
desc: "Манго, маракуйя и холодок. Тропические ноты для долгого вечера.",
|
||
price: BASE_PRICE,
|
||
strength: 2,
|
||
},
|
||
{
|
||
id: "electric-cola",
|
||
name: "Electric Cola",
|
||
desc: "Кола, вишня и лёд. Знакомый вкус в неоновом исполнении.",
|
||
price: BASE_PRICE,
|
||
strength: 2,
|
||
},
|
||
];
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* Справочник табаков — страница «Вкусы» */
|
||
/* Формат: вкус · крепость · фирма · холодок */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
export type TobaccoFlavor = {
|
||
id: string;
|
||
name: string;
|
||
brand: string;
|
||
strength: TobaccoStrength;
|
||
cooling: boolean;
|
||
note?: string;
|
||
available: boolean;
|
||
image?: string;
|
||
createdAt?: string; // заполнено для вкусов, добавленных владельцем через CRM
|
||
};
|
||
|
||
export type TobaccoBrandInfo = {
|
||
url?: string;
|
||
image: string;
|
||
accent: string;
|
||
};
|
||
|
||
export const tobaccoBrandInfo: Record<string, TobaccoBrandInfo> = {
|
||
Blackburn: { url: "https://burntobacco.com/", image: "./images/hookah-smoke.jpg", accent: "#ff3636" },
|
||
Overdose: { url: "https://overdose.pro/", image: "./images/hookah-smoke.jpg", accent: "#ff8a00" },
|
||
Banger: { url: "https://www.bangertobacco.com/", image: "./images/interior-bar.jpg", accent: "#d4af37" },
|
||
Undercoal: { url: "https://musthave.ru/", image: "./images/hookah-smoke.jpg", accent: "#ff4d8d" },
|
||
Darkside: { url: "https://darksidecorp.ru/", image: "https://static.tildacdn.com/tild3036-6566-4231-a239-313362636638/mainFooter.png", accent: "#ef2b2d" },
|
||
"Хулиган / WOOD": { url: "https://hlgn.cc/tobacco", image: "https://static.tildacdn.com/tild6662-6138-4437-b334-303162643234/_2____1.png", accent: "#ff453a" },
|
||
Hupreme: { url: "https://t.me/s/Hypremetc", image: "./images/interior-sofas.jpg", accent: "#b026ff" },
|
||
"JENT Alcohol Line": { url: "https://vk.com/jent.club", image: "https://sun9-6.userapi.com/impg/VSLGmsKem1jEfrzMwQ2zntx8tvmHu-mhR7h8iA/dja__TnVak0.jpg", accent: "#e2b04a" },
|
||
DEUS: { url: "https://t.me/deus_tobacco", image: "./images/hookah-smoke.jpg", accent: "#a7a7a7" },
|
||
Северный: { url: "https://www.tabak-sever.ru/", image: "./images/interior-sofas.jpg", accent: "#a8d7ff" },
|
||
Bliss: { url: "https://taplink.cc/blisstobacco", image: "https://p.taplink.st/a/0/3/b/e/bc523d.png?2", accent: "#78a7d2" },
|
||
Muassel: { url: "http://muassel.ru/", image: "https://muassel.ru/images/22_1.jpg", accent: "#d5a760" },
|
||
Chabacco: { url: "https://chabacco.ru/", image: "https://static.tildacdn.com/tild3466-3934-4163-b131-653731646231/banner-new-chabacco-.png", accent: "#ffca28" },
|
||
"Joy Kiwichanga": { url: "https://alphahookah.ru/mix-joy/", image: "https://alphahookah.ru/upload/iblock/7e9/ah3jnujz5k06qd717ml9wo52t0s3bi3v.png", accent: "#00d68f" },
|
||
Хулиган: { url: "https://hlgn.cc/tobacco", image: "https://static.tildacdn.com/tild6662-6138-4437-b334-303162643234/_2____1.png", accent: "#ff453a" },
|
||
Сарма: { url: "https://sarmahookah.ru/", image: "https://static.tildacdn.com/tild6465-6337-4363-b365-376134396533/image_7.png", accent: "#e44e2d" },
|
||
Добавка: { image: "./images/menu-bg.jpg", accent: "#00f0ff" },
|
||
};
|
||
|
||
const tobacco = (
|
||
id: string,
|
||
brand: string,
|
||
name: string,
|
||
note: string | undefined,
|
||
strength: TobaccoStrength,
|
||
cooling = false,
|
||
available = true,
|
||
image?: string,
|
||
): TobaccoFlavor => ({ id, brand, name, note, strength, cooling, available, image });
|
||
|
||
export const tobaccoFlavors: TobaccoFlavor[] = [
|
||
tobacco("bb-cola", "Blackburn", "Классическая кола", undefined, 3),
|
||
tobacco("bb-lulo", "Blackburn", "Lulo", undefined, 3),
|
||
tobacco("bb-real-pf", "Blackburn", "Real P.F.", "Маракуйя", 3),
|
||
tobacco("bb-white-grape", "Blackburn", "White Grape", "Белый виноград", 3),
|
||
tobacco("bb-forest-raspberry", "Blackburn", "Лесная малина", undefined, 3),
|
||
tobacco("bb-brownie", "Blackburn", "Брауни", undefined, 3),
|
||
tobacco("bb-blackberry-lemonade", "Blackburn", "Blackberry Lemonade", "Ежевичный лимонад", 3),
|
||
tobacco("bb-lemon-shock", "Blackburn", "Lemon Shock", "Ультракислый лимон", 3),
|
||
tobacco("bb-blueberry", "Blackburn", "Blueberry", "Голубика", 3),
|
||
tobacco("bb-apple-shock", "Blackburn", "Apple Shock", "Кислое зелёное яблоко", 3),
|
||
tobacco("bb-red-energy", "Blackburn", "Red Energy", "Энергетик", 3),
|
||
tobacco("bb-kiwi-stoner", "Blackburn", "Kiwi Stoner", "Смузи из киви", 3),
|
||
tobacco("bb-bananini", "Blackburn", "Bananini", "Банан", 3),
|
||
tobacco("bb-honey-melon", "Blackburn", "Медовая дыня", undefined, 3),
|
||
tobacco("bb-pineapple", "Blackburn", "Pineapple", "Сочный ананас", 3),
|
||
tobacco("bb-grape-lollipop", "Blackburn", "Виноградный чупа-чупс", undefined, 3),
|
||
tobacco("bb-fir", "Blackburn", "Ёлка", undefined, 3, true),
|
||
tobacco("bb-red-orange", "Blackburn", "Красный апельсин", undefined, 3),
|
||
tobacco("bb-juicy-mango", "Blackburn", "Сочное манго", undefined, 3),
|
||
tobacco("bb-basilic", "Blackburn", "Basilic", "Базилик", 3),
|
||
tobacco("bb-berry-sorbet", "Blackburn", "Ягодный сорбет", "С грейпфрутом", 3),
|
||
tobacco("bb-ananas-shock", "Blackburn", "Ananas Shock", "Кислый ананас", 3),
|
||
tobacco("bb-after-8", "Blackburn", "After 8", "Шоколад-мята", 3, true),
|
||
tobacco("bb-overdose", "Blackburn", "Overdose", "Лимон-лайм", 3),
|
||
tobacco("bb-pina-colada", "Blackburn", "Pina Colada", undefined, 3),
|
||
tobacco("bb-pistachio-ice", "Blackburn", "Pistachio Ice Snow", "Фисташковое мороженое", 3, true),
|
||
tobacco("bb-pomelo", "Blackburn", "Pomelo", undefined, 3),
|
||
tobacco("bb-pear-lemonade", "Blackburn", "Pear Lemonade", "Грушевый лимонад", 3),
|
||
|
||
tobacco("od-lost-futura", "Overdose", "Lost Futura", "Мускусная вишня", 3),
|
||
tobacco("od-frustyle", "Overdose", "Frustyle", "Кактус-лайм", 3),
|
||
tobacco("od-black-banano", "Overdose", "Black Banano", "Амбровый банан", 3),
|
||
tobacco("od-gin-cucumber", "Overdose", "Gin Cucumber", "Огуречный джин", 3),
|
||
|
||
tobacco("banger-black-white", "Banger", "Black and White", "Печенье Oreo", 2),
|
||
tobacco("banger-cream-soda", "Banger", "Cream Soda", "Крем-сода", 2),
|
||
tobacco("banger-sexy", "Banger", "Sexy", "Грейпфрут, клубника, малина", 2),
|
||
tobacco("banger-grapefruit", "Banger", "Grapefruit", "Грейпфрут", 2),
|
||
tobacco("banger-green-day", "Banger", "Green Day", "Яблоко, киви, кислинка", 2),
|
||
tobacco("banger-cola-bella", "Banger", "Cola Bella", "Ванильная кола", 2),
|
||
|
||
tobacco("uc-pinkman", "Undercoal", "Pinkman", "Клубника, малина, грейпфрут", 2),
|
||
tobacco("uc-coconut-shake", "Undercoal", "Кокосовый шейк", undefined, 2, false, false),
|
||
tobacco("uc-caribbean-rum", "Undercoal", "Caribbean Rum", undefined, 2),
|
||
tobacco("uc-mango-rose", "Undercoal", "Манго, маракуйя, личи и роза", undefined, 2),
|
||
tobacco("uc-tropical-juice", "Undercoal", "Тропический сок", undefined, 2),
|
||
tobacco("uc-cactus-kiwi", "Undercoal", "Кактус, киви и абсент", undefined, 2),
|
||
tobacco("uc-milky-oolong", "Undercoal", "Чай «Молочный улун»", undefined, 2),
|
||
tobacco("uc-cranberry", "Undercoal", "Клюква", undefined, 2),
|
||
tobacco("uc-pear-tarragon", "Undercoal", "Груша, лимон и тархун", undefined, 2),
|
||
tobacco("uc-cinnamon-roll", "Undercoal", "Cinnamon Roll", undefined, 2),
|
||
tobacco("uc-cookie", "Undercoal", "Cookie", "Печенье", 2),
|
||
|
||
tobacco("ds-alpine-trip", "Darkside", "Алтайский трип", "Хвоя, фейхоа, эвкалипт", 2, true),
|
||
|
||
tobacco("wood-begemot", "Хулиган / WOOD", "Begemot", "Бергамот-мандарин", 2),
|
||
tobacco("wood-boo", "Хулиган / WOOD", "Boo", "Яблоко-гранат", 2),
|
||
tobacco("wood-old", "Хулиган / WOOD", "Old", "Лимон с мёдом", 2),
|
||
tobacco("wood-berry-ninja", "Хулиган / WOOD", "Берри Ниндзя", "Лесные ягоды", 2),
|
||
tobacco("wood-sir-hard", "Хулиган / WOOD", "Sir Hard", "Воздушный рис", 3),
|
||
|
||
tobacco("hupreme-milk-tea", "Hupreme", "Чай с молоком", undefined, 2),
|
||
tobacco("hupreme-gooseberry", "Hupreme", "Крыжовник", undefined, 2),
|
||
tobacco("hupreme-guava", "Hupreme", "Гуава", undefined, 2),
|
||
|
||
tobacco("jent-blue-agave", "JENT Alcohol Line", "Blue Agave", "«Текила Бум»", 2),
|
||
tobacco("jent-havana", "JENT Alcohol Line", "Havana 290", "Мохито", 2, true),
|
||
tobacco("jent-cuba-libre", "JENT Alcohol Line", "Cuba Libre", undefined, 2),
|
||
|
||
tobacco("deus-blackberry-wine", "DEUS", "Blackberry Wine", "Ежевичное вино", 2),
|
||
tobacco("deus-guinness", "DEUS", "Guinness", "Тёмное пиво", 2),
|
||
tobacco("deus-peonies", "DEUS", "Peonies", "Пионы", 2),
|
||
tobacco("deus-violet-zephyr", "DEUS", "Violet Zephyr", "Фиалковый зефир", 2),
|
||
tobacco("deus-cherry-jelly", "DEUS", "Cherry Jelly", "Вишнёвое желе", 2),
|
||
tobacco("deus-pumpkin-pie", "DEUS", "Pumpkin Pie", "Тыквенный пирог с миндалём", 2),
|
||
tobacco("deus-blueberry-yogurt", "DEUS", "Blueberry Yogurt", "Черничный йогурт", 2),
|
||
tobacco("deus-base", "DEUS", "Base", "Табачный лист", 2),
|
||
tobacco("deus-champagne", "DEUS", "Champagne", "Игристое вино", 2),
|
||
|
||
tobacco("north-flower", "Северный", "Цветочный", undefined, 3),
|
||
tobacco("north-feijoa", "Северный", "Финдеперцовый фейхоа", undefined, 3),
|
||
tobacco("north-elderberry", "Северный", "Бузина", undefined, 3),
|
||
tobacco("north-sorbet", "Северный", "Sorbet", "Фруктовый", 3),
|
||
|
||
tobacco("bliss-mango-chamomile", "Bliss", "Манго-ромашка", undefined, 1),
|
||
tobacco("bliss-peach-yogurt", "Bliss", "Персик-йогурт", undefined, 1),
|
||
tobacco("bliss-lime", "Bliss", "Лайм", undefined, 1),
|
||
tobacco("bliss-love-shot", "Bliss", "Love Shot", "Маракуйя, арбуз, лимон, холодок", 1, true),
|
||
tobacco("bliss-strawberry", "Bliss", "Клубника", undefined, 1),
|
||
|
||
tobacco("muassel-cinnamon-gum", "Muassel", "Жвачка с корицей", undefined, 3),
|
||
tobacco("chabacco-strawberry-milksake", "Chabacco", "Mix", "Клубничный милкшейк", 2),
|
||
tobacco("joy-kiwichanga", "Joy Kiwichanga", "Киви, фейхоа", undefined, 2, false, true, "https://alphahookah.ru/upload/iblock/7e9/ah3jnujz5k06qd717ml9wo52t0s3bi3v.png"),
|
||
tobacco("hooligan-grapefruit", "Хулиган", "Грейпфрутовый сок", undefined, 2),
|
||
tobacco("sarma-drunk-pear", "Сарма", "Дачная груша", undefined, 2),
|
||
tobacco("sarma-corn-paprika", "Сарма", "Кукуруза-паприка", undefined, 2),
|
||
tobacco("hooligan-flash", "Хулиган", "«Флеш»", "Медовая малина", 2),
|
||
tobacco("add-north", "Добавка", "Север", "Бустер", 1, true),
|
||
tobacco("add-cooling", "Добавка", "Холодок", undefined, 1, true),
|
||
];
|
||
|
||
export const tobaccoBrands = [...new Set(tobaccoFlavors.map((f) => f.brand))].sort((a, b) =>
|
||
a.localeCompare(b, "ru")
|
||
);
|
||
|
||
export const tobaccoCatalogNotice =
|
||
"Актуальный ассортимент по вашей карте. Изображение показывает упаковку или визуал бренда; наличие отмечено в каждой карточке.";
|
||
|
||
/** Витрина: генерации движка по всем профилям/крепостям/холодку. */
|
||
/** Табаки, которых нет на сайте (или они помечены недоступными), в витрину
|
||
* не берём: каждый микс собран из реального ассортимента «Вкусов». */
|
||
const siteUnavailableFlavorIds: string[] = FLAVORS.filter((f) => {
|
||
const t = tobaccoFlavors.find((x) => x.id === (f.catalogId ?? f.id));
|
||
return !!t && !t.available;
|
||
}).map((f) => f.id);
|
||
|
||
/** Витрина: генерации движка по всем профилям/крепостям/холодку. */
|
||
const showcase = generateShowcaseMixes(siteUnavailableFlavorIds);
|
||
|
||
/** Тег фильтра «Вкус» из категории вкуса состава; холодок-добавка — «лёд». */
|
||
const flavorTag = (flavorId: string): string | null => {
|
||
const f = getFlavor(flavorId);
|
||
if (!f) return null;
|
||
return f.category === "cooling" ? "лёд" : CATEGORY_LABELS[f.category];
|
||
};
|
||
|
||
export const hookahMixes: HookahMix[] = showcase.map(({ mix, strength, cooling }, index) => ({
|
||
id: `showcase-${index + 1}`,
|
||
name: mix.name,
|
||
desc: mix.description,
|
||
strength,
|
||
cooling,
|
||
flavorTags: [...new Set(mix.items.map((i) => flavorTag(i.flavorId)).filter((t): t is string => !!t))],
|
||
price: strength >= 5 ? PRICE_STRONG : PRICE_BASE,
|
||
featured: index < 5,
|
||
items: mix.items.map((i) => ({ flavorId: i.flavorId })),
|
||
}));
|
||
|
||
export const mixFlavorTags = [...new Set(hookahMixes.flatMap((m) => m.flavorTags))].sort(
|
||
(a, b) => a.localeCompare(b, "ru")
|
||
);
|
||
|
||
export const mixesCatalogNotice =
|
||
"Цены указаны за один кальян. Крепкие миксы — 1 800 ₽, остальные — 1 400 ₽.";
|
||
/* ------------------------------------------------------------------ */
|
||
/* PlayStation 5 */
|
||
/* Формат: название · изображение · жанр · макс. игроков */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
export type Ps5Game = {
|
||
id: string;
|
||
name: string;
|
||
genre: string;
|
||
maxPlayers: number;
|
||
image: string; // путь к обложке, пустая строка = CSS-плейсхолдер
|
||
accent?: string; // цвет для плейсхолдера
|
||
};
|
||
|
||
export const ps5Games: Ps5Game[] = [
|
||
{
|
||
id: "fifa-25",
|
||
name: "FIFA 25",
|
||
genre: "Футбольный симулятор",
|
||
maxPlayers: 4,
|
||
image: "/images/games/fifa25.jfif",
|
||
},
|
||
{
|
||
id: "ufc-5",
|
||
name: "UFC 5",
|
||
genre: "Файтинг",
|
||
maxPlayers: 2,
|
||
image: "/images/games/ufc5.jfif",
|
||
},
|
||
{
|
||
id: "mortal-kombat-1",
|
||
name: "Mortal Kombat 1",
|
||
genre: "Файтинг",
|
||
maxPlayers: 2,
|
||
image: "/images/games/mk1.jpg",
|
||
},
|
||
{
|
||
id: "move-or-die",
|
||
name: "Move or Die",
|
||
genre: "Кооперативная аркада",
|
||
maxPlayers: 4,
|
||
image: "/images/games/mod.jpg",
|
||
},
|
||
{
|
||
id: "overcooked",
|
||
name: "Overcooked",
|
||
genre: "Кооперативная аркада",
|
||
maxPlayers: 4,
|
||
image: "/images/games/over.jpg",
|
||
},
|
||
|
||
/* --- сингл-игры --- */
|
||
{
|
||
id: "god-of-war-ragnarok",
|
||
name: "God of War Ragnarök",
|
||
genre: "Экшен-приключение",
|
||
maxPlayers: 1,
|
||
image: "/images/games/gowr.jpg",
|
||
},
|
||
{
|
||
id: "god-of-war",
|
||
name: "God of War",
|
||
genre: "Экшен-приключение",
|
||
maxPlayers: 1,
|
||
image: "/images/games/gow.jpg",
|
||
},
|
||
{
|
||
id: "spider-man-remastered",
|
||
name: "Marvel's Spider-Man Remastered",
|
||
genre: "Экшен-приключение",
|
||
maxPlayers: 1,
|
||
image: "/images/games/smr.jpg",
|
||
},
|
||
];
|
||
|
||
export const gameGenres = [...new Set(ps5Games.map((g) => g.genre))].sort((a, b) =>
|
||
a.localeCompare(b, "ru")
|
||
);
|
||
|
||
export const gamesCatalogNotice =
|
||
"Количество геймпадов уточняйте при бронировании VIP-зала.";
|
||
|
||
/* ------------------------------------------------------------------ */
|
||
/* Настольные игры */
|
||
/* Формат: название · тип · игроки (мин–макс) · время · сложность */
|
||
/* ------------------------------------------------------------------ */
|
||
|
||
export type BoardGameCategory =
|
||
| "Карточные"
|
||
| "Классика"
|
||
| "Компанейские"
|
||
| "Стратегия"
|
||
| "На логику";
|
||
|
||
export type BoardGameDifficulty = 1 | 2 | 3; // 1 — правила за минуту, 3 — надо вникать
|
||
|
||
export type BoardGame = {
|
||
id: string;
|
||
name: string;
|
||
category: BoardGameCategory;
|
||
minPlayers: number;
|
||
maxPlayers: number;
|
||
duration: string; // «20–40 мин»
|
||
difficulty: BoardGameDifficulty;
|
||
desc: string;
|
||
icon: string; // ключ иконки для карточки
|
||
accent: string; // цвет плейсхолдера
|
||
hit?: boolean;
|
||
};
|
||
|
||
export const boardGameDifficultyLabels: Record<BoardGameDifficulty, string> = {
|
||
1: "Простая",
|
||
2: "Средняя",
|
||
3: "Сложная",
|
||
};
|
||
|
||
export const boardGames: BoardGame[] = [
|
||
{
|
||
id: "mafia",
|
||
name: "Мафия",
|
||
category: "Компанейские",
|
||
minPlayers: 6,
|
||
maxPlayers: 16,
|
||
duration: "40–90 мин",
|
||
difficulty: 1,
|
||
desc: "Город засыпает — просыпается мафия. Психологическая игра на блеф и дедукцию для большой компании.",
|
||
icon: "eye",
|
||
accent: "#b026ff",
|
||
hit: true,
|
||
},
|
||
{
|
||
id: "bunker",
|
||
name: "Бункер",
|
||
category: "Компанейские",
|
||
minPlayers: 4,
|
||
maxPlayers: 16,
|
||
duration: "40–60 мин",
|
||
difficulty: 1,
|
||
desc: "Апокалипсис близко, а мест в бункере на всех не хватит. Докажи, что именно ты нужен человечеству.",
|
||
icon: "skull",
|
||
accent: "#00f0ff",
|
||
hit: true,
|
||
},
|
||
{
|
||
id: "cards",
|
||
name: "Игральные карты",
|
||
category: "Карточные",
|
||
minPlayers: 2,
|
||
maxPlayers: 8,
|
||
duration: "10–60 мин",
|
||
difficulty: 1,
|
||
desc: "Классическая колода 54 карты: дурак, покер, 21, бридж — играйте во что угодно.",
|
||
icon: "spade",
|
||
accent: "#ff4d6d",
|
||
hit: true,
|
||
},
|
||
{
|
||
id: "chess",
|
||
name: "Шахматы",
|
||
category: "Классика",
|
||
minPlayers: 2,
|
||
maxPlayers: 2,
|
||
duration: "20–60 мин",
|
||
difficulty: 3,
|
||
desc: "Королевская игра. Дуэль умов на 64 клетках под неоновым светом.",
|
||
icon: "crown",
|
||
accent: "#e0e0e0",
|
||
},
|
||
{
|
||
id: "backgammon",
|
||
name: "Нарды",
|
||
category: "Классика",
|
||
minPlayers: 2,
|
||
maxPlayers: 2,
|
||
duration: "20–40 мин",
|
||
difficulty: 2,
|
||
desc: "Длинные и короткие нарды. Кости, стратегия и немного удачи — идеально под кальян.",
|
||
icon: "dices",
|
||
accent: "#f4a261",
|
||
hit: true,
|
||
},
|
||
{
|
||
id: "domino",
|
||
name: "Домино",
|
||
category: "Классика",
|
||
minPlayers: 2,
|
||
maxPlayers: 4,
|
||
duration: "15–30 мин",
|
||
difficulty: 1,
|
||
desc: "Забей «козла» — простая и азартная игра, в которую можно играть часами.",
|
||
icon: "grid",
|
||
accent: "#ffd23d",
|
||
},
|
||
{
|
||
id: "checkers",
|
||
name: "Шашки",
|
||
category: "Классика",
|
||
minPlayers: 2,
|
||
maxPlayers: 2,
|
||
duration: "10–30 мин",
|
||
difficulty: 1,
|
||
desc: "Русские шашки и поддавки. Быстро, азартно, знакомо с детства.",
|
||
icon: "circle",
|
||
accent: "#4dff88",
|
||
},
|
||
{
|
||
id: "uno",
|
||
name: "UNO",
|
||
category: "Карточные",
|
||
minPlayers: 2,
|
||
maxPlayers: 10,
|
||
duration: "15–30 мин",
|
||
difficulty: 1,
|
||
desc: "Скинь все карты первым. +4, пропуск хода и разворот — главное, не забудь крикнуть «УНО!».",
|
||
icon: "hash",
|
||
accent: "#ff3636",
|
||
hit: true,
|
||
},
|
||
{
|
||
id: "monopoly",
|
||
name: "Монополия",
|
||
category: "Стратегия",
|
||
minPlayers: 2,
|
||
maxPlayers: 6,
|
||
duration: "60–120 мин",
|
||
difficulty: 2,
|
||
desc: "Скупай улицы, строй отели и разоряй друзей. Классика, которая ссорит компании уже сто лет.",
|
||
icon: "landmark",
|
||
accent: "#2ec27e",
|
||
},
|
||
{
|
||
id: "jenga",
|
||
name: "Дженга",
|
||
category: "Компанейские",
|
||
minPlayers: 2,
|
||
maxPlayers: 8,
|
||
duration: "10–20 мин",
|
||
difficulty: 1,
|
||
desc: "Вытаскивай брусок и клади наверх. Кто уронит башню — тот и проиграл. Твёрдая рука обязательна.",
|
||
icon: "layout",
|
||
accent: "#d4af37",
|
||
},
|
||
{
|
||
id: "alias",
|
||
name: "Alias",
|
||
category: "Компанейские",
|
||
minPlayers: 4,
|
||
maxPlayers: 12,
|
||
duration: "30–60 мин",
|
||
difficulty: 1,
|
||
desc: "Объясни слово команде, не называя его. Игра на скорость мысли и командную химию.",
|
||
icon: "brain",
|
||
accent: "#ff8a00",
|
||
},
|
||
{
|
||
id: "imaginarium",
|
||
name: "Имаджинариум",
|
||
category: "Компанейские",
|
||
minPlayers: 4,
|
||
maxPlayers: 7,
|
||
duration: "30–60 мин",
|
||
difficulty: 1,
|
||
desc: "Загадай ассоциацию к карточке с сюрреалистичной картинкой. Творческая игра для душевной компании.",
|
||
icon: "puzzle",
|
||
accent: "#c77dff",
|
||
},
|
||
{
|
||
id: "crocodile",
|
||
name: "Крокодил",
|
||
category: "Компанейские",
|
||
minPlayers: 4,
|
||
maxPlayers: 16,
|
||
duration: "20–60 мин",
|
||
difficulty: 1,
|
||
desc: "Покажи слово жестами — без звуков и подсказок. Гарантированно смешно.",
|
||
icon: "users",
|
||
accent: "#00c2a8",
|
||
},
|
||
{
|
||
id: "poker",
|
||
name: "Покерный набор",
|
||
category: "Карточные",
|
||
minPlayers: 2,
|
||
maxPlayers: 9,
|
||
duration: "60–180 мин",
|
||
difficulty: 2,
|
||
desc: "Фишки, колоды и дилерская кнопка. Техасский холдем на серьёзных щах — но только на интерес.",
|
||
icon: "club",
|
||
accent: "#1fa37a",
|
||
},
|
||
{
|
||
id: "exploding-kittens",
|
||
name: "Взрывные котята",
|
||
category: "Карточные",
|
||
minPlayers: 2,
|
||
maxPlayers: 5,
|
||
duration: "15 мин",
|
||
difficulty: 1,
|
||
desc: "Русская рулетка с котиками. Тяни карту и молись, чтобы не попался взрывной котёнок.",
|
||
icon: "ghost",
|
||
accent: "#ff6b9d",
|
||
},
|
||
{
|
||
id: "catan",
|
||
name: "Колонизаторы (Catan)",
|
||
category: "Стратегия",
|
||
minPlayers: 3,
|
||
maxPlayers: 4,
|
||
duration: "60–90 мин",
|
||
difficulty: 2,
|
||
desc: "Строй дороги и поселения, торгуй ресурсами. Одна из лучших стратегий в истории настолок.",
|
||
icon: "castle",
|
||
accent: "#e9c46a",
|
||
},
|
||
{
|
||
id: "dixit",
|
||
name: "Диксит",
|
||
category: "Компанейские",
|
||
minPlayers: 3,
|
||
maxPlayers: 6,
|
||
duration: "30 мин",
|
||
difficulty: 1,
|
||
desc: "Расскажи историю по картинке так, чтобы угадала часть игроков — но не все.",
|
||
icon: "heart",
|
||
accent: "#f77f00",
|
||
},
|
||
{
|
||
id: "codenames",
|
||
name: "Кодовые имена",
|
||
category: "На логику",
|
||
minPlayers: 4,
|
||
maxPlayers: 8,
|
||
duration: "15–30 мин",
|
||
difficulty: 2,
|
||
desc: "Капитаны дают ассоциации одним словом, команда ищет своих агентов. Напряжённо и умно.",
|
||
icon: "target",
|
||
accent: "#4895ef",
|
||
},
|
||
];
|
||
|
||
export const boardGameCategories = [...new Set(boardGames.map((g) => g.category))].sort(
|
||
(a, b) => a.localeCompare(b, "ru")
|
||
);
|
||
|
||
export const boardGamesNotice =
|
||
"Все игры бесплатны для гостей — просто попросите у бармена. Наличие конкретной игры уточняйте на месте.";
|