From 0a19018ba4dfc8c903f0c3c7434618589a3df61c Mon Sep 17 00:00:00 2001 From: root Date: Mon, 14 Apr 2025 22:26:54 +0000 Subject: [PATCH] Initial commit from Orsiris --- .dockerignore | 1 + Dockerfile | 18 +++++++++++++ app/characters/[id]/page.tsx | 43 ++++++++++++++++++++++++++++++++ data/characters/CC-CHR-0001.json | 16 ++++++++++++ docker-compose.yml | 22 ++++++++++++++++ 5 files changed, 100 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 app/characters/[id]/page.tsx create mode 100644 data/characters/CC-CHR-0001.json create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..d619a0c --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +node_modules\n.dockerignore\n.git\n*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..251e9bc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +FROM node:18-alpine AS builder +WORKDIR /app + +COPY package*.json ./ +RUN npm install + +COPY . . +RUN npm run build + +FROM node:18-alpine +WORKDIR /app + +COPY --from=builder /app ./ +ENV NODE_ENV=production + +EXPOSE 3000 +CMD ["npm", "start"] + diff --git a/app/characters/[id]/page.tsx b/app/characters/[id]/page.tsx new file mode 100644 index 0000000..fb1d2bc --- /dev/null +++ b/app/characters/[id]/page.tsx @@ -0,0 +1,43 @@ +import { promises as fs } from 'fs' +import path from 'path' + +// ✅ Tell Next.js to render dynamically on every request +export const dynamic = "force-dynamic" + +export default async function Page({ params }: { params: any }) { + const filePath = path.join(process.cwd(), 'data', 'characters', `${params.id}.json`) + + try { + const raw = await fs.readFile(filePath, 'utf-8') + const character = JSON.parse(raw) + + return ( +
+

+ {character.name} ({character.codename}) +

+

Age: {character.age}

+

Rank: {character.rank}

+

Affiliation: {character.affiliation}

+ +

Quotes:

+ +
+ ) + } catch (error) { + return ( +
+

+ Character not found: {params.id} +

+

+ Tried to read: {filePath} +

+
+ ) + } +} diff --git a/data/characters/CC-CHR-0001.json b/data/characters/CC-CHR-0001.json new file mode 100644 index 0000000..b71ebf5 --- /dev/null +++ b/data/characters/CC-CHR-0001.json @@ -0,0 +1,16 @@ +{ + "id": "CC-CHR-0001", + "codename": "Soupfork", + "name": "Cadet Captain Tsai", + "age": 17, + "rank": "Naval Cadet Captain", + "affiliation": "Troy High NJROTC", + "quotes": [ + "Discipline first. Emotions after.", + "I'm not a princess. I'm a commanding officer." + ], + "food_likes": ["Unagi don", "Salmon sushi", "Cucumber", "Japanese curry"], + "food_dislikes": ["Eggplant"], + "signature_equipment": "Prototype Silver Combat Boots" +} + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..fd3397a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +services: + cc-web: + build: . + container_name: cc-web + restart: always + environment: + - NODE_ENV=production + - VIRTUAL_HOST=cc.johntsai.online + - LETSENCRYPT_HOST=cc.johntsai.online + - LETSENCRYPT_EMAIL=john@johntsai.online + expose: + - "3000" + volumes: + - ./data:/app/data + - ./public/images:/app/public/images + networks: + - proxy + +networks: + proxy: + external: true +