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:
pacnpal
2025-08-23 18:40:07 -04:00
parent b0e0678590
commit d504d41de2
762 changed files with 142636 additions and 0 deletions

346
frontend/README.md Normal file
View 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
View 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
View 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"
}
}

View File

View 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
View 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')

View 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
View 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"
}
]
}

View 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
View 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,
},
})