# Frontend Development Guide ## Overview The Hotel Pi frontend is a fullscreen kiosk application built with **Vite** and **Svelte**. It provides a premium, responsive interface for browsing restaurants, attractions, and launching media apps. ## Architecture ``` src/ ├── App.svelte # Root component (routing & state) ├── main.js # Entry point ├── components/ # Reusable UI components │ ├── IdleScreen.svelte # Welcome/idle display │ ├── HomeScreen.svelte # Main menu │ ├── RestaurantsPage.svelte # Restaurant list │ ├── AttractionsPage.svelte # Attractions list │ └── Clock.svelte # Time display ├── lib/ │ ├── store.js # Svelte state management │ ├── api.js # Directus CMS integration │ ├── websocket.js # WebSocket client │ └── qrcode.js # QR code generation └── routes/ # Page components (if using SvelteKit) index.html # HTML entry point vite.config.js # Build configuration tsconfig.json # TypeScript config package.json # Dependencies ``` ## Development ### Setup ```bash cd frontend npm install npm run dev ``` Frontend will run on http://localhost:5173 with hot reload enabled. ### Commands ```bash npm run dev # Start dev server npm run build # Build for production npm run preview # Preview production build npm run format # Format code with Prettier npm run lint # Check code style ``` ## Core Components ### App.svelte Main application component handling: - Screen navigation (idle → home → restaurants/attractions) - Input handling (keyboard and WebSocket) - State management - API data fetching - Idle timeout logic **Props:** - None (root component) **State:** - `currentScreen` - Active screen - `selectedIndex` - Currently selected menu item - `restaurants`, `attractions` - CMS content - `wsConnected` - Control service connection status ### IdleScreen.svelte Fullscreen ambient display shown when idle. **Features:** - Animated gradient background - Current time display (Clock component) - Welcome message - Floating ambient elements - Auto-advance on any input **Props:** ```javascript export let welcomeName = 'Guest'; ``` ### HomeScreen.svelte Main menu with three options: 1. Watch Plex 2. Restaurants 3. Things to Do **Features:** - Grid-based menu layout - Navigation with arrow keys - Visual feedback for selected item - Smooth transitions ### RestaurantsPage.svelte Carousel of restaurants with details. **Features:** - Full-screen restaurant display - Image gallery - QR code for website - Description and cuisine type - Navigation controls **Data:** Pulled from Directus `restaurants` collection: - name - description - cuisine_type - website_url - image ### AttractionsPage.svelte Similar to RestaurantsPage but for attractions. **Features:** - Attraction showcase - Category badges - Distance information - Operating hours - Website QR code **Data:** From Directus `attractions` collection: - name - description - category - distance_km - website_url - hours - image ### Clock.svelte Real-time clock display. **Features:** - Updates every second - 12-hour format with AM/PM - Large, readable typeface - Text shadow for visibility ## Store (State Management) Located in `src/lib/store.js`: ```javascript export const currentScreen; // Svelte store export const selectedIndex; // Current selection export const restaurants; // From CMS export const attractions; // From CMS export const wsConnected; // WebSocket status export function pushScreen(screen); // Navigate to screen export function popScreen(); // Go back export function resetNavigation(); // Reset to idle ``` ### Usage ```svelte {#if $currentScreen === 'home'} {/if} ``` ## API Integration Located in `src/lib/api.js`: ```javascript export async function fetchRestaurants() // Get all restaurants export async function fetchAttractions() // Get all attractions export function getImageUrl(filename) // Construct image URL ``` ### Example ```javascript import { fetchRestaurants } from '$lib/api.js'; const restaurants = await fetchRestaurants(); // Returns: // [ // { // id: 'uuid', // name: 'La Bella Vita', // description: '...', // image: { ... } // } // ] ``` ## WebSocket Communication Located in `src/lib/websocket.js`: ```javascript const ws = new WebSocketManager(url); ws.on('connected', () => {}); ws.on('disconnected', () => {}); ws.on('input', (data) => {}); ws.connect(); ws.send('launch-plex'); ``` ## Styling ### Design System - **Colors:** - Primary: `#667eea` (purple-blue) - Accent Red: `#e94560` - Accent Cyan: `#00d4ff` - Dark BG: `#1a1a2e` - Card BG: `#0f3460` - **Typography:** - Font: Inter (system fonts fallback) - Sizes: 0.875rem to 4rem - Weights: 300 (light), 400 (regular), 600 (semibold), 700 (bold) - **Spacing:** - Base unit: 1rem - Gaps: 0.5rem to 3rem ### CSS Features - CSS Grid for layouts - Flexbox for components - CSS animations (preferred over JS) - Media queries for responsive design - CSS variables for theming ### Animations Key animations used: ```css @keyframes fade-in @keyframes slide-down @keyframes float @keyframes bounce @keyframes gradient-shift ``` Keep animations smooth and under 600ms for best UX. ## Input Handling ### Keyboard Input ```javascript 'arrowup', 'arrowdown', 'arrowleft', 'arrowright' - Navigate 'enter' - Select 'escape' - Go back any key - Wake from idle (if on idle screen) ``` ### WebSocket Input Control service sends `input` events: ```json { "type": "input", "payload": { "type": "up" // "up", "down", "left", "right", "select", "back" } } ``` ## Performance Optimization 1. **Lazy Loading:** Images load on-demand 2. **CSS Animations:** Prefer over JavaScript transitions 3. **Minimal Dependencies:** Only `qrcode` library 4. **Vite Optimization:** - Tree-shaking - Minification in production - Code splitting ## Building for Production ```bash npm run build # Creates dist/ with optimized bundle ``` ### Docker Production Build ```dockerfile FROM node:20-alpine WORKDIR /app COPY . . RUN npm ci && npm run build CMD ["npm", "run", "preview"] ``` ## Troubleshooting ### Hot Reload Not Working - Clear `.svelte-kit/` and `dist/` - Restart dev server - Check Vite config ### Components Not Updating - Verify store subscriptions use `$` prefix - Check for reactive declarations (`:`) - Ensure state updates are triggering changes ### CSS Not Applied - Check CSS is within ` ``` ## Browser Support - Chrome/Chromium 90+ - Firefox 88+ - Safari 14+ Tested primarily on Chromium for Raspberry Pi. ## Resources - [Svelte Docs](https://svelte.dev) - [Vite Docs](https://vitejs.dev) - [Inter Font](https://fonts.google.com/specimen/Inter)