As a frontend developer, implement the Navbar section for the Home page. Build the `Navbar` component using `useState` to manage the mobile menu open/close state (`open`). Render a `nav.nv-root` with an inner `div.nv-inner` containing: a logo anchor (`a.nv-logo`) with `Globe` icon from lucide-react and DESTRAVE branding text; a desktop `ul.nv-links` mapping over the `links` array (Início, Categorias, Frases, Favoritos) to anchor tags; a `div.nv-actions` with a CTA anchor to `/Phrases` featuring the `Sparkles` icon; and a `button.nv-burger` that toggles the `nv-open` class with three `span.nv-burger-bar` children and proper `aria-expanded` attribute. Also render a `div.nv-mobile` with `nv-mobile-open` class conditionally applied, containing a mobile link list and a mobile CTA anchor, both calling `closeMenu` on click. Apply all styles from `Navbar.css`.
As a Frontend Developer, configure the global design system and theme for the DESTRAVE application. Set up CSS variables for the color palette: primary #FF5733, primary_light #FF8F66, secondary #3366FF, accent #33FF57, highlight #FFD700, bg #FFFFFF, surface rgba(255,255,255,0.9), text #000000, text_muted #666666, border rgba(0,0,0,0.1). Configure global typography with larger base font sizes (18px+) for accessibility targeting users 50+. Set up global reset, base styles, and shared utility classes. Configure Framer Motion global settings and ensure @react-three/fiber and three.js dependencies are installed. Create a shared CSS variables file imported by all component stylesheets.
As a Backend Developer, define MongoDB document schemas and seed data for the DESTRAVE application using Motor (async MongoDB driver for FastAPI). Create the following collections: 1) phrases - fields: id, portuguese (string), translations (array of {lang, flag, text}), category (string), difficulty (easy/medium/hard), context (string), popularity (int), created_at; 2) categories - fields: id, name, emoji, description, slug; 3) favorites - fields: id, phrase_id, user_session, saved_at. Write a seed script populating all 9 categories and at least 50+ phrases covering all categories (commerce, education, public spaces, home, transportation, greetings, food, accommodation, personal care) with translations in Spanish, French, and English. Create indexes on phrases.category, phrases.difficulty, and favorites.user_session for query performance.
As a frontend developer, implement the `HomeHero` section for the Home page. Use `useRef` for the section ref and framer-motion hooks: `useScroll` (offset `['start start','end start']`), `useSpring` (stiffness 80, damping 20), and `useTransform`/`useMotionTemplate` to derive `bgTranslateY` (0 to -180), `mgTranslateY` (0 to -360), and a dynamic `gradientBg` that hue-rotates from 0°→45°→90° as the user scrolls. Render three layers: a `motion.div.hh-bg-layer` with the animated gradient background and three decorative orb divs (`hh-orb--warm`, `hh-orb--cool`, `hh-orb--gold`); a `motion.div.hh-mg-layer` with `y: mgTranslateY` style containing 6 floating emoji spans positioned absolutely via the `emojis` array; and a `div.hh-content` with `motion` entrance animations (`opacity 0→1, y 18→0` for badge; `opacity 0→1, scale 0.88→1` for h1) triggered `whileInView`. Also render a language flags bar for ES/FR/EN and a `ChevronDown` scroll indicator. Apply styles from `HomeHero.css`.
As a frontend developer, implement the `HomeCategoriesGrid` section for the Home page. Define the `categories` array of 9 items (comercio, educacao, espacos-publicos, casa, transporte, saudacoes, alimentacao, hospedagem, cuidados-pessoais) each with emoji, name, and desc. Define `cardVariants` (`initial: opacity 0, y 28` → `visible: opacity 1, y 0`) and `containerVariants` with `staggerChildren: 0.1, delayChildren: 0.15`. Build a `Card` sub-component using `useRef` and `useInView` (`once: true, margin: '-40px 0px'`) to trigger the card variant animation. Each card is a `motion.a` linking to `/Category` with `whileHover: {y: -4, boxShadow orange shadow}` and `whileTap: {scale: 0.97}`. Inside the card render a `motion.span.hcg-card-emoji` with `whileHover` scale/background, a `motion.h3.hcg-card-name` with `whileHover` color change, a `p.hcg-card-desc`, and a `motion.span.hcg-card-arrow` with `whileHover` x-translate. Render a decorative `hcg-decor-bg` parallax layer. Apply styles from `HomeCategoriesGrid.css`.
As a frontend developer, implement the `HomeHowItWorks` section for the Home page. Define a `steps` array of 3 items: '1 Selecione uma Categoria', '2 Explore Frases', '3 Pratique e Salve'. Define `cardVariants` with `hidden: {opacity:0, y:32}` and `visible(i)` returning staggered transitions (delay `0.2 + i*0.18`, cubic-bezier easing). Define `badgeVariants` with a scale pulse `[1,1.1,1]` at delay 0.55 and `arrowVariants` fading in from `x:-10`. Render two CSS parallax layers: `hiw-bg-layer` with `translateY(calc(var(--scroll,0)*-0.3px))` containing two `hiw-bg-blob` divs, and `hiw-mid-layer` at speed 0.6 with four `hiw-mid-dot` divs. In the content layer, animate the section header (`hiw-title`, `hiw-subtitle`) with `whileInView opacity/y`. Map over steps rendering `motion.div.hiw-step.hiw-step--N` using `custom={i}` with `whileInView='visible'` and the staggered cardVariants; inside each step render the `badgeVariants` animated step number badge, the icon, title, desc, and between steps render the `arrowVariants` animated connector arrows. Apply styles from `HomeHowItWorks.css`.
As a frontend developer, implement the `HomeCTA` section for the Home page. Use `useState` for `burstId` (incrementing int) and `ripple` ({active, x, y}). Implement `handleClick` with `useCallback`: on click, compute cursor position relative to the button's bounding rect via `e.currentTarget.getBoundingClientRect()`, set `ripple` active with x/y coordinates, increment `burstId`, and reset ripple after 500ms via `setTimeout`. Generate `PARTICLE_COUNT=7` particles using `Array.from`, each with an `id` of `${burstId}-${i}` and an `angle` computed from `i * (2π/7)`. Render two CSS parallax decorative divs (`hcta-glow-bg` at speed 0.3 and `hcta-glow-mid` at speed 0.6) with radial gradient backgrounds. In `hcta-inner`, animate `h2.hcta-title` and `p.hcta-desc` with `whileInView opacity/y` transitions (desc delayed by 0.12s). Render a `motion.a.hcta-btn` linking to `/Phrases` with `onClick={handleClick}`, `whileHover: {scale:1.05, boxShadow green glow}`, `whileTap: {scale:0.97}`, spring transition (stiffness 400, damping 17). Use `AnimatePresence` to render particle burst elements keyed by `burstId`. Apply styles from `HomeCTA.css`.
As a frontend developer, implement the `Footer` section for the Home page. Note: this component may already exist from a previous page and should be reused if available. Render a `footer.ftr-root` with a decorative `div.ftr-glow`. Inside `ftr-inner`, render a `ftr-brand-col` containing: a logo anchor to `/Home` with `Globe` icon (strokeWidth 2.2) and 'DESTRAVE' brand name; a `p.ftr-tagline` describing the app; and a `div.ftr-langs` mapping over 3 language objects (🇪🇸 Español, 🇫🇷 Français, 🇬🇧 English) into `span.ftr-lang-chip` elements. Render a `ftr-links-grid` with two `nav.ftr-group` elements: 'Navegar' (Home, Category, Phrases, Favorites) and 'Explorar' (Greetings, Food & Dining, Transportation, Accommodation), each rendered as `ul.ftr-link-list` with `a.ftr-link` anchors. Below `ftr-inner`, render a `div.ftr-divider` and a `div.ftr-bottom` with a copyright `p` using `new Date().getFullYear()` and a 'Feito com ♥' tagline span. Apply styles from `Footer.css`.
As a frontend developer, implement the CategoryHero section for the Category page. Build the `ch-root` section with a decorative background layer (`ch-decor`) containing three orb divs (`ch-decor__orb--top`, `ch-decor__orb--bottom`, `ch-decor__orb--mid`) and four animated emoji shapes (🛒, 📚, 🏠, ✈️) rendered via `decorativeShapes` array using `motion.span` with `decorVariant` (spring stiffness 60, damping 12) and `whileInView` viewport triggers. Implement the `ch-content` motion.div with `containerVariants` (staggerChildren 0.16, delayChildren 0.1) orchestrating staggered `fadeUpVariant` (spring y: 28→0, stiffness 100, damping 18) animations for the `ch-badge` span ('🌐 Explore por Tema'), `ch-headline` h1 with highlighted `ch-headline__highlight` span, `ch-subheadline` paragraph, and `ch-divider` div. All motion elements use `whileInView` with `viewport={{ once: true, margin: '-40px' }}`. Import `CategoryHero.css` for styling. Note: Navbar component may already exist from the Home page.
As a frontend developer, implement the CategoryFilter section for the Category page. Build a language filter toggle bar using `useState('espanhol')` for selected language and `useRef` for the bar DOM reference. Implement the animated sliding pill using `motion.div` with `cf-pill` class, animating `left` and `width` properties via spring (stiffness 380, damping 28, mass 0.8) derived from `pillStyle` state. Implement `updatePill()` that uses `getBoundingClientRect()` on the bar and each `.cf-toggle` button to compute pixel-accurate pill position, called via `schedulePillUpdate()` which debounces into `requestAnimationFrame`. Wire a `ResizeObserver` (with `window.resize` fallback) on `barRef.current` inside `useEffect([selected])` to recompute pill on layout shifts and font loads. Render three toggle buttons from the `LANGUAGES` array (`espanhol`, `frances`, `ingles`) each with flag emoji, name, and subtitle. Use `AnimatePresence` for any animated presence transitions. Display current language info derived from `LANGUAGES.find()`. Import `CategoryFilter.css`.
As a frontend developer, implement the CategoryGrid section for the Category page. Build the `cg-section` with a `cg-container` holding a `cg-header` (label span 'Categorias', h2 title, subtitle paragraph) and an animated `motion.ul` with class `cg-grid` using `containerVariants` (staggerChildren 0.08) and `whileInView` viewport trigger (`once: true, margin: '-60px'`). Render 9 category cards from the `categories` array (Comércio 🛒, Educação 📚, Espaços Públicos 🏛️, Casa 🏠, Transporte 🚌, Saudações 👋, Alimentação 🍽️, Hospedagem 🏨, Cuidados Pessoais 💆) as `motion.li` elements with `cg-card-wrapper` class using `cardVariants` (hidden: opacity 0, y 24, scale 0.96 → spring stiffness 260, damping 24). Each card is an anchor tag (`href='/Phrases'`) with class `cg-card` containing a `cg-card__badge` emoji span and a `cg-card__body` div with `cg-card__name` h3 and `cg-card__desc` paragraph. Import `CategoryGrid.css`.
As a frontend developer, implement the CategoryCallToAction section for the Category page. Build a Three.js canvas background mounted via `useRef(mountRef)` inside a `useEffect`. Initialize a `THREE.Scene` with a `PerspectiveCamera` (FOV 45, z=12) and a `THREE.WebGLRenderer` (alpha: true, antialias: true) appended to `mountRef.current`. Spawn 12 `THREE.SphereGeometry` meshes (size 0.12–0.47) with `THREE.MeshBasicMaterial` using colors `['#FF5733','#3366FF','#33FF57','#FFD700','#FF8F66']` and opacity 0.55–0.90, positioned randomly across x: ±7, y: ±3.5, z: -3 to -8. Attach `userData` (baseX, baseY, speedX, speedY, amplitude) to each sphere for sinusoidal floating animation in the `animate` loop (time-driven `Math.sin`/`Math.cos` + rotation increments 0.003/0.005). Add `THREE.AmbientLight` (intensity 0.6). Implement resize handler updating renderer size and camera aspect. Perform full cleanup in effect teardown: `cancelAnimationFrame`, `removeChild`, `renderer.dispose()`, and `geometry/material.dispose()` for each sphere. Wrap CTA content in `motion` components for entrance animations. Import `CategoryCallToAction.css`.
As a Backend Developer, implement the FastAPI endpoints for phrases and translations. Create the following routes: GET /api/phrases - list phrases with optional filters (category, language, difficulty, search, sort); GET /api/phrases/{id} - get a single phrase with all translations; GET /api/categories - list all 9 categories (Comércio, Educação, Espaços Públicos, Casa, Transporte, Saudações, Alimentação, Hospedagem, Cuidados Pessoais); POST /api/phrases - create a phrase (admin); PUT /api/phrases/{id} - update a phrase (admin). Each phrase document must contain: portuguese text, translations array (lang, flag, text for espanhol/frances/ingles), category, difficulty (easy/medium/hard), context description, and popularity count. Implement pagination and text search. Note: frontend tasks PhrasesGrid (7f51f2b6), FilterBar (49090ac7), PhrasesHeader (0773668f), and PracticeBanner (a9d40103) depend on this API.
As a Frontend Developer, create a centralized API client layer for the DESTRAVE React application. Set up an axios or fetch-based API client configured with the base URL from environment variables (REACT_APP_API_URL). Implement the following service modules: phrasesService (getPhrases, getPhraseById, getCategories), favoritesService (getFavorites, addFavorite, removeFavorite). Add request/response interceptors for error handling. Implement a simple caching layer using localStorage for offline support per the SRD requirement. Export typed service functions for use in all page components. This is a prerequisite for all frontend sections that fetch live data from the backend APIs.
As a frontend developer, implement the PhrasesHeader section for the Phrases page. This section renders a breadcrumb nav (🌍 Destrave › Categorias › Comércio) and a header row containing a 🛒 emoji, an h1 title with a .phh-title__accent span, and an interactive language selector dropdown. State: useState for selectedLanguage (default 'espanhol') and dropdownOpen. The dropdown renders a listbox with three language options (Espanhol 🇪🇸, Francês 🇫🇷, Inglês 🇬🇧) each showing flag, name, and subtitle (e.g. 'Português → Espanhol'). The chevron icon toggles the .phh-lang__chevron--open class when open. handleSelect sets the language and closes the dropdown. Below the header row, a category description paragraph is rendered. Import PhrasesHeader.css. Note: Navbar component may already exist from the Home page task.
As a Backend Developer, implement the FastAPI endpoints for managing user favorites. Create the following routes: GET /api/favorites - list all favorites for the current session/user with optional filters (language, category, sort); POST /api/favorites - add a phrase to favorites (body: phrase_id); DELETE /api/favorites/{id} - remove a phrase from favorites; GET /api/favorites/count - get total favorites count. Each favorite document contains: phrase_id reference, saved_at timestamp, and user session identifier. Since auth is already done, integrate with the existing authentication middleware. Note: frontend tasks FavoritesList (68046575), FavoritesFilters (7d8ec1cb), and FavoritesEmpty (a4ad320f) depend on this API.
As a Backend Developer, implement the FastAPI endpoint to support offline access as specified in Non-Functional Requirements. Create: GET /api/phrases/export?category={slug}&lang={lang} - returns a full JSON bundle of phrases for a given category and language pair, suitable for client-side caching via Service Worker or localStorage. The response payload should include all phrase fields needed for offline display. Optionally add an ETag/Last-Modified header for cache validation. Note: frontend offline caching integration will depend on this endpoint.
As a Tech Lead, verify the end-to-end integration between the Phrases page frontend implementation and the Phrases backend API. Ensure PhrasesGrid (7f51f2b6), FilterBar (49090ac7), and PhrasesHeader (0773668f) correctly fetch and display data from GET /api/phrases with working filters (category, language, difficulty, search, sort). Verify favorite toggling in PhrasesGrid persists via POST/DELETE /api/favorites. Confirm API responses are handled properly in the UI, loading states are shown, and error states are handled gracefully. Validate that the language selector in PhrasesHeader filters translations correctly.
As a Tech Lead, verify the end-to-end integration between the Category page frontend and the Categories backend API. Ensure CategoryGrid (ba911898) fetches and renders categories from GET /api/categories. Confirm CategoryFilter (1805692d) language selection is correctly passed as a query parameter when navigating to the Phrases page. Validate that each category card links to /Phrases with the correct category slug and language pre-selected. Ensure data flows correctly and error/loading states are handled gracefully.
As a frontend developer, implement the FilterBar section for the Phrases page. This section provides phrase filtering controls with the following state: useState for searchTerm, activeDifficulty (null by default), sortBy ('popular'), sortOpen, and mobileOpen. A useRef (sortRef) enables click-outside detection via a useEffect mousedown listener that closes the sort dropdown. The search input (.flb-search__input) includes a magnifier SVG icon and a conditional clear button (×) when searchTerm is non-empty. A divider separates the search from a mobile toggle button with an animated chevron SVG (.flb-toggle__icon--open class when open). Difficulty filter buttons render DIFFICULTY_OPTIONS (Fácil #33FF57, Médio #FFD700, Difícil #FF5733) with colored dot indicators and toggle active state. A sort dropdown renders SORT_OPTIONS (Mais Populares, Adicionados Recentemente, Ordem Alfabética). An activeFilterCount badge shows the count of active filters (activeDifficulty + searchTerm). handleClearAll resets all state. Import FilterBar.css.
As a frontend developer, implement the PhrasesGrid section for the Phrases page. This section renders an animated grid of phrase cards using framer-motion AnimatePresence and motion components, with lucide-react icons (Star, Volume2, ChevronDown, Search). State: useState for expanded card tracking and favorites via useCallback and useRef. Each phrase card in phraseData contains: id, portuguese text, translation, difficulty (easy/medium/hard), category, context description, and a languages array with lang name, flag emoji, and translated text for Espanhol 🇪🇸, Francês 🇫🇷, and Inglês 🇬🇧. Cards display the Portuguese phrase, difficulty badge, Star (favorite) button, Volume2 (audio) button, and a ChevronDown expand toggle that reveals the multi-language translations panel and context text via AnimatePresence. Sample data includes 5+ phrases across categories: greetings, commerce, transportation, accommodation. Import PhrasesGrid.css and framer-motion.
As a frontend developer, implement the PracticeBanner section for the Phrases page. This section uses framer-motion useInView (sectionRef with once:true, margin:'-80px') to trigger entrance animations. containerVariants uses staggerChildren: 0.12 and delayChildren: 0.1; itemVariants animate opacity 0→1 and y 24→0 with duration 0.55 and cubic-bezier easing [0.25, 0.46, 0.45, 0.94]. Renders: an animated icon row (.pb-icon-row) with three staggered emoji spans (🌟, 📖, 🌍) using .pb-sparkle class; an h2 title with .pb-title__highlight span ('frases favoritas'); an encouragement paragraph with bold text ('Revise, pronuncie e salve'); an animated stats row (.pb-stats) mapping the stats array (3 Idiomas, 10+ Categorias, 500+ Frases) as .pb-stat divs with .pb-stat__number and .pb-stat__label spans; and a CTA anchor (.pb-cta) linking to /Phrases labeled 'Iniciar Sessão de Prática'. Import PracticeBanner.css and framer-motion.
As a frontend developer, implement the FavoritesHero section for the Favorites page. This section renders a full-width hero (`.fh-root`) with decorative dot elements (`.fh-dot--1`, `.fh-dot--2`, `.fh-dot--3`) and an accent ring (`.fh-accent-ring`). The content area (`.fh-content`) uses Framer Motion with two animation variants: `scaleIn` (opacity 0→1, scale 0.8→1, 0.5s easeOut) for the SVG star polygon icon (`.fh-decor-icon`), and `fadeUp` (opacity 0→1, y 24→0, 0.55s easeOut) with staggered `custom` delays (0, 0.1, 0.2, 0.3) applied to the badge (`.fh-badge` with text 'Seus Favoritos'), the h1 title with `.fh-title-accent` span, subtitle, and description paragraph. All motion elements use `whileInView` with `viewport={{ once: true, margin: '-50px' }}`. Import FavoritesHero.css. No state hooks required.
As a Tech Lead, verify the end-to-end integration between the Favorites page frontend implementation and the Favorites backend API. Ensure FavoritesList (68046575) correctly fetches saved favorites from GET /api/favorites, FavoritesFilters (7d8ec1cb) filters are applied as query parameters, and FavoritesEmpty (a4ad320f) is displayed when the API returns an empty list. Confirm that removing a favorite in FavoritesList calls DELETE /api/favorites/{id} and refreshes the list. Validate that filter state (language, category, sort) maps correctly to API query params and that pagination or infinite scroll works if implemented.
As a frontend developer, implement the FavoritesFilters section for the Favorites page. This section renders a filter bar (`.ff-root` > `.ff-inner` > `.ff-bar`) with three stateful filter groups managed by `useState`: `activeLanguage` (default 'espanhol'), `activeCategory` (default ''), and `activeSort` (default 'recent'). Language chips are rendered from a `languages` array (Espanhol 🇪🇸, Francês 🇫🇷, Inglês 🇬🇧) as buttons with `.ff-group__label`. Category selection uses a dropdown (`categoryRef`, `categoryOpen` state) from a `categories` array of 10 items (all, comercio, educacao, espacos-publicos, casa, transporte, saudacoes, alimentacao, hospedagem, cuidados-pessoais) with emoji icons. Sort selection uses a second dropdown (`sortRef`, `sortOpen` state) from `sortOptions` array (recent, az, most-used). A `useEffect` registers `mousedown` and `touchstart` listeners via `handleClickOutside` to close both dropdowns when clicking outside their refs. A `hasFilters` boolean drives visibility of active filter tags with individual `removeLanguageFilter`, `removeCategoryFilter`, `removeSortFilter` handlers, plus a `clearAllFilters` function resetting all three states to defaults. Import FavoritesFilters.css.
As a frontend developer, implement the FavoritesList section for the Favorites page. This section manages a `favorites` array in `useState` seeded with 5 mock items (ids: fav-1 through fav-5), each containing `phrase`, `translations` array (with `lang`, `flag`, `text`), `category` (emoji + name), and `savedAt` date. A second state `copiedId` tracks clipboard feedback. The `removeFavorite(id)` handler filters out items by id. The `copyToClipboard(text, id)` handler calls `navigator.clipboard.writeText`, sets `copiedId`, then clears it after 1800ms. Cards are animated using Framer Motion `motion.div` with `containerVariants` (staggerChildren 0.08, delayChildren 0.06) and `cardVariants` (opacity 0→1, y 24→0, 0.45s cubic-bezier easeOut). When `favorites.length === 0`, renders an inline empty state (`.fl-empty-inner`) with 📭 icon and message 'Nenhuma frase favorita encontrada com os filtros atuais.' rather than the separate FavoritesEmpty component. Import FavoritesList.css.
As a frontend developer, implement the FavoritesEmpty section for the Favorites page. This section renders a full empty-state screen (`.fe-root`, aria-label='Nenhum favorito salvo') displayed when the user has no saved favorites at all (distinct from the inline filter-empty state in FavoritesList). The `.fe-inner` wrapper uses Framer Motion with `containerVariants` (staggerChildren 0.15, delayChildren 0.1) and `itemVariants` (opacity 0→1, y 18→0, 0.5s easeOut), both triggered via `whileInView` with `viewport={{ once: true, margin: '-60px' }}`. Child elements animate sequentially: `.fe-icon-wrap` wrapping a ⭐ emoji span (`.fe-icon-emoji`, role='img', aria-hidden), an h2 `.fe-title` ('Você ainda não tem frases favoritas'), a paragraph `.fe-desc`, and a CTA anchor `.fe-cta` linking to `/Phrases` with text 'Começar a Adicionar Frases' and a `.fe-cta-arrow` span (→). No state hooks required. Import FavoritesEmpty.css.
No comments yet. Be the first!