commit 92f4d037b187766e5d7312756dae7c251ba146fb Author: Min Zeya Phyo Date: Tue Jan 20 12:14:35 2026 +0630 Initial commit from react-vite boilerplate diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..51879c8 --- /dev/null +++ b/.env.example @@ -0,0 +1,5 @@ +# API Configuration +VITE_API_URL=https://api.example.com + +# Feature Flags +VITE_ENABLE_ANALYTICS=false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80901ec --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Dependencies +node_modules/ + +# Build output +dist/ + +# Environment +.env +.env.local +.env.*.local + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log +npm-debug.log* + +# Testing +coverage/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4d8a46a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy source code +COPY . . + +# Build the application +RUN npm run build + +# Production stage +FROM nginx:alpine + +# Copy custom nginx config +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Copy built assets from builder +COPY --from=builder /app/dist /usr/share/nginx/html + +# Expose port +EXPOSE 3000 + +# Start nginx +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..d81f658 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# bp-rect + +React + Vite + TypeScript + TailwindCSS application. + +## Quick Start + +```bash +# Install dependencies +npm install + +# Start development server +npm run dev + +# Build for production +npm run build + +# Preview production build +npm run preview +``` + +## Deploy to Unity Infrastructure + +### Prerequisites + +1. DNS record pointing to Gateway (3.0.22.121) +2. Git repository on Gitea (git.qikbite.asia) + +### Deployment Steps + +1. **Push to Gitea:** + ```bash + git remote add origin https://git.qikbite.asia/git_admin/bp-rect.git + git push -u origin main + ``` + +2. **Create app in Coolify:** + ```bash + curl -sk -X POST 'https://coolify.qikbite.asia/api/v1/applications/dockerfile' \ + --header 'Authorization: Bearer ' \ + --header 'Content-Type: application/json' \ + --data '{ + "project_uuid": "r8so044sg4cgcko84o8kgcks", + "server_uuid": "v8s4kw84o00gcocwcwos4k4s", + "destination_uuid": "tg80co08408s04oo80cg80ok", + "environment_name": "production", + "git_repository": "https://git.qikbite.asia/git_admin/bp-rect.git", + "git_branch": "main", + "build_pack": "dockerfile", + "ports_exposes": "3000", + "name": "bp-rect" + }' + ``` + +3. **Add Gateway route** (SSH to 3.0.22.121): + ```yaml + # /home/ubuntu/traefik/config/dynamic/services.yml + http: + routers: + bp-rect: + rule: "Host(`bp-rect.qikbite.asia`)" + service: coolify-apps + tls: + certResolver: letsencrypt + entryPoints: + - websecure + ``` + +4. **Verify:** https://bp-rect.qikbite.asia + +## Project Structure + +``` +src/ +├── components/ # Reusable UI components +├── pages/ # Route pages +├── hooks/ # Custom React hooks +├── lib/ # Utilities and API clients +└── styles/ # Global styles +``` + +## Tech Stack + +- React 18 +- TypeScript +- Vite 5 +- TailwindCSS 3 +- React Router 6 +- TanStack Query +- Zustand (state management) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..2eb5c76 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,11 @@ +# Local development +services: + app: + build: . + ports: + - "3000:3000" + volumes: + - ./src:/app/src + - ./public:/app/public + environment: + - NODE_ENV=development diff --git a/index.html b/index.html new file mode 100644 index 0000000..03fa742 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + bp-rect + + +
+ + + diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..ed3dce0 --- /dev/null +++ b/nginx.conf @@ -0,0 +1,26 @@ +server { + listen 3000; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + + # Handle React Router (SPA) + location / { + try_files $uri $uri/ /index.html; + } + + # Cache static assets + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..60dbd19 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "bp-rect", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.20.0", + "@tanstack/react-query": "^5.8.0", + "axios": "^1.6.0", + "zustand": "^4.4.0" + }, + "devDependencies": { + "@types/react": "^18.2.0", + "@types/react-dom": "^18.2.0", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "@vitejs/plugin-react": "^4.2.0", + "autoprefixer": "^10.4.16", + "eslint": "^8.53.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.4", + "postcss": "^8.4.31", + "tailwindcss": "^3.3.5", + "typescript": "^5.2.2", + "vite": "^5.0.0" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..4732c14 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,14 @@ +import { Routes, Route } from 'react-router-dom' +import Home from './pages/Home' +import NotFound from './pages/NotFound' + +function App() { + return ( + + } /> + } /> + + ) +} + +export default App diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..7726881 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { BrowserRouter } from 'react-router-dom' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import App from './App' +import './styles/index.css' + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 1000 * 60 * 5, // 5 minutes + retry: 1, + }, + }, +}) + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + + + , +) diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx new file mode 100644 index 0000000..2e336b4 --- /dev/null +++ b/src/pages/Home.tsx @@ -0,0 +1,32 @@ +export default function Home() { + return ( +
+
+

+ Welcome to bp-rect +

+

+ Your React + Vite application is running! +

+
+ + Vite Docs + + + React Docs + +
+
+
+ ) +} diff --git a/src/pages/NotFound.tsx b/src/pages/NotFound.tsx new file mode 100644 index 0000000..47607ab --- /dev/null +++ b/src/pages/NotFound.tsx @@ -0,0 +1,18 @@ +import { Link } from 'react-router-dom' + +export default function NotFound() { + return ( +
+
+

404

+

Page not found

+ + Go Home + +
+
+ ) +} diff --git a/src/styles/index.css b/src/styles/index.css new file mode 100644 index 0000000..2e129cf --- /dev/null +++ b/src/styles/index.css @@ -0,0 +1,15 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; +} + +body { + margin: 0; + min-width: 320px; + min-height: 100vh; +} diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..b54b4c9 --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly VITE_API_URL: string +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..dca8ba0 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5413626 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..c96ef79 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + server: { + port: 3000, + host: true, + }, + preview: { + port: 3000, + host: true, + }, + build: { + outDir: 'dist', + sourcemap: false, + }, +})