mirror of
https://github.com/StepanovPlaton/torrent_frontend.git
synced 2026-04-03 12:20:48 +04:00
Init game page
This commit is contained in:
48
src/app/games/[game_id]/page.tsx
Normal file
48
src/app/games/[game_id]/page.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import { GameService } from "@/entities/game";
|
||||||
|
import { GameCard } from "@/features/gameCard";
|
||||||
|
import { Section } from "@/widgets/section";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export default async function Games({
|
||||||
|
params: { game_id },
|
||||||
|
}: {
|
||||||
|
params: { game_id: number };
|
||||||
|
}) {
|
||||||
|
const gameCards = await GameService.getGameCards();
|
||||||
|
const game = await GameService.getGame(game_id);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{game && (
|
||||||
|
<div className="p-4 flex flex-col lp:flex-row">
|
||||||
|
{game.cover && (
|
||||||
|
<Image
|
||||||
|
src={game.cover}
|
||||||
|
className="rounded-lg w-[60%] aspect-video object-cover"
|
||||||
|
alt=""
|
||||||
|
width={1280}
|
||||||
|
height={720}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="pt-2 max-w-[40%]">
|
||||||
|
<h1 className="text-4xl">{game.title}</h1>
|
||||||
|
<p className="text-md text-justify text-fg4 pt-2">
|
||||||
|
{game.description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{gameCards && (
|
||||||
|
<Section
|
||||||
|
name="Другие популярные игры"
|
||||||
|
link="/games"
|
||||||
|
invite_text={'Перейти в раздел "Игры"'}
|
||||||
|
>
|
||||||
|
{gameCards.map((card) => (
|
||||||
|
<GameCard key={card.id} card={card} />
|
||||||
|
))}
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -9,10 +9,10 @@ export const metadata: Metadata = {
|
|||||||
".Torrent: Игры - каталог .torrent файлов для обмена видеоиграми",
|
".Torrent: Игры - каталог .torrent файлов для обмена видеоиграми",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Games() {
|
||||||
const gameCards = await GameService.getGameCards();
|
const gameCards = await GameService.getGameCards();
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full max-w-[var(--app-width)] m-auto overflow-y-auto">
|
<>
|
||||||
{gameCards && (
|
{gameCards && (
|
||||||
<Section>
|
<Section>
|
||||||
{gameCards.map((card) => (
|
{gameCards.map((card) => (
|
||||||
@@ -20,6 +20,6 @@ export default async function Home() {
|
|||||||
))}
|
))}
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ export default function RootLayout({
|
|||||||
<body className={inter.className}>
|
<body className={inter.className}>
|
||||||
<ThemeProvider enableSystem={false} defaultTheme="light">
|
<ThemeProvider enableSystem={false} defaultTheme="light">
|
||||||
<Header />
|
<Header />
|
||||||
{children}
|
<div className="w-full h-full max-w-[var(--app-width)] m-auto overflow-y-auto">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Section } from "@/widgets/section";
|
|||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const gameCards = await GameService.getGameCards();
|
const gameCards = await GameService.getGameCards();
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full max-w-[var(--app-width)] m-auto overflow-y-auto">
|
<>
|
||||||
{gameCards && (
|
{gameCards && (
|
||||||
<Section
|
<Section
|
||||||
name="Игры"
|
name="Игры"
|
||||||
@@ -17,6 +17,6 @@ export default async function Home() {
|
|||||||
))}
|
))}
|
||||||
</Section>
|
</Section>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { HTTPService } from "@/shared/http/httpService";
|
import { HTTPService } from "@/shared/http/httpService";
|
||||||
import { gameCardsSchema, GameCardType } from "./schemas/gameCard";
|
import { gameCardsSchema, GameCardType } from "./schemas/gameCard";
|
||||||
|
import { gameSchema, GameType } from "./schemas/game";
|
||||||
|
|
||||||
export abstract class GameService {
|
export abstract class GameService {
|
||||||
public static async getGameCards() {
|
public static async getGameCards() {
|
||||||
@@ -8,4 +9,7 @@ export abstract class GameService {
|
|||||||
gameCardsSchema
|
gameCardsSchema
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
public static async getGame(id: number) {
|
||||||
|
return await HTTPService.get<GameType>(`/games/${id}`, gameSchema);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { gameCardSchema } from "./gameCard";
|
import { gameCardSchema } from "./gameCard";
|
||||||
|
|
||||||
export const gameSchema = z.union([
|
export const gameSchema = gameCardSchema.and(
|
||||||
gameCardSchema,
|
|
||||||
z.object({
|
z.object({
|
||||||
torrent_file: z.string().min(1),
|
torrent_file: z.string().min(1),
|
||||||
language: z.string().optional(),
|
language: z.string().optional(),
|
||||||
@@ -17,8 +16,8 @@ export const gameSchema = z.union([
|
|||||||
.string()
|
.string()
|
||||||
.min(1)
|
.min(1)
|
||||||
.transform((d) => new Date(d)),
|
.transform((d) => new Date(d)),
|
||||||
}),
|
})
|
||||||
]);
|
);
|
||||||
export type GameType = z.infer<typeof gameSchema>;
|
export type GameType = z.infer<typeof gameSchema>;
|
||||||
|
|
||||||
export const isGame = (a: any): a is GameType => {
|
export const isGame = (a: any): a is GameType => {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { GameCardType } from "@/entities/game";
|
import { GameCardType } from "@/entities/game";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export const GameCard = ({ card }: { card: GameCardType }) => {
|
export const GameCard = ({ card }: { card: GameCardType }) => {
|
||||||
return (
|
return (
|
||||||
<div className="group/gamecard cursor-pointer">
|
<Link className="group/gamecard cursor-pointer" href={"/games/" + card.id}>
|
||||||
{!!card.cover_preview && (
|
{!!card.cover_preview && (
|
||||||
<Image
|
<Image
|
||||||
src={card.cover_preview}
|
src={card.cover_preview}
|
||||||
@@ -26,6 +27,6 @@ export const GameCard = ({ card }: { card: GameCardType }) => {
|
|||||||
<p className="text-lg tb:text-sm pr-2 text-justify line-clamp-5 text-fg4">
|
<p className="text-lg tb:text-sm pr-2 text-justify line-clamp-5 text-fg4">
|
||||||
{card.description}
|
{card.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
19
src/shared/ui/cover/cover.tsx
Normal file
19
src/shared/ui/cover/cover.tsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
|
export const Cover = ({
|
||||||
|
cover,
|
||||||
|
type = "preview",
|
||||||
|
}: {
|
||||||
|
cover: string;
|
||||||
|
type?: "cover" | "preview";
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
src={cover}
|
||||||
|
className="rounded-lg aspect-video object-cover"
|
||||||
|
alt=""
|
||||||
|
width={type === "preview" ? 700 : 1280}
|
||||||
|
height={type === "preview" ? 400 : 720}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
3
src/shared/ui/cover/index.ts
Normal file
3
src/shared/ui/cover/index.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { Cover } from "./cover";
|
||||||
|
|
||||||
|
export { Cover };
|
||||||
Reference in New Issue
Block a user