Skip to content

Data Management

Learn how to add team members, portfolio projects, and manage your site’s content.


Employees are displayed in the Team Section using the EmployeeSection.astro component.

File: src/consts.ts

Add a new employee entry to the EMPLOYEES object:

src/consts.ts
export const EMPLOYEES: Record<string, EmployeeInfo> = {
// ... existing employees ...
// Add your new employee
ABC: { // Use a 3-letter trigram (e.g., initials)
id: "ABC",
name: "Anna Brown Carter",
portrait: "/images/employees/anna-brown.jpg", // Optional
email: "anna.brown@yourcompany.com",
phone: "+41 89 123 45 70",
socials: {
linkedin: "https://www.linkedin.com/in/annabrown/",
facebook: "", // Leave empty if not used
instagram: "",
twitter: "",
github: "https://github.com/annabrown/",
},
},
};

File: src/i18n/ui.ts

Add translations for the employee’s title and bio in all languages:

src/i18n/ui.ts
export const ui = {
fr: {
// ... existing translations ...
// Add employee translations (French)
'employee.ABC.title': 'Directrice Marketing',
'employee.ABC.bio': 'Anna dirige notre stratégie marketing avec créativité et innovation.',
},
de: {
// ... existing translations ...
// Add employee translations (German)
'employee.ABC.title': 'Marketing Direktorin',
'employee.ABC.bio': 'Anna leitet unsere Marketingstrategie mit Kreativität und Innovation.',
},
en: {
// ... existing translations ...
// Add employee translations (English)
'employee.ABC.title': 'Marketing Director',
'employee.ABC.bio': 'Anna leads our marketing strategy with creativity and innovation.',
},
} as const;

Translation Keys Format:

  • Title: employee.{ID}.title
  • Bio: employee.{ID}.bio

If you have a portrait image:

  1. Add the image to public/images/employees/
  2. Reference it in consts.ts as shown above
  3. Recommended size: 240x240px or larger (square)

If you leave the portrait field empty, the component will automatically generate an avatar using the employee’s name.

  1. Save all files
  2. The employee will automatically appear in the Team section
  3. Check all language versions to ensure translations are correct

Portfolio projects are displayed in the Portfolio Section with an interactive carousel and lightbox.

Portfolio carousel with lightbox

Option A: Use a local image

  1. Add your image to src/assets/portfolio/
  2. Recommended size: 800x600px or similar aspect ratio
  3. Supported formats: JPG, PNG, WebP

Option B: Use an external URL

  • You can use any image URL (e.g., placeholder services, CDN)

File: src/data/portfolio/fr.ts

src/data/portfolio/fr.ts
import { nanoid } from "nanoid";
import type { ImageMetadata } from "astro";
// If using local image, import it:
import myProjectImage from "../../assets/portfolio/my-project.jpg";
export const portfolioFr: PortfolioProject[] = [
// ... existing projects ...
// Add your new project
{
id: nanoid(), // Auto-generates unique ID
title: "Mon Nouveau Projet",
description: "Description détaillée du projet en français.\n\nVous pouvez utiliser plusieurs lignes.",
image: myProjectImage, // Use imported image
// OR use external URL:
// image: "https://example.com/image.jpg",
// Optional: Call-to-action buttons
primaryCtaText: "Voir le projet →",
primaryCtaLink: "https://example.com/project",
secondaryCtaText: "En savoir plus",
secondaryCtaLink: "https://example.com/about",
},
];

File: src/data/portfolio/de.ts

Add the same project with German translations:

src/data/portfolio/de.ts
import { nanoid } from "nanoid";
import myProjectImage from "../../assets/portfolio/my-project.jpg";
export const portfolioDe: PortfolioProject[] = [
// ... existing projects ...
{
id: nanoid(), // Different ID is OK
title: "Mein Neues Projekt",
description: "Detaillierte Projektbeschreibung auf Deutsch.\n\nSie können mehrere Zeilen verwenden.",
image: myProjectImage, // Same image
primaryCtaText: "Projekt ansehen →",
primaryCtaLink: "https://example.com/project",
secondaryCtaText: "Mehr erfahren",
secondaryCtaLink: "https://example.com/about",
},
];

Repeat for English (src/data/portfolio/en.ts) with English translations.

Property Required Description
id ✅ Yes Unique identifier (use nanoid())
title ✅ Yes Project title
description ✅ Yes Project description (supports multi-line with \n)
image ✅ Yes Imported image/video or URL string (supports MP4, WebM, MOV, OGG)
primaryCtaText ❌ No Text for primary button
primaryCtaLink ❌ No URL for primary button
secondaryCtaText ❌ No Text for secondary button
secondaryCtaLink ❌ No URL for secondary button
  1. Save all files
  2. The project will automatically appear in the portfolio carousel
  3. Test the lightbox by clicking on the project image
  4. Verify all language versions

The portfolio section supports both images and videos, providing a richer showcase for your projects. Videos are detected automatically and displayed with enhanced UX features.

The portfolio component supports the following video formats (case-insensitive):

  • MP4 (.mp4) - Recommended for best compatibility
  • WebM (.webm) - Good for web optimization
  • MOV (.mov) - Apple QuickTime format
  • OGG (.ogg) - Open format support

Adding a video works exactly like adding an image project. The component automatically detects video files and handles them appropriately.

  1. Add your video to src/assets/portfolio/

    src/assets/portfolio/
    ├── my-project.jpg
    └── my-demo-video.mp4 ← Add your video here
  2. Import and use in src/data/portfolio/fr.ts:

    src/data/portfolio/fr.ts
    import { nanoid } from "nanoid";
    import myDemoVideo from "../../assets/portfolio/my-demo-video.mp4";
    export const portfolioFr: PortfolioProject[] = [
    // ... existing projects ...
    {
    id: nanoid(),
    title: "Démonstration Vidéo",
    description: "Une présentation vidéo de notre projet.",
    image: myDemoVideo, // Use video file just like an image
    },
    ];
  3. Add the same project to other language files with translated text

src/data/portfolio/fr.ts
{
id: nanoid(),
title: "Projet Vidéo Externe",
description: "Vidéo hébergée sur un CDN ou service externe.",
image: "https://example.com/videos/my-video.mp4", // External URL
}

Videos in the portfolio have enhanced UX features:

  • First frame display: Videos show their first frame as the thumbnail using #t=0.1 timestamp
  • Play icon overlay: Centered play button with hover animation
  • Visual feedback: Darker overlay on hover with scaling play button effect
  • Auto-play: Videos attempt to play automatically when opened (with graceful fallback)
  • Native controls: Full video player controls (play, pause, seek, volume, fullscreen)
  • Loading indicator: Spinner shown while video is buffering
  • Responsive sizing: Videos scale to fit viewport (max-w-[90vw], max-h-[80vh])
  • Seamless navigation: Arrow keys and buttons work between images and videos
  • Auto-stop: Videos automatically pause when navigating away or closing lightbox
  • Memory efficient: Video sources are cleared to prevent background buffering

✅ Do:

  • Compress videos before adding (recommended: under 10MB for web)
  • Use MP4 with H.264 codec for best compatibility
  • Test on both desktop and mobile devices
  • Ensure the first frame is visually appealing (it becomes the thumbnail)
  • Keep videos short (30-60 seconds recommended for portfolio showcases)
  • Add descriptive titles and descriptions

❌ Don’t:

  • Use extremely large video files (slow loading, poor UX)
  • Rely solely on autoplay (some browsers/devices restrict it)
  • Forget to test video playback on mobile
  • Use proprietary formats without MP4 fallback

After adding a video, verify the following:

  1. Carousel Display

    • ✅ Video thumbnail shows first frame
    • ✅ Play icon overlay appears centered
    • ✅ Hover effect works (darker overlay, larger play button)
    • ✅ Click opens lightbox
  2. Lightbox Playback

    • ✅ Video plays automatically or shows controls
    • ✅ Controls are visible and functional
    • ✅ Navigation counter shows correct position
    • ✅ Previous/Next buttons work
  3. Mixed Content Navigation

    • ✅ Arrow keys navigate between images and videos smoothly
    • ✅ Videos stop playing when navigating away
    • ✅ No console errors or buffering issues
  4. Cleanup

    • ✅ Escape key closes lightbox and stops video
    • ✅ Clicking outside lightbox closes it and stops video
    • ✅ No memory leaks (check browser task manager)
  5. Mobile Testing

    • ✅ Swipe gestures work for navigation
    • ✅ Video plays on mobile devices
    • ✅ Play button is touch-friendly
    • ✅ Responsive sizing works correctly

Video content maintains full accessibility:

  • ARIA labels: All interactive elements properly labeled
  • Keyboard navigation: Tab, Enter, Escape, Arrow keys fully functional
  • Semantic HTML: Proper <video> element with fallback text
  • Focus management: Lightbox traps focus appropriately

Company information is centralized in src/consts.ts.

src/consts.ts
export const COMPANY: CompanyInfo = {
name: "Your Company Name",
address: "Your Street Address",
pobox: "P.O. Box 123", // Leave empty if not used
city: "CH-1000 Your City",
phone: "+41 XX XXX XX XX",
email: "contact@yourcompany.com",
mapsUrl: "https://maps.google.com/?q=Your+Address",
socials: {
linkedin: "https://www.linkedin.com/company/yourcompany/",
facebook: "https://facebook.com/yourcompany",
instagram: "https://instagram.com/yourcompany",
twitter: "https://twitter.com/yourcompany",
github: "https://github.com/yourcompany",
},
};

File: src/i18n/ui.ts

Update translatable company information:

src/i18n/ui.ts
export const ui = {
fr: {
'business.name': 'Votre Entreprise',
'business.tagline': 'Votre slogan ici',
'business.description': 'Description de votre entreprise...',
// ... more translations
},
de: {
'business.name': 'Ihr Unternehmen',
'business.tagline': 'Ihr Slogan hier',
'business.description': 'Beschreibung Ihres Unternehmens...',
// ... more translations
},
};

✅ Do:

  • Use consistent 3-letter trigrams (IDs)
  • Add translations for all languages
  • Optimize portrait images before adding
  • Leave social fields empty if not used

❌ Don’t:

  • Use duplicate IDs
  • Forget to add translations in all languages
  • Use overly large portrait images

✅ Do:

  • Use consistent image sizes (800x600 recommended)
  • Optimize images before importing
  • Compress videos before adding (recommended: under 10MB)
  • Use MP4 (H.264) format for videos for best compatibility
  • Add projects to all language files
  • Use nanoid() for unique IDs
  • Test the lightbox functionality with both images and videos
  • Ensure video first frames are visually appealing (they become thumbnails)
  • Test video playback on mobile devices

❌ Don’t:

  • Use different projects in different languages
  • Forget to import local images/videos
  • Use extremely large images or videos (slow loading, poor UX)
  • Rely solely on video autoplay (some browsers restrict it)
  • Use proprietary video formats without MP4 fallback

✅ Do:

  • Keep translation keys consistent across languages
  • Use dot notation for organization
  • Add comments for context
  • Test all language versions

❌ Don’t:

  • Hardcode text in components
  • Skip languages when adding new keys
  • Use inconsistent naming conventions

  1. Add to EMPLOYEES in src/consts.ts
  2. Add translations in src/i18n/ui.ts (all languages)
  3. Optionally add portrait image to public/images/employees/
  1. Add image/video to src/assets/portfolio/ (if local)
  2. Import image/video in src/data/portfolio/fr.ts
  3. Add project object to portfolioFr array
  4. Repeat for src/data/portfolio/de.ts (and other languages)
  5. For videos: Use MP4 format for best compatibility
  1. Edit COMPANY object in src/consts.ts
  2. Update translations in src/i18n/ui.ts