Update README and improve code structure for reviews feature
This commit is contained in:
211
README.md
211
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
|
## Features
|
||||||
- [@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
|
|
||||||
|
|
||||||
## 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
|
- **Vite** (build + dev server)
|
||||||
export default tseslint.config({
|
- **React 19** + **TypeScript**
|
||||||
extends: [
|
- **Tailwind CSS v4** (via `@tailwindcss/vite`)
|
||||||
// Remove ...tseslint.configs.recommended and replace with this
|
- **Firebase (Firestore)** for reviews
|
||||||
...tseslint.configs.recommendedTypeChecked,
|
- **Docker + Nginx** for production container
|
||||||
// Alternatively, use this for stricter rules
|
|
||||||
...tseslint.configs.strictTypeChecked,
|
## Getting Started (Local Dev)
|
||||||
// Optionally, add this for stylistic rules
|
|
||||||
...tseslint.configs.stylisticTypeChecked,
|
### Prerequisites
|
||||||
],
|
|
||||||
languageOptions: {
|
- Node.js (recommended: **Node 22** to match the Docker build image)
|
||||||
// other options...
|
- pnpm (recommended) or npm
|
||||||
parserOptions: {
|
|
||||||
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
If you don’t have pnpm yet:
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
```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
|
```bash
|
||||||
// eslint.config.js
|
pnpm install
|
||||||
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,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 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).
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "portfolio",
|
"name": "portfolio",
|
||||||
|
"description": "A personal portfolio website",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { db } from './firebase.ts';
|
import { db } from './firebase.ts';
|
||||||
import { collection, getDocs, addDoc } from 'firebase/firestore';
|
import { collection, getDocs, addDoc } from 'firebase/firestore';
|
||||||
|
|
||||||
export type Review = {
|
export interface Review {
|
||||||
name: string;
|
name: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
position: string;
|
position: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user