fix: Move more directories

This commit is contained in:
Wanjohi
2025-09-06 16:50:44 +03:00
parent 1c1c73910b
commit 9818165a90
248 changed files with 9 additions and 9566 deletions

View File

@@ -0,0 +1,46 @@
import { z } from "zod";
import { timestamps } from "../drizzle/types";
import { baseGamesTable } from "../base-game/base-game.sql";
import { index, integer, json, pgEnum, pgTable, primaryKey, text, varchar } from "drizzle-orm/pg-core";
export const ImageTypeEnum = pgEnum("image_type", ["heroArt", "icon", "logo", "banner", "poster", "boxArt", "screenshot", "backdrop"])
export const ImageDimensions = z.object({
width: z.number().int(),
height: z.number().int(),
})
export const ImageColor = z.object({
hex: z.string(),
isDark: z.boolean()
})
export type ImageColor = z.infer<typeof ImageColor>;
export type ImageDimensions = z.infer<typeof ImageDimensions>;
export const imagesTable = pgTable(
"images",
{
...timestamps,
type: ImageTypeEnum("type").notNull(),
imageHash: varchar("image_hash", { length: 255 })
.notNull(),
baseGameID: varchar("base_game_id", { length: 255 })
.notNull()
.references(() => baseGamesTable.id, {
onDelete: "cascade"
}),
sourceUrl: text("source_url"), // The BoxArt is source Url will always be null;
position: integer("position").notNull().default(0),
fileSize: integer("file_size").notNull(),
dimensions: json("dimensions").$type<ImageDimensions>().notNull(),
extractedColor: json("extracted_color").$type<ImageColor>().notNull(),
},
(table) => [
primaryKey({
columns: [table.imageHash, table.type, table.baseGameID, table.position]
}),
index("idx_images_type").on(table.type),
index("idx_images_game_id").on(table.baseGameID),
]
)

View File

@@ -0,0 +1,119 @@
import { z } from "zod";
import { fn } from "../utils";
import { Examples } from "../examples";
import { createSelectSchema } from "drizzle-zod";
import { createTransaction } from "../drizzle/transaction";
import { ImageColor, ImageDimensions, imagesTable } from "./images.sql";
export namespace Images {
const Image = z.object({
hash: z.string().openapi({
description: "A unique cryptographic hash identifier for the image, used for deduplication and URL generation",
example: Examples.CommonImg[0].hash
}),
averageColor: ImageColor.openapi({
description: "The calculated dominant color of the image with light/dark classification, used for UI theming",
example: Examples.CommonImg[0].averageColor
}),
dimensions: ImageDimensions.openapi({
description: "The width and height dimensions of the image in pixels",
example: Examples.CommonImg[0].dimensions
}),
fileSize: z.number().int().openapi({
description: "The size of the image file in bytes, used for storage and bandwidth calculations",
example: Examples.CommonImg[0].fileSize
})
})
export const Info = z.object({
screenshots: Image.array().openapi({
description: "In-game captured images showing actual gameplay, user interface, and key moments",
example: Examples.Images.screenshots
}),
boxArts: Image.array().openapi({
description: "Square 1:1 aspect ratio artwork, typically used for store listings and thumbnails",
example: Examples.Images.boxArts
}),
posters: Image.array().openapi({
description: "Vertical 2:3 aspect ratio promotional artwork, similar to movie posters",
example: Examples.Images.posters
}),
banners: Image.array().openapi({
description: "Horizontal promotional artwork optimized for header displays and banners",
example: Examples.Images.banners
}),
heroArts: Image.array().openapi({
description: "High-resolution, wide-format artwork designed for featured content and main entries",
example: Examples.Images.heroArts
}),
backdrops: Image.array().openapi({
description: "Full-width backdrop images optimized for page layouts and decorative purposes",
example: Examples.Images.backdrops
}),
logos: Image.array().openapi({
description: "Official game logo artwork, typically with transparent backgrounds for flexible placement",
example: Examples.Images.logos
}),
icons: Image.array().openapi({
description: "Small-format identifiers used for application shortcuts and compact displays",
example: Examples.Images.icons
}),
}).openapi({
ref: "Images",
description: "Complete collection of game-related visual assets, including promotional materials, UI elements, and store assets",
example: Examples.Images
})
export type Info = z.infer<typeof Info>
export const InputInfo = createSelectSchema(imagesTable)
.omit({ timeCreated: true, timeDeleted: true, timeUpdated: true })
export const create = fn(
InputInfo,
(input) =>
createTransaction(async (tx) =>
tx
.insert(imagesTable)
.values(input)
.onConflictDoUpdate({
target: [imagesTable.imageHash, imagesTable.type, imagesTable.baseGameID, imagesTable.position],
set: { timeDeleted: null }
})
)
)
export function serialize(
input: typeof imagesTable.$inferSelect[],
): z.infer<typeof Info> {
return input
.sort((a, b) => {
if (a.type === b.type) {
return a.position - b.position;
}
return a.type.localeCompare(b.type);
})
.reduce<Record<`${typeof imagesTable.$inferSelect["type"]}s`, { hash: string; averageColor: ImageColor; dimensions: ImageDimensions; fileSize: number }[]>>((acc, img) => {
const key = `${img.type}s` as `${typeof img.type}s`
if (Array.isArray(acc[key])) {
acc[key]!.push({
hash: img.imageHash,
averageColor: img.extractedColor,
dimensions: img.dimensions,
fileSize: img.fileSize
})
}
return acc
}, {
screenshots: [],
boxArts: [],
banners: [],
heroArts: [],
posters: [],
backdrops: [],
icons: [],
logos: [],
})
}
}