diff --git a/frontend/src/components/mahjong/Mahjong.tsx b/frontend/src/components/mahjong/Mahjong.tsx index 008c66f..674f6b7 100644 --- a/frontend/src/components/mahjong/Mahjong.tsx +++ b/frontend/src/components/mahjong/Mahjong.tsx @@ -1,3 +1,4 @@ +import type { LevelInfo } from '@/components/mahjong/levels.ts' import type { DotLottieWorker } from '@lottiefiles/dotlottie-react' import type { Tile as TileT } from './game' import { DotLottieWorkerReact } from '@lottiefiles/dotlottie-react' @@ -7,14 +8,14 @@ import soundTilesMergedDelayed from './assets/bloop_300ms.mp3' import boomLottie from './assets/boom.lottie?arraybuffer' import soundTileSelect from './assets/pop-down.mp3' import { Controls } from './Controls' -import { FieldTemplate, TEMPLATE_2 } from './field-template' +import { FieldTemplate } from './field-template' import { Game } from './game' import styles from './Mahjong.module.scss' import { Tile } from './Tile' const LOTTIE_SIZE = 300 -export function Mahjong() { +export function Mahjong({ level }: { level: LevelInfo }) { const [tiles, setTiles] = useState([]) const [selected, setSelected] = useState(null) const [mergedAt, setMergedAt] = useState<{ x: number, y: number } | null>(null) @@ -27,43 +28,9 @@ export function Mahjong() { const [game, _] = useState(() => { const g = Game.random( - FieldTemplate.decode(TEMPLATE_2), + FieldTemplate.decode(level.template), (a, b) => a === b, - [ - 'alfa-romeo', - 'aston-martin', - 'atom', - 'audi', - 'bentley', - 'bmw', - 'bugatti', - 'byd', - 'chevrolet', - 'ferrari', - 'fiat', - 'ford', - 'honda', - 'hyundai', - 'jeep', - 'kia', - 'lamborghini', - 'land-rover', - 'lexus', - 'lucid-motors', - 'mclaren', - 'mercedes-benz', - 'mini', - 'morgan-motor-company', - 'nio', - 'porsche', - 'rivian', - 'rolls-royce', - 'subaru', - 'tesla', - 'toyota', - 'volkswagen', - 'volvo', - ], + level.choices, ) g.onTilesChange = (newTitles) => { setTiles(newTitles) @@ -200,7 +167,7 @@ export function Mahjong() { platesLeading={[ { id: 'title', - items: [{ icon: }], + items: [{ icon: }], clickable: true, onClick: () => { alert('not yet :)') diff --git a/frontend/src/components/mahjong/levels.ts b/frontend/src/components/mahjong/levels.ts new file mode 100644 index 0000000..450992e --- /dev/null +++ b/frontend/src/components/mahjong/levels.ts @@ -0,0 +1,127 @@ +import type { EncodedTemplate } from '@/components/mahjong/field-template.ts' +import { TEMPLATE_1, TEMPLATE_2 } from '@/components/mahjong/field-template.ts' + +const allChoices = [ + 'alfa-romeo', + 'aston-martin', + 'atom', + 'audi', + 'bentley', + 'bmw', + 'bugatti', + 'byd', + 'chevrolet', + 'ferrari', + 'fiat', + 'ford', + 'honda', + 'hyundai', + 'jeep', + 'kia', + 'lamborghini', + 'land-rover', + 'lexus', + 'lucid-motors', + 'mclaren', + 'mercedes-benz', + 'mini', + 'morgan-motor-company', + 'nio', + 'porsche', + 'rivian', + 'rolls-royce', + 'subaru', + 'tesla', + 'toyota', + 'volkswagen', + 'volvo', +] +type Choice = typeof allChoices[number] + +export type LevelInfo = { + id: string + title: string + description: string + template: EncodedTemplate + choices: Choice[] +} + +export const levels: LevelInfo[] = [ + { + id: '1', + title: 'Уровень 1', + description: 'Самый простой уровень', + template: TEMPLATE_1, + choices: allChoices, + }, + { + id: '2', + title: 'Уровень 2', + description: 'Чуть сложнее', + template: TEMPLATE_2, + choices: allChoices, + }, + { + id: '3', + title: 'Уровень 3', + description: 'Российский автопром', + template: TEMPLATE_2, + choices: [ + 'atom', + ], + }, + { + id: '4', + title: 'Уровень 4', + description: 'Только топовые марки', + template: TEMPLATE_2, + choices: [ + 'bugatti', + 'ferrari', + 'lamborghini', + 'mclaren', + 'porsche', + 'rolls-royce', + 'tesla', + ], + }, + { + id: '5', + title: 'Уровень 5', + description: 'Только немецкие марки', + template: TEMPLATE_2, + choices: [ + 'audi', + 'bmw', + 'mercedes-benz', + 'porsche', + 'volkswagen', + ], + }, + { + id: '6', + title: 'Уровень 6', + description: 'Только китайские марки', + template: TEMPLATE_2, + choices: [ + 'byd', + 'nio', + ], + }, + { + id: '7', + title: 'Уровень 7', + description: 'Только японские марки', + template: TEMPLATE_2, + choices: [ + 'honda', + 'lexus', + 'subaru', + 'toyota', + ], + }, +] + +export function getLevelById(id: string | undefined): LevelInfo | undefined { + return levels.find(level => level.id === id) +} diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts index 14abc67..7633bb4 100644 --- a/frontend/src/routeTree.gen.ts +++ b/frontend/src/routeTree.gen.ts @@ -12,6 +12,7 @@ import { Route as rootRoute } from './routes/__root' import { Route as TestImport } from './routes/test' +import { Route as PlayImport } from './routes/play' import { Route as IndexImport } from './routes/index' // Create/Update Routes @@ -22,6 +23,12 @@ const TestRoute = TestImport.update({ getParentRoute: () => rootRoute, } as any) +const PlayRoute = PlayImport.update({ + id: '/play', + path: '/play', + getParentRoute: () => rootRoute, +} as any) + const IndexRoute = IndexImport.update({ id: '/', path: '/', @@ -39,6 +46,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof IndexImport parentRoute: typeof rootRoute } + '/play': { + id: '/play' + path: '/play' + fullPath: '/play' + preLoaderRoute: typeof PlayImport + parentRoute: typeof rootRoute + } '/test': { id: '/test' path: '/test' @@ -53,36 +67,41 @@ declare module '@tanstack/react-router' { export interface FileRoutesByFullPath { '/': typeof IndexRoute + '/play': typeof PlayRoute '/test': typeof TestRoute } export interface FileRoutesByTo { '/': typeof IndexRoute + '/play': typeof PlayRoute '/test': typeof TestRoute } export interface FileRoutesById { __root__: typeof rootRoute '/': typeof IndexRoute + '/play': typeof PlayRoute '/test': typeof TestRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/test' + fullPaths: '/' | '/play' | '/test' fileRoutesByTo: FileRoutesByTo - to: '/' | '/test' - id: '__root__' | '/' | '/test' + to: '/' | '/play' | '/test' + id: '__root__' | '/' | '/play' | '/test' fileRoutesById: FileRoutesById } export interface RootRouteChildren { IndexRoute: typeof IndexRoute + PlayRoute: typeof PlayRoute TestRoute: typeof TestRoute } const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, + PlayRoute: PlayRoute, TestRoute: TestRoute, } @@ -97,12 +116,16 @@ export const routeTree = rootRoute "filePath": "__root.tsx", "children": [ "/", + "/play", "/test" ] }, "/": { "filePath": "index.tsx" }, + "/play": { + "filePath": "play.tsx" + }, "/test": { "filePath": "test.tsx" } diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index 7ba74bf..338df39 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -1,3 +1,5 @@ +import type { LevelInfo } from '@/components/mahjong/levels.ts' +import { levels } from '@/components/mahjong/levels.ts' import { Button } from '@/components/ui/button.tsx' import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card.tsx' import { createFileRoute, Link } from '@tanstack/react-router' @@ -20,34 +22,32 @@ function RouteComponent() { Сыграйте в увлекательную игру и ближе познакомьтесь с ведущими автомобильными компаниями мира
- - - - - - - - - + {levels.map((level, i) => ( + + ))}
) } -function LevelCard({ title, isUnlocked }: { title: string, isUnlocked: boolean }) { +function LevelCard({ level, isUnlocked }: { level: LevelInfo, isUnlocked: boolean }) { return ( - {title} - 72 кости, Российский автопром + {level.title} + + 72 кости, + {' '} + {level.description} +
diff --git a/frontend/src/routes/play.tsx b/frontend/src/routes/play.tsx new file mode 100644 index 0000000..01358bc --- /dev/null +++ b/frontend/src/routes/play.tsx @@ -0,0 +1,28 @@ +import { getLevelById } from '@/components/mahjong/levels.ts' +import { Mahjong } from '@/components/mahjong/Mahjong' +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/play')({ + component: RouteComponent, + validateSearch: (search: Record) => { + return { + level: (search.level as string | undefined) || undefined, + } + }, +}) + +function RouteComponent() { + const { level: levelId } = Route.useSearch() + + const level = getLevelById(levelId) + + if (!level) { + return
Invalid level id
+ } + + return ( +
+ +
+ ) +} diff --git a/frontend/src/routes/test.tsx b/frontend/src/routes/test.tsx index 6c2a32b..5caa0e6 100644 --- a/frontend/src/routes/test.tsx +++ b/frontend/src/routes/test.tsx @@ -1,3 +1,4 @@ +import { levels } from '@/components/mahjong/levels.ts' import { Mahjong } from '@/components/mahjong/Mahjong' import { createFileRoute } from '@tanstack/react-router' @@ -8,7 +9,7 @@ export const Route = createFileRoute('/test')({ function RouteComponent() { return (
- +
) }