diff --git a/developer/api-reference.mdx b/developer/api-reference.mdx new file mode 100644 index 0000000..c663ed4 --- /dev/null +++ b/developer/api-reference.mdx @@ -0,0 +1,380 @@ +--- +title: "API Reference" +description: "Service functions and Appwrite API usage" +--- + +# API Reference + +Reference for service functions and Appwrite operations. + +## Appwrite Client Setup + +```javascript +import { Client, Databases, Storage, Account, ID, Query } from 'appwrite'; + +const client = new Client() + .setEndpoint(import.meta.env.VITE_APPWRITE_ENDPOINT) + .setProject(import.meta.env.VITE_APPWRITE_PROJECT_ID); + +export const databases = new Databases(client); +export const storage = new Storage(client); +export const account = new Account(client); +export { ID, Query }; +``` + +## Database Operations + +### List Documents + +```javascript +import { databases, Query } from './appwrite'; + +// Basic list +const blogs = await databases.listDocuments( + 'portfolio_db', + 'blogs' +); + +// With queries +const featuredBlogs = await databases.listDocuments( + 'portfolio_db', + 'blogs', + [ + Query.equal('featured', true), + Query.orderDesc('publishDate'), + Query.limit(10) + ] +); +``` + +### Get Single Document + +```javascript +const blog = await databases.getDocument( + 'portfolio_db', + 'blogs', + 'document_id' +); +``` + +### Create Document + +```javascript +import { ID } from 'appwrite'; + +const newBlog = await databases.createDocument( + 'portfolio_db', + 'blogs', + ID.unique(), // Auto-generate ID + { + title: 'My Blog Post', + category: 'Technology', + description: 'A great post...', + // ... other fields + } +); +``` + +### Update Document + +```javascript +const updated = await databases.updateDocument( + 'portfolio_db', + 'blogs', + 'document_id', + { + title: 'Updated Title', + // Only include fields to update + } +); +``` + +### Delete Document + +```javascript +await databases.deleteDocument( + 'portfolio_db', + 'blogs', + 'document_id' +); +``` + +## Query Methods + +| Method | Description | Example | +|--------|-------------|---------| +| `Query.equal(attr, value)` | Exact match | `Query.equal('category', 'Tech')` | +| `Query.notEqual(attr, value)` | Not equal | `Query.notEqual('status', 'draft')` | +| `Query.lessThan(attr, value)` | Less than | `Query.lessThan('price', 100)` | +| `Query.greaterThan(attr, value)` | Greater than | `Query.greaterThan('likes', 10)` | +| `Query.search(attr, value)` | Full-text search | `Query.search('title', 'react')` | +| `Query.orderAsc(attr)` | Sort ascending | `Query.orderAsc('createdAt')` | +| `Query.orderDesc(attr)` | Sort descending | `Query.orderDesc('publishDate')` | +| `Query.limit(n)` | Limit results | `Query.limit(10)` | +| `Query.offset(n)` | Skip results | `Query.offset(20)` | +| `Query.contains(attr, value)` | Array contains | `Query.contains('tags', 'react')` | + +### Complex Queries + +```javascript +// Pagination +const page2 = await databases.listDocuments( + 'portfolio_db', + 'blogs', + [ + Query.orderDesc('publishDate'), + Query.limit(10), + Query.offset(10) // Skip first 10 + ] +); + +// Multiple conditions +const filtered = await databases.listDocuments( + 'portfolio_db', + 'products', + [ + Query.equal('category', 'Electronics'), + Query.equal('onSale', true), + Query.lessThan('price', 500), + Query.orderAsc('price') + ] +); +``` + +## Storage Operations + +### Upload File + +```javascript +import { storage, ID } from './appwrite'; + +const file = await storage.createFile( + 'blog_images', // Bucket ID + ID.unique(), // File ID + document.getElementById('fileInput').files[0] +); + +// Get file URL +const fileUrl = storage.getFileView('blog_images', file.$id); +``` + +### Get File URL + +```javascript +// View URL (for images) +const viewUrl = storage.getFileView('bucket_id', 'file_id'); + +// Download URL +const downloadUrl = storage.getFileDownload('bucket_id', 'file_id'); + +// Preview URL (with transformations) +const previewUrl = storage.getFilePreview( + 'bucket_id', + 'file_id', + 400, // width + 300, // height + 'center', // gravity + 90 // quality +); +``` + +### Delete File + +```javascript +await storage.deleteFile('bucket_id', 'file_id'); +``` + +## Authentication + +### Login + +```javascript +import { account } from './appwrite'; + +const session = await account.createEmailPasswordSession( + 'user@example.com', + 'password' +); +``` + +### Get Current User + +```javascript +try { + const user = await account.get(); + console.log('Logged in as:', user.email); +} catch (error) { + console.log('Not logged in'); +} +``` + +### Logout + +```javascript +await account.deleteSession('current'); +``` + +### Create Account + +```javascript +const user = await account.create( + ID.unique(), + 'user@example.com', + 'password', + 'User Name' // Optional +); +``` + +## Service Examples + +### Blog Service + +```javascript +// src/lib/blogService.js +export const blogService = { + async listAll() { + return await databases.listDocuments( + DATABASE_ID, + 'blogs', + [Query.orderDesc('publishDate')] + ); + }, + + async listFeatured() { + return await databases.listDocuments( + DATABASE_ID, + 'blogs', + [ + Query.equal('featured', true), + Query.orderDesc('publishDate'), + Query.limit(6) + ] + ); + }, + + async getBySlug(slug) { + const result = await databases.listDocuments( + DATABASE_ID, + 'blogs', + [Query.equal('customSlug', slug)] + ); + return result.documents[0] || null; + }, + + async listByCategory(category) { + return await databases.listDocuments( + DATABASE_ID, + 'blogs', + [ + Query.equal('category', category), + Query.orderDesc('publishDate') + ] + ); + } +}; +``` + +### Shortlink Service + +```javascript +// src/lib/shortlinkService.js +export const shortlinkService = { + async getByPath(path) { + const result = await databases.listDocuments( + DATABASE_ID, + 'shortlinks', + [ + Query.equal('customPath', path.toLowerCase()), + Query.equal('isActive', true) + ] + ); + return result.documents[0] || null; + }, + + async incrementClicks(id, currentCount) { + return await databases.updateDocument( + DATABASE_ID, + 'shortlinks', + id, + { clickCount: currentCount + 1 } + ); + }, + + async recordAnalytics(shortlinkId, data) { + return await databases.createDocument( + DATABASE_ID, + 'shortlink_analytics', + ID.unique(), + { + shortlinkId, + timestamp: new Date().toISOString(), + ...data + } + ); + } +}; +``` + +### Image Upload Helper + +```javascript +// src/lib/imageService.js +export const imageService = { + async upload(bucketId, file) { + const uploaded = await storage.createFile( + bucketId, + ID.unique(), + file + ); + + const url = storage.getFileView(bucketId, uploaded.$id); + + return { + id: uploaded.$id, + url: url.href + }; + }, + + async delete(bucketId, fileId) { + await storage.deleteFile(bucketId, fileId); + }, + + getPreviewUrl(bucketId, fileId, width = 400, height = 300) { + return storage.getFilePreview( + bucketId, + fileId, + width, + height + ).href; + } +}; +``` + +## Error Handling + +```javascript +try { + const result = await databases.listDocuments(...); +} catch (error) { + if (error.code === 404) { + console.log('Collection not found'); + } else if (error.code === 401) { + console.log('Not authorized'); + } else if (error.code === 403) { + console.log('Permission denied'); + } else { + console.log('Error:', error.message); + } +} +``` + +## Common Error Codes + +| Code | Meaning | Solution | +|------|---------|----------| +| 401 | Unauthorized | Check authentication | +| 403 | Forbidden | Check permissions | +| 404 | Not Found | Check collection/document ID | +| 409 | Conflict | Duplicate unique value | +| 413 | Payload Too Large | Reduce file/data size | +| 429 | Rate Limited | Slow down requests | diff --git a/developer/architecture.mdx b/developer/architecture.mdx new file mode 100644 index 0000000..02eeb21 --- /dev/null +++ b/developer/architecture.mdx @@ -0,0 +1,310 @@ +--- +title: "Architecture" +description: "Technical architecture and project structure overview" +--- + +# Project Architecture + +Understanding the technical structure of the portfolio website. + +## Tech Stack + +| Layer | Technology | Purpose | +|-------|------------|---------| +| Frontend | React 18 | UI components and state management | +| Build Tool | Vite 5 | Fast development and optimized builds | +| Styling | Tailwind CSS 3 | Utility-first CSS framework | +| Backend | Appwrite | Database, storage, authentication | +| Icons | Lucide React | Consistent icon library | +| Deployment | Vercel | Hosting and CI/CD | + +## Project Structure + +``` +portfolio/ +├── public/ # Static assets +├── src/ +│ ├── components/ # Reusable UI components +│ │ ├── Header/ +│ │ ├── Footer/ +│ │ ├── FontSelector/ +│ │ ├── RichTextEditor/ +│ │ ├── PhotoGrid/ +│ │ └── ... +│ ├── pages/ +│ │ ├── Admin/ # Admin dashboard pages +│ │ │ ├── BlogManagement/ +│ │ │ ├── ProjectManagement/ +│ │ │ ├── ShortlinkManagement/ +│ │ │ ├── ShopManagement/ +│ │ │ └── Settings/ +│ │ ├── HomePage.jsx +│ │ ├── BlogPage.jsx +│ │ ├── ProjectPage.jsx +│ │ ├── ShopPage.jsx +│ │ └── ... +│ ├── lib/ # Services and utilities +│ │ ├── appwrite.js # Appwrite client config +│ │ ├── shortlinkService.js +│ │ ├── analyticsService.js +│ │ └── ... +│ ├── utils/ # Helper functions +│ │ ├── googleFonts.js +│ │ ├── fontLoader.js +│ │ └── ... +│ ├── context/ # React context providers +│ │ ├── AuthContext.jsx +│ │ ├── CartContext.jsx +│ │ └── ... +│ ├── App.jsx # Main app component +│ ├── main.jsx # Entry point +│ └── index.css # Global styles +├── docs/ # Documentation (separate repo) +├── .env # Environment variables +├── vite.config.js # Vite configuration +├── tailwind.config.js # Tailwind configuration +└── package.json +``` + +## Data Flow + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ Browser │────▶│ React │────▶│ Appwrite │ +│ (User) │◀────│ App │◀────│ Backend │ +└─────────────┘ └─────────────┘ └─────────────┘ + │ + ┌──────┴──────┐ + │ │ + ┌─────▼─────┐ ┌─────▼─────┐ + │ Components│ │ Context │ + │ (UI) │ │ (State) │ + └───────────┘ └───────────┘ +``` + +## Key Components + +### Appwrite Client (`src/lib/appwrite.js`) + +Central configuration for Appwrite SDK: + +```javascript +import { Client, Databases, Storage, Account } from 'appwrite'; + +const client = new Client() + .setEndpoint(import.meta.env.VITE_APPWRITE_ENDPOINT) + .setProject(import.meta.env.VITE_APPWRITE_PROJECT_ID); + +export const databases = new Databases(client); +export const storage = new Storage(client); +export const account = new Account(client); +``` + +### Database Service Pattern + +Each feature has a dedicated service file: + +```javascript +// src/lib/blogService.js +import { databases, ID, Query } from './appwrite'; + +const DATABASE_ID = import.meta.env.VITE_APPWRITE_DATABASE_ID; +const COLLECTION_ID = 'blogs'; + +export const blogService = { + async list(queries = []) { + return await databases.listDocuments( + DATABASE_ID, + COLLECTION_ID, + queries + ); + }, + + 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 + ); + } +}; +``` + +### Context Providers + +Global state management using React Context: + +```javascript +// src/context/AuthContext.jsx +import { createContext, useContext, useState, useEffect } from 'react'; +import { account } from '../lib/appwrite'; + +const AuthContext = createContext(); + +export function AuthProvider({ children }) { + const [user, setUser] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + checkUser(); + }, []); + + async function checkUser() { + try { + const session = await account.get(); + setUser(session); + } catch { + setUser(null); + } + setLoading(false); + } + + return ( + + {children} + + ); +} + +export const useAuth = () => useContext(AuthContext); +``` + +## Routing Structure + +```javascript +// src/App.jsx + + {/* Public Routes */} + } /> + } /> + } /> + } /> + } /> + } /> + + {/* Shortlink Redirect */} + } /> + + {/* Admin Routes (Protected) */} + }> + } /> + } /> + } /> + } /> + {/* ... more admin routes */} + + +``` + +## State Management + +| State Type | Solution | Use Case | +|------------|----------|----------| +| Server State | Direct Appwrite calls | Database operations | +| Auth State | AuthContext | User session | +| Cart State | CartContext + localStorage | Shopping cart | +| UI State | useState/useReducer | Component-level state | + +## Performance Optimizations + +### Code Splitting + +```javascript +// Lazy load admin pages +const BlogManagement = lazy(() => import('./pages/Admin/BlogManagement')); +const ProjectManagement = lazy(() => import('./pages/Admin/ProjectManagement')); +``` + +### Image Optimization + +- Lazy loading for images below the fold +- WebP format support +- Responsive image sizes + +### Font Loading + +```javascript +// Dynamic Google Font loading +const loadGoogleFont = (fontFamily) => { + const link = document.createElement('link'); + link.href = `https://fonts.googleapis.com/css2?family=${fontFamily}&display=swap`; + link.rel = 'stylesheet'; + document.head.appendChild(link); +}; +``` + +## Security Considerations + +| Concern | Solution | +|---------|----------| +| Authentication | Appwrite session management | +| Authorization | Collection-level permissions | +| XSS Prevention | DOMPurify for rich text | +| CORS | Appwrite platform configuration | +| Secrets | Environment variables (never in code) | + +## Build Configuration + +### Vite Config (`vite.config.js`) + +```javascript +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + rollupOptions: { + output: { + manualChunks: { + vendor: ['react', 'react-dom', 'react-router-dom'], + appwrite: ['appwrite'], + } + } + } + } +}); +``` + +### Tailwind Config (`tailwind.config.js`) + +```javascript +export default { + content: ['./index.html', './src/**/*.{js,jsx}'], + theme: { + extend: { + colors: { + primary: '#1E8479', + secondary: '#105652', + } + } + }, + plugins: [] +}; +``` diff --git a/developer/customization.mdx b/developer/customization.mdx new file mode 100644 index 0000000..df82f0a --- /dev/null +++ b/developer/customization.mdx @@ -0,0 +1,389 @@ +--- +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. + diff --git a/features/photo-grids.mdx b/features/photo-grids.mdx new file mode 100644 index 0000000..0097e1f --- /dev/null +++ b/features/photo-grids.mdx @@ -0,0 +1,240 @@ +--- +title: "Photo Grids" +description: "Create beautiful image layouts with 24 pre-designed templates" +--- + +# Photo Grids + +Insert stunning image galleries with professional layouts directly in your content. + +## Overview + +Photo grids allow you to display multiple images in visually appealing arrangements. Choose from 24 pre-designed layouts to showcase your work. + +## Inserting a Photo Grid + + + + Go to any content editor (Blog, Project, Product) + + + Click the **Grid** icon (Grid3x3) in the toolbar + + + Browse 24 layout options and click your preferred one + + + For each cell: + 1. Click the empty cell + 2. Choose **URL** or **Upload** + 3. Add your image + 4. Click **Add Image** + + + Click **Insert Grid** when all cells are filled + + + +## Available Layouts + +### Simple Grids (1-5) + +| Layout | Description | Images | +|--------|-------------|--------| +| 2 Columns | Side by side | 2 | +| 3 Columns | Three in a row | 3 | +| 4 Columns | Four in a row | 4 | +| 2×2 Grid | Square grid | 4 | +| 3×2 Grid | Two rows of three | 6 | + +**Best for:** Simple galleries, before/after comparisons, product showcases + +### Asymmetric Layouts (6-10) + +| Layout | Description | Images | +|--------|-------------|--------| +| Large Left + 2 Right | Featured image on left | 3 | +| Large Right + 2 Left | Featured image on right | 3 | +| 2 Top + 3 Bottom | Wide top, small bottom | 5 | +| 3 Top + 2 Bottom | Small top, wide bottom | 5 | +| Large Center + 4 Corners | Center focus | 5 | + +**Best for:** Highlighting a main image with supporting images + +### Creative Layouts (11-15) + +| Layout | Description | Images | +|--------|-------------|--------| +| Masonry 1 | Tall images on sides | 4-6 | +| Masonry 2 | Alternating heights | 4-6 | +| Featured + 3 | One large, three small | 4 | +| Split + 4 | Two large top, 4 small bottom | 6 | +| Showcase | Alternating sizes | 5 | + +**Best for:** Portfolio showcases, creative presentations + +### Gallery Layouts (16-20) + +| Layout | Description | Images | +|--------|-------------|--------| +| Gallery 1 | Tall left, wide right | 4 | +| Gallery 2 | Large square with small images | 5 | +| Portfolio 1 | Wide top, tall right | 4 | +| Portfolio 2 | Mixed sizes | 5 | +| Magazine | Editorial style | 5 | + +**Best for:** Professional portfolios, editorial content + +### Special Layouts (21-24) + +| Layout | Description | Images | +|--------|-------------|--------| +| Hero + Grid | Hero image with thumbnails | 5 | +| Spotlight | Wide feature with small images | 4 | +| Collage 1 | Artistic arrangement | 5 | +| Collage 2 | Creative mixed layout | 6 | + +**Best for:** Hero sections, artistic presentations + +## Editing Photo Grids + +### Change Images + +1. Hover over the grid in the editor +2. Click **Settings** icon (gear) +3. Click on the image you want to change +4. Upload or enter new image URL +5. Click **Update Grid** + +### Change Layout + +1. Click **Settings** on the grid +2. Click **Change Layout** +3. Select new layout +4. Rearrange images if needed +5. Click **Update Grid** + +### Delete Grid + +1. Hover over the grid +2. Click **Delete** icon (trash) +3. Confirm deletion + +## Image Recommendations + +### Optimal Sizes + +| Use Case | Recommended Size | +|----------|------------------| +| Thumbnail cells | 400×400px | +| Wide cells | 800×400px | +| Tall cells | 400×800px | +| Hero/Large cells | 1200×800px | + +### File Formats + +| Format | Best For | +|--------|----------| +| JPG | Photos, complex images | +| PNG | Graphics, transparency | +| WebP | Best compression (modern browsers) | + +### Tips for Best Results + + + Use images with similar color tones for a cohesive look. + + + + Keep file sizes under 500KB per image for faster loading. + + + + Use consistent aspect ratios within the same grid when possible. + + + + Very large images (>2MB) will slow down page loading. Compress before uploading. + + +## Use Cases + +### Portfolio Showcase + +Use **Gallery** or **Portfolio** layouts to display your best work with a featured piece. + +``` +┌─────────────────┬─────────┐ +│ │ 2 │ +│ 1 ├─────────┤ +│ (Featured) │ 3 │ +│ ├─────────┤ +│ │ 4 │ +└─────────────────┴─────────┘ +``` + +### Product Gallery + +Use **2×2 Grid** or **3 Columns** for product photos from different angles. + +``` +┌─────────┬─────────┬─────────┐ +│ 1 │ 2 │ 3 │ +└─────────┴─────────┴─────────┘ +``` + +### Before/After + +Use **2 Columns** for side-by-side comparisons. + +``` +┌─────────────┬─────────────┐ +│ Before │ After │ +└─────────────┴─────────────┘ +``` + +### Photo Essay + +Use **Magazine** or **Collage** layouts for storytelling. + +``` +┌─────────────────────────────┐ +│ Hero │ +├─────────┬─────────┬─────────┤ +│ 2 │ 3 │ 4 │ +└─────────┴─────────┴─────────┘ +``` + +## Responsive Behavior + +All photo grids are automatically responsive: + +| Screen Size | Behavior | +|-------------|----------| +| Desktop | Full grid layout | +| Tablet | Adjusted spacing, some stacking | +| Mobile | Stacked or simplified layout | + + + Complex layouts may simplify on mobile devices for better viewing experience. + + +## Troubleshooting + +### Grid Not Appearing + +1. Ensure you clicked **Insert Grid** after adding images +2. Check that all cells have images +3. Refresh the editor + +### Images Not Loading + +1. Verify image URLs are correct and accessible +2. Check file upload completed successfully +3. Ensure images are publicly accessible + +### Layout Looks Wrong + +1. Check image aspect ratios match the cell shapes +2. Try a different layout better suited to your images +3. Ensure all cells are filled diff --git a/introduction.mdx b/introduction.mdx index 20d76e7..5b380db 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -5,55 +5,121 @@ description: "A modern portfolio website built with React, Vite, Tailwind CSS, a # Portfolio Website -A comprehensive, feature-rich portfolio website with an admin dashboard for complete content management. +A comprehensive, feature-rich portfolio website with an admin dashboard for complete content management. Built for developers, designers, and creators who want full control over their online presence. + +## Why This Portfolio? + + + + Manage all content through an intuitive admin panel + + + Change fonts, colors, and layouts without touching code + + + Optimized for performance, SEO, and accessibility + + ## Tech Stack -| Technology | Purpose | -|------------|---------| -| React 18 | Frontend framework | -| Vite 5 | Build tool & dev server | -| Tailwind CSS 3 | Styling | -| Appwrite | Backend, database & storage | -| Lucide React | Icons | +| Technology | Purpose | Why Chosen | +|------------|---------|------------| +| React 18 | Frontend framework | Component-based, large ecosystem | +| Vite 5 | Build tool & dev server | Lightning fast HMR, optimized builds | +| Tailwind CSS 3 | Styling | Utility-first, highly customizable | +| Appwrite | Backend, database & storage | Open-source, self-hostable, generous free tier | +| Lucide React | Icons | Consistent, lightweight, 1000+ icons | ## Key Features - - Full-featured blog with categories, multiple authors, and rich text editing + + Full-featured blog with categories, multiple authors, rich text editing, and SEO-friendly URLs - - Showcase projects with custom URLs, galleries, and detailed descriptions + + Showcase projects with custom URLs, image galleries, and detailed descriptions - - URL shortener with analytics, custom domains, and preview images + + URL shortener with click analytics, geographic tracking, and custom domain support - - E-commerce with PayPal integration, order tracking, and secure file delivery + + E-commerce with PayPal integration, order tracking, coupons, and secure file delivery - - 70+ Google Fonts plus custom font uploads with Bangla support + + 70+ Google Fonts plus custom font uploads with full Bangla language support - - Advanced editor with embeds, photo grids, tables, and full formatting + + Advanced editor with embeds, photo grids, tables, and complete formatting options +## What's Included + +### Public Pages +- **Homepage** - Hero section, featured content, about preview +- **Blog** - List view, single post, category filtering +- **Projects** - Gallery view, detailed project pages +- **Shop** - Product catalog, cart, checkout +- **Contact** - Contact form with validation + +### Admin Dashboard +- **Content Management** - Header, about, experience, FAQ +- **Blog Management** - Posts, categories, authors +- **Project Management** - Projects, categories, galleries +- **Shop Management** - Products, orders, coupons +- **Shortlinks** - URL shortener, analytics, custom domains +- **Settings** - Fonts, menu, social links + ## Project Structure ``` -src/ -├── components/ # Reusable UI components -├── pages/ -│ ├── Admin/ # Admin dashboard pages -│ └── ... # Public pages -├── lib/ # Appwrite services & utilities -└── utils/ # Helper functions +portfolio/ +├── src/ +│ ├── components/ # Reusable UI components +│ │ ├── Header/ +│ │ ├── Footer/ +│ │ ├── RichTextEditor/ +│ │ └── ... +│ ├── pages/ +│ │ ├── Admin/ # Admin dashboard (protected) +│ │ ├── HomePage.jsx +│ │ ├── BlogPage.jsx +│ │ └── ... +│ ├── lib/ # Appwrite services +│ ├── utils/ # Helper functions +│ └── context/ # React context providers +├── public/ # Static assets +├── docs/ # Documentation +└── .env # Environment variables ``` ## Quick Links -- [Quick Start Guide](/quick-start) - Get up and running in 10 minutes -- [Appwrite Setup](/appwrite/overview) - Configure your backend -- [Deployment Guide](/deployment) - Deploy to Vercel + + + Get up and running in 10 minutes + + + Configure your backend services + + + Deploy to Vercel or other platforms + + + Common issues and solutions + + + +## Requirements + +Before you begin, ensure you have: + +- **Node.js 18+** - [Download](https://nodejs.org/) +- **npm or yarn** - Comes with Node.js +- **Appwrite Account** - [Sign up free](https://cloud.appwrite.io) +- **Git** - [Download](https://git-scm.com/) + + + Appwrite Cloud offers a generous free tier that's sufficient for most portfolio sites. You can also self-host Appwrite if preferred. + diff --git a/mint.json b/mint.json index 6d2ae1c..5908ad7 100644 --- a/mint.json +++ b/mint.json @@ -29,7 +29,7 @@ "navigation": [ { "group": "Getting Started", - "pages": ["introduction", "quick-start", "deployment"] + "pages": ["introduction", "quick-start", "deployment", "troubleshooting"] }, { "group": "Appwrite Setup", @@ -48,7 +48,8 @@ "features/shortlink-system", "features/shop-system", "features/font-management", - "features/rich-text-editor" + "features/rich-text-editor", + "features/photo-grids" ] }, { @@ -58,6 +59,14 @@ "admin/content-management", "admin/settings" ] + }, + { + "group": "Developer Guide", + "pages": [ + "developer/architecture", + "developer/api-reference", + "developer/customization" + ] } ], "footerSocials": { diff --git a/quick-start.mdx b/quick-start.mdx index ba87dad..8555b79 100644 --- a/quick-start.mdx +++ b/quick-start.mdx @@ -5,35 +5,72 @@ description: "Get your portfolio website running in 10 minutes" # Quick Start Guide +Get your portfolio website up and running quickly with this step-by-step guide. + ## Prerequisites -- Node.js 18+ installed -- Appwrite account ([cloud.appwrite.io](https://cloud.appwrite.io)) -- Git installed +Before starting, make sure you have: + +| Requirement | Version | Check Command | +|-------------|---------|---------------| +| Node.js | 18+ | `node --version` | +| npm | 9+ | `npm --version` | +| Git | Any | `git --version` | + +You'll also need an [Appwrite Cloud](https://cloud.appwrite.io) account (free). ## Installation - + ```bash git clone cd portfolio + ``` + + + + ```bash npm install ``` + + This installs all required packages including React, Vite, Tailwind, and Appwrite SDK. + + + + 1. Go to [cloud.appwrite.io](https://cloud.appwrite.io) + 2. Click **Create Project** + 3. Name it (e.g., "Portfolio") + 4. Copy your **Project ID** Create a `.env` file in the root directory: ```env + # Appwrite Configuration VITE_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1 - VITE_APPWRITE_PROJECT_ID=your_project_id + VITE_APPWRITE_PROJECT_ID=your_project_id_here VITE_APPWRITE_DATABASE_ID=portfolio_db VITE_APPWRITE_STORAGE_ID=reactbucket + + # Optional: PayPal (for shop) + VITE_PAYPAL_CLIENT_ID=your_paypal_client_id ``` + + Never commit `.env` to version control. It's already in `.gitignore`. + + + + + 1. In Appwrite Console, go to **Settings** → **Platforms** + 2. Click **Add Platform** → **Web** + 3. Enter hostname: `localhost` + 4. Click **Create** + - Get these values from your Appwrite Console after creating a project. + This allows your local development server to communicate with Appwrite. @@ -43,47 +80,133 @@ description: "Get your portfolio website running in 10 minutes" ``` Open [http://localhost:5173](http://localhost:5173) in your browser. + + You should see the portfolio homepage (with placeholder content until you set up the database). -## First-Time Setup +## Database Setup -### 1. Create Admin Account +Your site needs database collections to store content. You have two options: -1. Go to `/admin` in your browser -2. Sign up with your email -3. Verify your email in Appwrite Console +### Option A: Quick Setup (Recommended for Testing) -### 2. Set Up Database +Create the minimum required collections: -Follow the [Appwrite Setup Guide](/appwrite/overview) to create: -- Required collections (blogs, projects, products, etc.) -- Storage buckets for images -- Proper permissions +1. Go to Appwrite Console → **Databases** +2. Click **Create Database** → ID: `portfolio_db` +3. Create these collections with basic attributes: -### 3. Add Your First Content +| Collection | Required Attributes | +|------------|---------------------| +| `header_section` | `name` (string), `roles` (string[]), `description` (string) | +| `menubar_settings` | `showBlog` (boolean), `showProjects` (boolean) | -| Section | Admin URL | What to Add | -|---------|-----------|-------------| -| Header | `/admin/header` | Name, roles, description | -| About | `/admin/about` | Bio, skills, experience | -| Projects | `/admin/projects` | Portfolio projects | -| Blog | `/admin/blogs` | Blog posts | +See [Database Setup](/appwrite/database-setup) for complete schema. + +### Option B: Full Setup + +Follow the complete [Appwrite Setup Guide](/appwrite/overview) to create all collections and storage buckets. + +## First-Time Admin Setup + + + + Go to [http://localhost:5173/admin](http://localhost:5173/admin) + + + + Click **Sign Up** and create an account with your email. + + + + If email verification is enabled in Appwrite, check your inbox and verify. + + + + Start adding your content: + + | Section | What to Add | + |---------|-------------| + | Header | Your name, job titles, intro | + | About | Bio, skills, profile image | + | Projects | Your portfolio work | + | Blog | Articles and posts | + + + +## Quick Content Checklist + +After setup, add content in this order: + + + + `/admin/header` - Your name, rotating roles, description + + + `/admin/about` - Bio, skills, profile image + + + `/admin/project-categories` - Create 2-3 categories + + + `/admin/projects` - Add your best project + + + `/admin/blog-categories` - Create a category + + + `/admin/blogs` - Write your first post + + ## Build for Production ```bash +# Build optimized production bundle npm run build -npm run preview # Test production build locally + +# Preview production build locally +npm run preview ``` +The build output is in the `dist/` folder, ready for deployment. + +## Common Issues + + + + - Check `.env` file exists with correct values + - Verify Appwrite project ID is correct + - Ensure `localhost` is added to Appwrite platforms + + + + Add `localhost` to Appwrite Console → Settings → Platforms + + + + - Delete `node_modules` and `package-lock.json` + - Run `npm install` again + - Ensure Node.js 18+ is installed + + + +See [Troubleshooting](/troubleshooting) for more solutions. + ## Next Steps - - Complete database and storage configuration + + Set up all collections and storage buckets - - Deploy to Vercel or other platforms + + Make your portfolio live + + + Change colors, fonts, and styles + + + Learn about all available features diff --git a/troubleshooting.mdx b/troubleshooting.mdx new file mode 100644 index 0000000..735b248 --- /dev/null +++ b/troubleshooting.mdx @@ -0,0 +1,281 @@ +--- +title: "Troubleshooting" +description: "Common issues and solutions for your portfolio website" +--- + +# Troubleshooting Guide + +Quick solutions to common problems you might encounter. + +## Database & Backend Issues + +### Data Not Loading + + + + **Cause:** Environment variables not configured or Appwrite connection failed. + + **Solution:** + 1. Check `.env` file exists with correct values + 2. Verify Appwrite project ID is correct + 3. Check browser console for errors + 4. Ensure Appwrite platform includes your domain + + ```env + VITE_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1 + VITE_APPWRITE_PROJECT_ID=your_project_id + VITE_APPWRITE_DATABASE_ID=portfolio_db + ``` + + + + **Error:** `Access to XMLHttpRequest blocked by CORS policy` + + **Solution:** + 1. Go to Appwrite Console → Settings → Platforms + 2. Add your domain: + - `localhost` (for development) + - `your-site.vercel.app` (for production) + - `yourdomain.com` (custom domain) + 3. Wait 1-2 minutes for changes to propagate + + + + **Error:** `Collection or database not found` + + **Solution:** + 1. Verify collection exists in Appwrite Console + 2. Check collection ID matches exactly (case-sensitive) + 3. Ensure database ID is correct in `.env` + + + + **Error:** `User is not authorized` + + **Solution:** + 1. Check collection permissions in Appwrite + 2. For public content: Add "Any" with Read permission + 3. For admin content: Add "Users" with all permissions + 4. See [Permissions Guide](/appwrite/permissions) + + + +## Image & Storage Issues + + + + **Possible Causes:** + - File too large (check bucket max size) + - Wrong file format + - Bucket permissions incorrect + + **Solution:** + 1. Check file size (usually max 10MB) + 2. Use supported formats: jpg, png, gif, webp + 3. Verify bucket has "Users" create permission + 4. Check browser console for specific error + + + + **Possible Causes:** + - Bucket doesn't have public read access + - Image URL is incorrect + - Image was deleted + + **Solution:** + 1. Check bucket has "Any" read permission + 2. Test image URL directly in browser + 3. Re-upload the image if needed + + + + **Solution:** + 1. Ensure file is `.ttf`, `.otf`, or `.woff` format + 2. Check file size < 5MB + 3. Verify `custom-fonts` bucket exists + 4. Check bucket permissions + + + +## Deployment Issues + + + + **Common Causes:** + - Missing dependencies + - Environment variables not set + - Syntax errors in code + + **Solution:** + 1. Check Vercel build logs for specific error + 2. Run `npm run build` locally to test + 3. Ensure all env variables are set in Vercel + 4. Check for TypeScript/ESLint errors + + + + **Cause:** SPA routing not configured + + **Solution:** Add `vercel.json` to project root: + ```json + { + "rewrites": [{ "source": "/(.*)", "destination": "/" }] + } + ``` + + + + **Solution:** + 1. Variables must start with `VITE_` prefix + 2. Redeploy after adding variables + 3. Check variables are set for correct environment (Production/Preview) + 4. Clear browser cache after redeploying + + + +## Admin Panel Issues + + + + **Solution:** + 1. Verify Appwrite account exists + 2. Check email is verified in Appwrite + 3. Clear browser cookies and try again + 4. Check Appwrite Console for user status + + + + **Possible Causes:** + - Network error + - Permission denied + - Validation error + + **Solution:** + 1. Check browser console for errors + 2. Verify you're logged in + 3. Check all required fields are filled + 4. Try refreshing and re-saving + + + + **Solution:** + 1. Clear browser cache + 2. Try a different browser + 3. Check for JavaScript errors in console + 4. Ensure all dependencies are installed + + + +## Shortlink Issues + + + + **Solution:** + 1. Check shortlink is marked "Active" + 2. Verify path doesn't have typos + 3. Clear browser cache + 4. Check if path conflicts with existing routes + + + + **Solution:** + 1. Wait 10-15 minutes for DNS propagation + 2. Verify DNS records are correct: + - CNAME pointing to your domain + - TXT record with verification token + 3. Check DNS with online tools (dnschecker.org) + 4. Ensure Cloudflare proxy is enabled (if using) + + + + **Solution:** + 1. Check `shortlink_analytics` collection exists + 2. Verify collection permissions + 3. Test with incognito/private browsing + 4. Check browser console for errors + + + +## Shop & Payment Issues + + + + **Solution:** + 1. Verify `VITE_PAYPAL_CLIENT_ID` is set + 2. Check PayPal Client ID is correct + 3. Ensure PayPal app is enabled + 4. Test with sandbox credentials first + + + + **Solution:** + 1. Check `orders` collection exists with all attributes + 2. Verify collection permissions + 3. Check browser console for validation errors + 4. Ensure all required fields are provided + + + + **Solution:** + 1. Check `order-files` bucket exists + 2. Verify user is logged in + 3. Ensure user email matches order email + 4. Check if download token expired (15 min limit) + + + +## Performance Issues + + + + **Solutions:** + 1. Optimize images before uploading (compress, resize) + 2. Reduce number of embeds per page + 3. Use lazy loading for images + 4. Check network tab for slow requests + 5. Consider CDN for static assets + + + + **Solutions:** + 1. Clear browser cache + 2. Close unused browser tabs + 3. Check for memory leaks in console + 4. Reduce number of items per page in lists + + + +## Quick Diagnostic Steps + +When something isn't working: + + + + Press `F12` → Console tab. Look for red error messages. + + + Press `F12` → Network tab. Look for failed requests (red). + + + Ensure `.env` file exists and has correct values. + + + Verify collections, buckets, and permissions are set up. + + + Hard refresh: `Ctrl+Shift+R` (Windows) or `Cmd+Shift+R` (Mac) + + + +## Getting Help + +If you're still stuck: + +1. **Check the specific feature documentation** for detailed setup steps +2. **Review Appwrite Console** for database/storage issues +3. **Check Vercel logs** for deployment issues +4. **Search error messages** online for common solutions + + + Most issues are caused by missing environment variables, incorrect permissions, or CORS configuration. Always check these first! +