Nano Banana Pro
Agent skill for nano-banana-pro
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Sign in to like and favorite skills
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Farmfolio is a React SPA that connects food producers with conscious consumers through digital storytelling and a marketplace discovery platform. Producers create story-based profiles using customizable templates, which can be shared via QR codes at physical locations.
npm run dev # Start Vite dev server (port 3000, auto-opens) npm run build # Build for production (outputs to dist/ with sourcemaps) npm run preview # Preview production build locally npm run lint # Run ESLint
useAuth() hook (src/hooks/useAuth.js)src/api/ (authApi, storiesApi, producerProfilesApi, etc.)Authorization: Bearer <token>STORAGE_KEYS constant{ token, user } or { data: { token, user } }PrivateRoute wrapper componentFarmfolio uses a template-driven approach for creating producer profiles and stories:
Story Templates: Predefined layouts for farm stories, artisan products, sustainability narratives
Producer Profile Templates: Similar system for producer marketplace profiles
Inline Editing: Recent feature allowing direct template editing
Admin Upload: src/pages/SimpleAdminPage.jsx provides interface to upload new templates
Routes defined in src/utils/constants.js under
ROUTES:
/marketplace, /producer/:id, /story/:id (story viewer)/login, /register (redirect if authenticated)/dashboard, /story/create, /story/edit/:id, /profile/edit, /admin/ redirects to dashboard (auth) or login (guest)Create small service modules in
src/api/ that export functions using the shared axios instance:
// Example from authApi.js import axiosInstance from './axiosConfig'; export const login = async (credentials) => { const response = await axiosInstance.post(API_ENDPOINTS.LOGIN, credentials); return response.data; };
Service calls return
response.data. Callers should handle multiple possible response shapes (see AuthContext for defensive patterns).
Use the
createFormData helper from src/api/axiosConfig.js:
CategoryIds) and filesContent-Type header for FormData requestsconst formData = createFormData(data, filesArray);ROUTES in src/utils/constants.jsAPI_ENDPOINTS if backend route needed<PrivateRoute> if authentication required{ message, errors?, originalError }ERROR_MESSAGES constantreact-hot-toast (configured in src/main.jsx)REACT_APP_ prefix (configured in vite.config.js)import.meta.env.REACT_APP_*REACT_APP_API_BASE_URL, REACT_APP_GOOGLE_MAPS_API_KEY, feature flagsfarmfolio-green, farmfolio-darkgreen, farmfolio-cream, farmfolio-brownanimate-fade-in, animate-slide-up, animate-pulse-soft@tailwindcss/forms plugin@tailwindcss/typography pluginBackend may return
{ token, user }, { data: { token, user } }, or just { token }. Always handle multiple shapes or decode JWT as fallback (see src/context/AuthContext.jsx lines 56-110).
When uploading files:
createFormData helper for correct array/file handlingContent-Type — axios interceptor removes itmultipart/form-dataAxios interceptor auto-redirects to
/login on 401 and clears localStorage. Avoid retry loops by checking _retry flag (already implemented in src/api/axiosConfig.js).
useAuth() throws error if used outside AuthProvider. Always ensure component is wrapped by provider tree (configured in src/main.jsx).
Vite only exposes vars with
REACT_APP_ prefix. Check vite.config.js envPrefix setting.
.env as REACT_APP_GOOGLE_MAPS_API_KEY@react-google-maps/api library with marker clusteringMAPS_CONFIG constantdist/ with sourcemaps enabled@ is aliased to ./src in vite.config.js. Use import { foo } from '@/utils/bar' instead of relative paths.
No test runner configured yet. When adding tests: