mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 11:31:07 -05:00
feat: complete monorepo structure with frontend and shared resources
- Add complete backend/ directory with full Django application - Add frontend/ directory with Vite + TypeScript setup ready for Next.js - Add comprehensive shared/ directory with: - Complete documentation and memory-bank archives - Media files and avatars (letters, park/ride images) - Deployment scripts and automation tools - Shared types and utilities - Add architecture/ directory with migration guides - Configure pnpm workspace for monorepo development - Update .gitignore to exclude .django_tailwind_cli/ build artifacts - Preserve all historical documentation in shared/docs/memory-bank/ - Set up proper structure for full-stack development with shared resources
This commit is contained in:
346
frontend/README.md
Normal file
346
frontend/README.md
Normal file
@@ -0,0 +1,346 @@
|
||||
# ThrillWiki Frontend
|
||||
|
||||
Vue.js SPA frontend for the ThrillWiki monorepo.
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
Modern Vue 3 application with TypeScript and composition API:
|
||||
|
||||
```
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/ # Vue components
|
||||
│ │ ├── common/ # Shared components
|
||||
│ │ ├── parks/ # Park-specific components
|
||||
│ │ ├── rides/ # Ride-specific components
|
||||
│ │ └── moderation/ # Moderation components
|
||||
│ ├── views/ # Page components
|
||||
│ ├── router/ # Vue Router setup
|
||||
│ ├── stores/ # Pinia state management
|
||||
│ ├── composables/ # Vue 3 composables
|
||||
│ ├── services/ # API services
|
||||
│ ├── utils/ # Utility functions
|
||||
│ ├── types/ # TypeScript types
|
||||
│ └── assets/ # Static assets
|
||||
├── public/ # Public assets
|
||||
└── tests/ # Frontend tests
|
||||
```
|
||||
|
||||
## 🛠️ Technology Stack
|
||||
|
||||
- **Vue 3** - Frontend framework with Composition API
|
||||
- **TypeScript** - Type safety and better developer experience
|
||||
- **Vite** - Fast build tool and dev server
|
||||
- **Vue Router** - Client-side routing
|
||||
- **Pinia** - State management
|
||||
- **Tailwind CSS** - Utility-first CSS framework
|
||||
- **Headless UI** - Unstyled, accessible UI components
|
||||
- **Heroicons** - Beautiful SVG icons
|
||||
- **Axios** - HTTP client for API requests
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18+
|
||||
- pnpm 8+
|
||||
|
||||
### Setup
|
||||
|
||||
1. **Install dependencies**
|
||||
```bash
|
||||
cd frontend
|
||||
pnpm install
|
||||
```
|
||||
|
||||
2. **Environment configuration**
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# Edit .env with your settings
|
||||
```
|
||||
|
||||
3. **Start development server**
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
Frontend will be available at http://localhost:3000
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# API Configuration
|
||||
VITE_API_BASE_URL=http://localhost:8000/api
|
||||
|
||||
# App Configuration
|
||||
VITE_APP_TITLE=ThrillWiki
|
||||
VITE_APP_DESCRIPTION=Your ultimate guide to theme parks
|
||||
|
||||
# Feature Flags
|
||||
VITE_ENABLE_PWA=true
|
||||
VITE_ENABLE_ANALYTICS=false
|
||||
```
|
||||
|
||||
### Build Configuration
|
||||
|
||||
- **Vite** configuration in `vite.config.ts`
|
||||
- **TypeScript** configuration in `tsconfig.json`
|
||||
- **Tailwind CSS** configuration in `tailwind.config.js`
|
||||
|
||||
## 🧩 Components
|
||||
|
||||
### Component Structure
|
||||
|
||||
```typescript
|
||||
// Example component structure
|
||||
<template>
|
||||
<div class="component-wrapper">
|
||||
<!-- Template content -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import type { ComponentProps } from '@/types'
|
||||
|
||||
// Component logic
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Component-specific styles */
|
||||
</style>
|
||||
```
|
||||
|
||||
### Shared Components
|
||||
|
||||
- **AppHeader** - Navigation and user menu
|
||||
- **AppSidebar** - Main navigation sidebar
|
||||
- **LoadingSpinner** - Loading indicator
|
||||
- **ErrorMessage** - Error display component
|
||||
- **SearchBox** - Global search functionality
|
||||
|
||||
## 🗂️ State Management
|
||||
|
||||
Using **Pinia** for state management:
|
||||
|
||||
```typescript
|
||||
// stores/auth.ts
|
||||
export const useAuthStore = defineStore('auth', () => {
|
||||
const user = ref<User | null>(null)
|
||||
const isAuthenticated = computed(() => !!user.value)
|
||||
|
||||
const login = async (credentials: LoginData) => {
|
||||
// Login logic
|
||||
}
|
||||
|
||||
return { user, isAuthenticated, login }
|
||||
})
|
||||
```
|
||||
|
||||
### Available Stores
|
||||
|
||||
- **authStore** - User authentication
|
||||
- **parksStore** - Park data and operations
|
||||
- **ridesStore** - Ride information
|
||||
- **uiStore** - UI state (modals, notifications)
|
||||
- **themeStore** - Dark/light mode toggle
|
||||
|
||||
## 🛣️ Routing
|
||||
|
||||
Vue Router setup with:
|
||||
|
||||
- **Route guards** for authentication
|
||||
- **Lazy loading** for code splitting
|
||||
- **Meta fields** for page titles and permissions
|
||||
|
||||
```typescript
|
||||
// router/index.ts
|
||||
const routes = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: () => import('@/views/Home.vue')
|
||||
},
|
||||
{
|
||||
path: '/parks',
|
||||
name: 'Parks',
|
||||
component: () => import('@/views/parks/ParksIndex.vue')
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## 🎨 Styling
|
||||
|
||||
### Tailwind CSS
|
||||
|
||||
- **Dark mode** support with class strategy
|
||||
- **Custom colors** for brand consistency
|
||||
- **Responsive design** utilities
|
||||
- **Component classes** for reusable styles
|
||||
|
||||
### Theme System
|
||||
|
||||
```typescript
|
||||
// composables/useTheme.ts
|
||||
export const useTheme = () => {
|
||||
const isDark = ref(false)
|
||||
|
||||
const toggleTheme = () => {
|
||||
isDark.value = !isDark.value
|
||||
document.documentElement.classList.toggle('dark')
|
||||
}
|
||||
|
||||
return { isDark, toggleTheme }
|
||||
}
|
||||
```
|
||||
|
||||
## 🔌 API Integration
|
||||
|
||||
### Service Layer
|
||||
|
||||
```typescript
|
||||
// services/api.ts
|
||||
class ApiService {
|
||||
private client = axios.create({
|
||||
baseURL: import.meta.env.VITE_API_BASE_URL,
|
||||
withCredentials: true,
|
||||
})
|
||||
|
||||
// API methods
|
||||
getParks(params?: ParkFilters) {
|
||||
return this.client.get('/parks/', { params })
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Global error interceptors
|
||||
- User-friendly error messages
|
||||
- Retry mechanisms for failed requests
|
||||
- Offline support indicators
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Test Structure
|
||||
|
||||
```bash
|
||||
tests/
|
||||
├── unit/ # Unit tests
|
||||
├── e2e/ # End-to-end tests
|
||||
└── __mocks__/ # Mock files
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Unit tests
|
||||
pnpm run test
|
||||
|
||||
# E2E tests
|
||||
pnpm run test:e2e
|
||||
|
||||
# Watch mode
|
||||
pnpm run test:watch
|
||||
```
|
||||
|
||||
### Testing Tools
|
||||
|
||||
- **Vitest** - Unit testing framework
|
||||
- **Vue Test Utils** - Vue component testing
|
||||
- **Playwright** - End-to-end testing
|
||||
|
||||
## 📱 Progressive Web App
|
||||
|
||||
PWA features:
|
||||
|
||||
- **Service Worker** for offline functionality
|
||||
- **App Manifest** for installation
|
||||
- **Push Notifications** for updates
|
||||
- **Background Sync** for data synchronization
|
||||
|
||||
## 🔧 Build & Deployment
|
||||
|
||||
### Development Build
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
### Production Build
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### Preview Production Build
|
||||
|
||||
```bash
|
||||
pnpm run preview
|
||||
```
|
||||
|
||||
### Build Output
|
||||
|
||||
- Static assets in `dist/`
|
||||
- Optimized and minified code
|
||||
- Source maps for debugging
|
||||
- Chunk splitting for performance
|
||||
|
||||
## 🎯 Performance
|
||||
|
||||
### Optimization Strategies
|
||||
|
||||
- **Code splitting** with dynamic imports
|
||||
- **Image optimization** with responsive loading
|
||||
- **Bundle analysis** with rollup-plugin-visualizer
|
||||
- **Lazy loading** for routes and components
|
||||
|
||||
### Core Web Vitals
|
||||
|
||||
- First Contentful Paint (FCP)
|
||||
- Largest Contentful Paint (LCP)
|
||||
- Cumulative Layout Shift (CLS)
|
||||
|
||||
## ♿ Accessibility
|
||||
|
||||
- **ARIA labels** and roles
|
||||
- **Keyboard navigation** support
|
||||
- **Screen reader** compatibility
|
||||
- **Color contrast** compliance
|
||||
- **Focus management**
|
||||
|
||||
## 🐛 Debugging
|
||||
|
||||
### Development Tools
|
||||
|
||||
- Vue DevTools browser extension
|
||||
- Vite's built-in debugging features
|
||||
- TypeScript error reporting
|
||||
- Hot module replacement (HMR)
|
||||
|
||||
### Logging
|
||||
|
||||
```typescript
|
||||
// utils/logger.ts
|
||||
export const logger = {
|
||||
info: (message: string, data?: any) => {
|
||||
if (import.meta.env.DEV) {
|
||||
console.log(message, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 Deployment
|
||||
|
||||
See the [Deployment Guide](../shared/docs/deployment/) for production setup.
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
1. Follow Vue.js style guide
|
||||
2. Use TypeScript for type safety
|
||||
3. Write tests for components
|
||||
4. Follow Prettier formatting
|
||||
5. Use conventional commits
|
||||
14
frontend/index.html
Normal file
14
frontend/index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ThrillWiki</title>
|
||||
<meta name="description" content="Your ultimate guide to theme parks and thrilling rides" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
47
frontend/package.json
Normal file
47
frontend/package.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "thrillwiki-frontend",
|
||||
"version": "0.1.0",
|
||||
"description": "ThrillWiki Vue.js Frontend",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest",
|
||||
"test:e2e": "playwright test",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
|
||||
"format": "prettier --write src/",
|
||||
"type-check": "vue-tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.4.0",
|
||||
"vue-router": "^4.3.0",
|
||||
"pinia": "^2.1.0",
|
||||
"axios": "^1.6.0",
|
||||
"@headlessui/vue": "^1.7.0",
|
||||
"@heroicons/vue": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.0.0",
|
||||
"vite": "^5.0.0",
|
||||
"vue-tsc": "^2.0.0",
|
||||
"typescript": "^5.3.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"autoprefixer": "^10.4.0",
|
||||
"postcss": "^8.4.0",
|
||||
"eslint": "^8.57.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||
"@typescript-eslint/parser": "^7.0.0",
|
||||
"eslint-plugin-vue": "^9.20.0",
|
||||
"prettier": "^3.2.0",
|
||||
"vitest": "^1.3.0",
|
||||
"@playwright/test": "^1.42.0",
|
||||
"@vue/test-utils": "^2.4.0",
|
||||
"jsdom": "^24.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"pnpm": ">=8.0.0"
|
||||
}
|
||||
}
|
||||
0
frontend/public/favicon.ico
Normal file
0
frontend/public/favicon.ico
Normal file
23
frontend/src/assets/styles/globals.css
Normal file
23
frontend/src/assets/styles/globals.css
Normal file
@@ -0,0 +1,23 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
html {
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-md font-medium focus:outline-none focus:ring-2 focus:ring-offset-2;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply btn bg-primary-600 text-white hover:bg-primary-700 focus:ring-primary-500;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply btn bg-gray-200 text-gray-900 hover:bg-gray-300 focus:ring-gray-500;
|
||||
}
|
||||
}
|
||||
13
frontend/src/main.ts
Normal file
13
frontend/src/main.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import router from './router'
|
||||
import App from './App.vue'
|
||||
|
||||
import './assets/styles/globals.css'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
34
frontend/tailwind.config.js
Normal file
34
frontend/tailwind.config.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||
],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#eff6ff',
|
||||
100: '#dbeafe',
|
||||
200: '#bfdbfe',
|
||||
300: '#93c5fd',
|
||||
400: '#60a5fa',
|
||||
500: '#3b82f6',
|
||||
600: '#2563eb',
|
||||
700: '#1d4ed8',
|
||||
800: '#1e40af',
|
||||
900: '#1e3a8a',
|
||||
950: '#172554',
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/typography'),
|
||||
],
|
||||
}
|
||||
42
frontend/tsconfig.json
Normal file
42
frontend/tsconfig.json
Normal file
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": [
|
||||
"ES2020",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "preserve",
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
/* Path mapping */
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
12
frontend/tsconfig.node.json
Normal file
12
frontend/tsconfig.node.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
33
frontend/vite.config.ts
Normal file
33
frontend/vite.config.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { resolve } from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
port: 3000,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:8000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
'/media': {
|
||||
target: 'http://localhost:8000',
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
assetsDir: 'assets',
|
||||
sourcemap: true,
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user