--- title: "Customization" description: "How to customize and extend the portfolio website" --- # Customization Guide Learn how to customize colors, fonts, components, and add new features. ## Theme Customization ### Colors Edit `tailwind.config.js` to change the color scheme: ```javascript // tailwind.config.js export default { theme: { extend: { colors: { primary: { DEFAULT: '#1E8479', light: '#07C983', dark: '#105652', }, secondary: '#F59E0B', accent: '#8B5CF6', } } } }; ``` ### Using Custom Colors ```jsx // In components
Content
``` ### CSS Variables For dynamic theming, use CSS variables in `src/index.css`: ```css :root { --color-primary: #1E8479; --color-primary-light: #07C983; --color-primary-dark: #105652; --color-background: #ffffff; --color-text: #1f2937; } /* Dark mode */ .dark { --color-background: #1f2937; --color-text: #f9fafb; } ``` ## Adding New Pages ### Public Page Create `src/pages/NewPage.jsx`: ```jsx export default function NewPage() { return (

New Page

{/* Your content */}
); } ```
In `src/App.jsx`: ```jsx import NewPage from './pages/NewPage'; // In Routes } /> ``` Update menu settings in admin or edit `Header.jsx`
### Admin Page Create `src/pages/Admin/NewFeature/NewFeature.jsx`: ```jsx export default function NewFeature() { return (

New Feature

{/* Admin content */}
); } ```
In `src/App.jsx` under admin routes: ```jsx } /> ``` Edit `src/pages/Admin/AdminLayout.jsx` to add menu item
## Adding New Collections ### 1. Create in Appwrite 1. Go to Appwrite Console → Databases → portfolio_db 2. Create new collection with attributes 3. Set permissions ### 2. Create Service ```javascript // src/lib/newFeatureService.js import { databases, ID, Query } from './appwrite'; const DATABASE_ID = import.meta.env.VITE_APPWRITE_DATABASE_ID; const COLLECTION_ID = 'new_collection'; export const newFeatureService = { async list() { return await databases.listDocuments(DATABASE_ID, COLLECTION_ID); }, async get(id) { return await databases.getDocument(DATABASE_ID, COLLECTION_ID, id); }, async create(data) { return await databases.createDocument( DATABASE_ID, COLLECTION_ID, ID.unique(), data ); }, async update(id, data) { return await databases.updateDocument( DATABASE_ID, COLLECTION_ID, id, data ); }, async delete(id) { return await databases.deleteDocument(DATABASE_ID, COLLECTION_ID, id); } }; ``` ### 3. Create Admin UI Use existing admin pages as templates. Key patterns: ```jsx // List view with CRUD const [items, setItems] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { loadItems(); }, []); async function loadItems() { setLoading(true); const result = await newFeatureService.list(); setItems(result.documents); setLoading(false); } async function handleDelete(id) { if (confirm('Delete this item?')) { await newFeatureService.delete(id); loadItems(); } } ``` ## Adding Font Selector to New Pages ```jsx import FontSelector from '../../../components/FontSelector/FontSelector'; const [titleFont, setTitleFont] = useState("'Open Sans', sans-serif"); // In your form ``` ## Customizing Rich Text Editor ### Add New Toolbar Button Edit `src/components/RichTextEditor/RichTextEditor.jsx`: ```jsx // Add to toolbar // Handler function const handleCustomAction = () => { document.execCommand('customCommand', false, 'value'); // Or manipulate selection directly }; ``` ### Add New Embed Type ```jsx // In embed handler const supportedEmbeds = { youtube: /youtube\.com|youtu\.be/, vimeo: /vimeo\.com/, // Add new type spotify: /spotify\.com/, }; ``` ## Custom Components ### Reusable Card Component ```jsx // src/components/Card/Card.jsx export default function Card({ title, description, image, onClick, className = '' }) { return (
{image && ( {title} )}

{title}

{description}

); } ``` ### Loading Spinner ```jsx // src/components/Spinner/Spinner.jsx export default function Spinner({ size = 'md' }) { const sizes = { sm: 'w-4 h-4', md: 'w-8 h-8', lg: 'w-12 h-12' }; return (
); } ``` ## Environment-Specific Config ```javascript // src/config.js const config = { development: { apiUrl: 'http://localhost:5173', debug: true, }, production: { apiUrl: 'https://yourdomain.com', debug: false, } }; export default config[import.meta.env.MODE] || config.development; ``` ## Adding Analytics ### Google Analytics ```html ``` ### Track Page Views ```jsx // src/App.jsx import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; function App() { const location = useLocation(); useEffect(() => { // Track page view if (window.gtag) { window.gtag('event', 'page_view', { page_path: location.pathname, }); } }, [location]); // ... } ``` ## Best Practices Keep components small and focused. If a component exceeds 200 lines, consider splitting it. Use TypeScript for better type safety and IDE support in larger projects. Create a `constants.js` file for magic strings and configuration values. Never hardcode API keys or secrets. Always use environment variables. Test thoroughly after customizations, especially database schema changes.