From 79c2b62306026ba7ddcfb9a88c2851d4e54fe986 Mon Sep 17 00:00:00 2001 From: Richard Grover <38992201+richgrov@users.noreply.github.com> Date: Tue, 20 May 2025 08:44:52 -0600 Subject: [PATCH] Initial commit --- .dockerignore | 3 + Dockerfile | 58 +++++++ app/page.js | 148 +++++++---------- app/page.module.css | 214 ++++++++++++------------ package-lock.json | 388 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 5 +- 6 files changed, 617 insertions(+), 199 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 package-lock.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7651bc4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +.env +.next/ +node_modules/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7316ce6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +# syntax=docker.io/docker/dockerfile:1 + +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +WORKDIR /app + +RUN npm i -g bun + +# Install dependencies based on the preferred package manager +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ +RUN npm i --frozen-lockfile + + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry during the build. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN npm run build + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +# Uncomment the following line in case you want to disable telemetry during runtime. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 + +# server.js is created by next build from the standalone output +# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output +ENV HOSTNAME="0.0.0.0" +CMD ["node", "server.js"] diff --git a/app/page.js b/app/page.js index a9c3e29..232d47d 100644 --- a/app/page.js +++ b/app/page.js @@ -1,95 +1,67 @@ -import Image from "next/image"; import styles from "./page.module.css"; +import postgres from "postgres"; + +const sql = postgres({ + host: "localhost:5432", + username: process.env["USERNAME"], + password: process.env["PASSWORD"], +}); + +await sql`CREATE TABLE IF NOT EXISTS Messages(name text, message text);`; + +function Form() { + async function onSubmit(formData) { + "use server"; + const name = formData.get("name"); + const message = formData.get("message"); + await sql`INSERT INTO Messages(name, message) VALUES (${name}, ${message})`; + router.refresh(); + } + + return ( +
+ + + +
+ ); +} + +function Message(props) { + const user = props.user; + const text = props.text; + return ( +

+ {user}: {text} +

+ ); +} + +export default async function Home() { + const messages = await sql`SELECT * FROM Messages`; + + const messageComponents = []; + let i = -1; + for (const message of messages) { + i++; + messageComponents.push( + , + ); + } -export default function Home() { return (
-
- Next.js logo -
    -
  1. - Get started by editing app/page.js. -
  2. -
  3. Save and see your changes instantly.
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
-
- +
+ {messageComponents}
); } diff --git a/app/page.module.css b/app/page.module.css index a11c8f3..24a7f11 100644 --- a/app/page.module.css +++ b/app/page.module.css @@ -1,168 +1,164 @@ .page { - --gray-rgb: 0, 0, 0; - --gray-alpha-200: rgba(var(--gray-rgb), 0.08); - --gray-alpha-100: rgba(var(--gray-rgb), 0.05); + --gray-rgb: 0, 0, 0; + --gray-alpha-200: rgba(var(--gray-rgb), 0.08); + --gray-alpha-100: rgba(var(--gray-rgb), 0.05); - --button-primary-hover: #383838; - --button-secondary-hover: #f2f2f2; + --button-primary-hover: #383838; + --button-secondary-hover: #f2f2f2; - display: grid; - grid-template-rows: 20px 1fr 20px; - align-items: center; - justify-items: center; - min-height: 100svh; - padding: 80px; - gap: 64px; - font-family: var(--font-geist-sans); + min-height: 100svh; + padding: 80px; + gap: 64px; + font-family: var(--font-geist-sans); } @media (prefers-color-scheme: dark) { - .page { - --gray-rgb: 255, 255, 255; - --gray-alpha-200: rgba(var(--gray-rgb), 0.145); - --gray-alpha-100: rgba(var(--gray-rgb), 0.06); + .page { + --gray-rgb: 255, 255, 255; + --gray-alpha-200: rgba(var(--gray-rgb), 0.145); + --gray-alpha-100: rgba(var(--gray-rgb), 0.06); - --button-primary-hover: #ccc; - --button-secondary-hover: #1a1a1a; - } + --button-primary-hover: #ccc; + --button-secondary-hover: #1a1a1a; + } } .main { - display: flex; - flex-direction: column; - gap: 32px; - grid-row-start: 2; + display: flex; + flex-direction: column; + gap: 32px; + grid-row-start: 2; } .main ol { - font-family: var(--font-geist-mono); - padding-left: 0; - margin: 0; - font-size: 14px; - line-height: 24px; - letter-spacing: -0.01em; - list-style-position: inside; + font-family: var(--font-geist-mono); + padding-left: 0; + margin: 0; + font-size: 14px; + line-height: 24px; + letter-spacing: -0.01em; + list-style-position: inside; } .main li:not(:last-of-type) { - margin-bottom: 8px; + margin-bottom: 8px; } .main code { - font-family: inherit; - background: var(--gray-alpha-100); - padding: 2px 4px; - border-radius: 4px; - font-weight: 600; + font-family: inherit; + background: var(--gray-alpha-100); + padding: 2px 4px; + border-radius: 4px; + font-weight: 600; } .ctas { - display: flex; - gap: 16px; + display: flex; + gap: 16px; } .ctas a { - appearance: none; - border-radius: 128px; - height: 48px; - padding: 0 20px; - border: none; - border: 1px solid transparent; - transition: - background 0.2s, - color 0.2s, - border-color 0.2s; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - line-height: 20px; - font-weight: 500; + appearance: none; + border-radius: 128px; + height: 48px; + padding: 0 20px; + border: none; + border: 1px solid transparent; + transition: + background 0.2s, + color 0.2s, + border-color 0.2s; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + line-height: 20px; + font-weight: 500; } a.primary { - background: var(--foreground); - color: var(--background); - gap: 8px; + background: var(--foreground); + color: var(--background); + gap: 8px; } a.secondary { - border-color: var(--gray-alpha-200); - min-width: 158px; + border-color: var(--gray-alpha-200); + min-width: 158px; } .footer { - grid-row-start: 3; - display: flex; - gap: 24px; + grid-row-start: 3; + display: flex; + gap: 24px; } .footer a { - display: flex; - align-items: center; - gap: 8px; + display: flex; + align-items: center; + gap: 8px; } .footer img { - flex-shrink: 0; + flex-shrink: 0; } /* Enable hover only on non-touch devices */ @media (hover: hover) and (pointer: fine) { - a.primary:hover { - background: var(--button-primary-hover); - border-color: transparent; - } + a.primary:hover { + background: var(--button-primary-hover); + border-color: transparent; + } - a.secondary:hover { - background: var(--button-secondary-hover); - border-color: transparent; - } + a.secondary:hover { + background: var(--button-secondary-hover); + border-color: transparent; + } - .footer a:hover { - text-decoration: underline; - text-underline-offset: 4px; - } + .footer a:hover { + text-decoration: underline; + text-underline-offset: 4px; + } } @media (max-width: 600px) { - .page { - padding: 32px; - padding-bottom: 80px; - } + .page { + padding: 32px; + padding-bottom: 80px; + } - .main { - align-items: center; - } + .main { + align-items: center; + } - .main ol { - text-align: center; - } + .main ol { + text-align: center; + } - .ctas { - flex-direction: column; - } + .ctas { + flex-direction: column; + } - .ctas a { - font-size: 14px; - height: 40px; - padding: 0 16px; - } + .ctas a { + font-size: 14px; + height: 40px; + padding: 0 16px; + } - a.secondary { - min-width: auto; - } + a.secondary { + min-width: auto; + } - .footer { - flex-wrap: wrap; - align-items: center; - justify-content: center; - } + .footer { + flex-wrap: wrap; + align-items: center; + justify-content: center; + } } @media (prefers-color-scheme: dark) { - .logo { - filter: invert(); - } + .logo { + filter: invert(); + } } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..3587683 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,388 @@ +{ + "name": "chat-were-back", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "chat-were-back", + "version": "0.1.0", + "dependencies": { + "next": "15.3.2", + "postgres": "^3.4.5", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.1", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.1.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.1.0", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@next/env": { + "version": "15.3.2", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.3.2", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001718", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "license": "MIT", + "optional": true + }, + "node_modules/color-string": { + "version": "1.9.1", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "license": "MIT", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.11", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "15.3.2", + "license": "MIT", + "dependencies": { + "@next/env": "15.3.2", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.3.2", + "@next/swc-darwin-x64": "15.3.2", + "@next/swc-linux-arm64-gnu": "15.3.2", + "@next/swc-linux-arm64-musl": "15.3.2", + "@next/swc-linux-x64-gnu": "15.3.2", + "@next/swc-linux-x64-musl": "15.3.2", + "@next/swc-win32-arm64-msvc": "15.3.2", + "@next/swc-win32-x64-msvc": "15.3.2", + "sharp": "^0.34.1" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.31", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postgres": { + "version": "3.4.5", + "license": "Unlicense", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" + } + }, + "node_modules/react": { + "version": "19.1.0", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.0", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.0" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.1", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.7.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.1", + "@img/sharp-darwin-x64": "0.34.1", + "@img/sharp-libvips-darwin-arm64": "1.1.0", + "@img/sharp-libvips-darwin-x64": "1.1.0", + "@img/sharp-libvips-linux-arm": "1.1.0", + "@img/sharp-libvips-linux-arm64": "1.1.0", + "@img/sharp-libvips-linux-ppc64": "1.1.0", + "@img/sharp-libvips-linux-s390x": "1.1.0", + "@img/sharp-libvips-linux-x64": "1.1.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", + "@img/sharp-libvips-linuxmusl-x64": "1.1.0", + "@img/sharp-linux-arm": "0.34.1", + "@img/sharp-linux-arm64": "0.34.1", + "@img/sharp-linux-s390x": "0.34.1", + "@img/sharp-linux-x64": "0.34.1", + "@img/sharp-linuxmusl-arm64": "0.34.1", + "@img/sharp-linuxmusl-x64": "0.34.1", + "@img/sharp-wasm32": "0.34.1", + "@img/sharp-win32-ia32": "0.34.1", + "@img/sharp-win32-x64": "0.34.1" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "license": "0BSD" + } + } +} diff --git a/package.json b/package.json index 249fbda..cf2103a 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,9 @@ "lint": "next lint" }, "dependencies": { + "next": "15.3.2", + "postgres": "^3.4.5", "react": "^19.0.0", - "react-dom": "^19.0.0", - "next": "15.3.2" + "react-dom": "^19.0.0" } }