diff --git a/README.md b/README.md index da98444..606c2fa 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,177 @@ -# React + TypeScript + Vite -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +# Portfolio (Vite + React + Tailwind) -Currently, two official plugins are available: +Personal portfolio site built with React + TypeScript and styled with Tailwind. Includes a light/dark theme toggle and an optional “Professional Reviews” section backed by Firebase Firestore. -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +## Features -## Expanding the ESLint configuration +- **Responsive single-page app** (SPA) with multiple portfolio sections. +- **Light/Dark theme** with persisted preference (`localStorage`). +- **Professional Reviews** + - Read reviews from Firestore on page load. + - Add review modal (name, position, rating, review text). + - If Firebase env vars are missing, reading returns an empty list and adding is disabled. -If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: +## Tech Stack -```js -export default tseslint.config({ - extends: [ - // Remove ...tseslint.configs.recommended and replace with this - ...tseslint.configs.recommendedTypeChecked, - // Alternatively, use this for stricter rules - ...tseslint.configs.strictTypeChecked, - // Optionally, add this for stylistic rules - ...tseslint.configs.stylisticTypeChecked, - ], - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) +- **Vite** (build + dev server) +- **React 19** + **TypeScript** +- **Tailwind CSS v4** (via `@tailwindcss/vite`) +- **Firebase (Firestore)** for reviews +- **Docker + Nginx** for production container + +## Getting Started (Local Dev) + +### Prerequisites + +- Node.js (recommended: **Node 22** to match the Docker build image) +- pnpm (recommended) or npm + +If you don’t have pnpm yet: + +```bash +corepack enable +corepack prepare pnpm@latest --activate ``` -You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: +### Install -```js -// eslint.config.js -import reactX from 'eslint-plugin-react-x' -import reactDom from 'eslint-plugin-react-dom' - -export default tseslint.config({ - plugins: { - // Add the react-x and react-dom plugins - 'react-x': reactX, - 'react-dom': reactDom, - }, - rules: { - // other rules... - // Enable its recommended typescript rules - ...reactX.configs['recommended-typescript'].rules, - ...reactDom.configs.recommended.rules, - }, -}) +```bash +pnpm install ``` + +### Run dev server + +```bash +pnpm dev +``` + +Vite will print the local URL (typically `http://localhost:5173`). + +## Environment Variables (Firebase) + +Firebase is optional, but required to use the Reviews feature. + +Create a `.env` file in the project root: + +```bash +VITE_FIREBASE_API_KEY=... +VITE_FIREBASE_AUTH_DOMAIN=... +VITE_FIREBASE_PROJECT_ID=... +VITE_FIREBASE_STORAGE_BUCKET=... +VITE_FIREBASE_MESSAGING_SENDER_ID=... +VITE_FIREBASE_APP_ID=... + +# Optional +VITE_FIREBASE_MEASUREMENT_ID=... +``` + +Vite only exposes environment variables prefixed with `VITE_`. + +### Firestore data model + +Reviews are stored in a Firestore collection named `reviews`. + +Document shape: + +```ts +interface Review { + name: string; + rating: number; // 1..5 + position: string; + text: string; +}; +``` + +## Firebase / Firestore Setup (for Reviews) + +1. Create a Firebase project. +2. Enable **Firestore Database**. +3. (Recommended for development) Start with permissive rules, then tighten before production. +4. Copy your Firebase web app config values into `.env.local`. + +Notes: + +- If Firebase is not configured, the app still runs normally—reviews will simply be empty and adding is disabled. + +## Scripts + +- `pnpm dev` — start Vite dev server +- `pnpm build` — typecheck (`tsc -b`) then build (`vite build`) +- `pnpm preview` — preview the production build locally +- `pnpm lint` — run ESLint + +## Production (Docker + Nginx) + +This repo includes a multi-stage Docker build: + +1. **Node build stage** runs `npm install` + `npm run build` +2. **Nginx stage** serves the `dist/` folder and provides SPA routing (`try_files ... /index.html`) + +### Build the image + +You must pass Firebase values as build args (they’re embedded at build time by Vite): + +```bash +docker build \ + --build-arg VITE_FIREBASE_API_KEY=... \ + --build-arg VITE_FIREBASE_AUTH_DOMAIN=... \ + --build-arg VITE_FIREBASE_PROJECT_ID=... \ + --build-arg VITE_FIREBASE_STORAGE_BUCKET=... \ + --build-arg VITE_FIREBASE_MESSAGING_SENDER_ID=... \ + --build-arg VITE_FIREBASE_APP_ID=... \ + --build-arg VITE_FIREBASE_MEASUREMENT_ID=... \ + -t portfolio:latest . +``` + +### Run the container + +```bash +docker run --rm -p 8080:80 portfolio:latest +``` + +Then open `http://localhost:8080`. + +### Docker Compose + +`docker-compose.yml` is provided and forwards Firebase env vars as build args. + +```bash +docker compose up --build +``` + +Note: the compose file currently uses `ports: - "80"` (short syntax). That exposes container port 80, for use with reverse proxy services, like Traefik, or more complex deployment methods, like Dokploy or Coolify. If you want a stable port, change it to something like: + +```yaml +ports: + - "8080:80" +``` + +## Project Structure + +```text +. +├─ src/ +│ ├─ main.tsx # React entrypoint +│ ├─ App.tsx # Main page composition + reviews modal +│ ├─ firebase.ts # Firebase + Firestore initialization +│ ├─ reviewsApi.ts # Firestore read/write helpers +│ ├─ contexts/ +│ │ └─ ThemeContext.tsx # Theme state + CSS variables +│ └─ components/ # Page sections (Hero, Tech, Reviews, Footer, ...) +├─ nginx.conf # SPA routing for production container +├─ Dockerfile # Vite build → Nginx serve +└─ vite.config.ts # Vite config (React + Tailwind) +``` + +## Customization Notes + +- Some sections accept an `isOutOfCollege` prop and are currently **disabled by default** in `src/App.tsx`. If you want those sections to render, pass `isOutOfCollege={true}` into the relevant components. +- Contact links are in the Hero section and Footer. + +## Troubleshooting + +- **Reviews don’t show up**: confirm Firestore is enabled and your Firebase env vars are set (`VITE_FIREBASE_*`). +- **“Firestore is not configured” error**: you’re missing one or more required Firebase variables. +- **Docker build doesn’t pick up env vars**: ensure you pass them as `--build-arg ...` (Vite embeds them during build). + diff --git a/package.json b/package.json index 2278e7c..75226e9 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "portfolio", + "description": "A personal portfolio website", "private": true, "version": "0.0.0", "type": "module", diff --git a/src/reviewsApi.ts b/src/reviewsApi.ts index 9d64604..b7b77d7 100644 --- a/src/reviewsApi.ts +++ b/src/reviewsApi.ts @@ -1,7 +1,7 @@ import { db } from './firebase.ts'; import { collection, getDocs, addDoc } from 'firebase/firestore'; -export type Review = { +export interface Review { name: string; rating: number; position: string;