Asset Management
Learn where to place images and how they’re optimized
Data configuration in the FiNAN website uses TypeScript interfaces to ensure consistency and catch errors at build time. All data lives in src/data/ and follows strict typing patterns.
All configuration data is organized by feature:
src/data/├── representation/│ └── committee/│ ├── types.ts # TypeScript interfaces│ ├── finlandCommittee.ts # Finland committee data│ ├── swedenCommittee.ts # Sweden committee data│ ├── norwayCommittee.ts # Norway committee data│ ├── denmarkCommittee.ts # Denmark committee data│ ├── icelandCommittee.ts # Iceland committee data│ ├── faroe-islandsCommittee.ts # Faroe Islands committee data│ ├── greenlandCommittee.ts # Greenland committee data│ └── aland-islandsCommittee.ts # Åland Islands committee data├── faqData.ts # FAQ questions and answers└── siteConfig.ts # Site-wide SEO and metadataTypes are defined in dedicated types.ts files to ensure consistency across all data files.
The committee type system is defined in src/data/representation/committee/types.ts:
import type { ImageMetadata } from 'astro';
/** * Represents a single committee member */export interface CommitteeMember { /** Full name of the committee member */ name: string;
/** Position/role in the committee (e.g., "President", "Secretary") */ position: string;
/** Imported image metadata for the member's photo */ photo: ImageMetadata;
/** Country this member represents */ country: string;
/** Optional contact email (not displayed publicly by default) */ email?: string;}
/** * Complete committee data for a country */export interface CommitteeData { /** Array of committee members */ members: CommitteeMember[];
/** Year the committee was established */ established: string;
/** Brief description of the committee's mission */ description: string;}FAQ data structure (typically inline in faqData.ts):
export interface FAQItem { question: string; answer: string; category?: 'membership' | 'events' | 'general';}
export interface FAQData { items: FAQItem[];}Site-wide configuration (in siteConfig.ts):
export interface SiteConfig { siteName: string; siteUrl: string; description: string; author: string; ogImage?: string; twitterHandle?: string;}Here’s how to create a committee data file following the Finland example (the best practice):
Import the type definition
import type { CommitteeData } from './types';Import committee member photos
import photoJohnDoe from '@/assets/images/committee/finland/john-doe.jpg';import photoJaneSmith from '@/assets/images/committee/finland/jane-smith.jpg';Create and export the committee data
export const finlandCommittee: CommitteeData = { members: [ { name: 'John Doe', position: 'President', photo: photoJohnDoe, country: 'Finland', email: 'john.doe@example.com', }, { name: 'Jane Smith', position: 'Secretary', photo: photoJaneSmith, country: 'Finland', }, ], established: '2015', description: 'Supporting Filipino nurses across Finland since 2015.',};Type safety catches errors
TypeScript will error if:
name, position, photo, country)photo is a string instead of ImageMetadata)import type { CommitteeData } from './types';
// Import member photosimport photoJohnDoe from '@/assets/images/committee/finland/john-doe.jpg';import photoJaneSmith from '@/assets/images/committee/finland/jane-smith.jpg';import photoMikeJohnson from '@/assets/images/committee/finland/mike-johnson.jpg';
/** * Finland committee member data * Updated: January 2026 */export const finlandCommittee: CommitteeData = { members: [ { name: 'John Doe', position: 'President', photo: photoJohnDoe, country: 'Finland', email: 'john.doe@finan-finland.org', }, { name: 'Jane Smith', position: 'Vice President', photo: photoJaneSmith, country: 'Finland', email: 'jane.smith@finan-finland.org', }, { name: 'Mike Johnson', position: 'Secretary', photo: photoMikeJohnson, country: 'Finland', }, ], established: '2015', description: 'The Finland chapter of FiNAN supports Filipino nurses throughout Finland with professional development, networking, and advocacy.',};import type { ImageMetadata } from 'astro';
export interface CommitteeMember { name: string; position: string; photo: ImageMetadata; country: string; email?: string;}
export interface CommitteeData { members: CommitteeMember[]; established: string; description: string;}If you’re a content editor adding or updating committee members, follow this simplified guide:
Find the correct file
Navigate to src/data/representation/committee/ and open the file for your country (e.g., finlandCommittee.ts).
Add member photos to assets
Place photos in src/assets/images/committee/[country]/ with kebab-case names:
john-doe.jpg, jane-smith.jpgJohn Doe.jpg, jane_smith.png, JohnDoe.jpegImport the photo
At the top of the file, add:
import photoNewMember from '@/assets/images/committee/finland/new-member.jpg';Add member to the array
Add a new member object in the members array:
{ name: 'New Member', position: 'Treasurer', photo: photoNewMember, country: 'Finland', email: 'new.member@example.com', // Optional},Save and test
Run pnpm build to check for errors. If the build succeeds, your changes are correct!
FAQ data is stored in src/data/faqData.ts:
export interface FAQItem { question: string; answer: string; category?: 'membership' | 'events' | 'general';}
export const faqData: FAQItem[] = [ { question: 'How do I become a member?', answer: 'You can apply for membership by filling out the form on our Membership page. Membership is open to all Filipino nurses working in the Nordic region.', category: 'membership', }, { question: 'When is the next FiNAN event?', answer: 'Check our Events page for the latest information on upcoming conferences, webinars, and networking events.', category: 'events', }, // Add more FAQ items...];Open src/data/faqData.ts
Add a new item to the array:
{ question: 'Your question here?', answer: 'Your detailed answer here.', category: 'membership', // or 'events' or 'general'},Save and run pnpm build to validate
Site-wide settings are stored in src/data/siteConfig.ts:
export interface SiteConfig { siteName: string; siteUrl: string; description: string; author: string; ogImage?: string; twitterHandle?: string;}
export const siteConfig: SiteConfig = { siteName: 'FiNAN', siteUrl: 'https://finan.org', description: 'Filipino Nurses Association in the Nordic Region - Supporting Filipino nurses across the Nordics', author: 'FiNAN', ogImage: '/images/og-image.jpg', twitterHandle: '@finan_nordic',};Errors are caught before deployment:
// ❌ This will fail at build timeexport const finlandCommittee: CommitteeData = { members: [ { name: 'John Doe', // Missing required 'position' field - TypeScript error! photo: photoJohnDoe, country: 'Finland', }, ], established: '2015', description: 'Supporting Filipino nurses in Finland',};Your code editor will autocomplete field names and show documentation:
If you change a type definition, TypeScript will show all affected files:
// Change the type definitionexport interface CommitteeMember { name: string; position: string; photo: ImageMetadata; country: string; email?: string; phoneNumber?: string; // New optional field}
// TypeScript will NOT error on existing files because it's optional// But you can add it to any member if neededTypes serve as inline documentation:
export interface CommitteeMember { /** Full name of the committee member */ name: string;
/** Position/role in the committee (e.g., "President", "Secretary") */ position: string;
// ... more fields}Use ? for optional fields:
export interface CommitteeMember { name: string; // Required email?: string; // Optional}Types can reference other types:
export interface Address { street: string; city: string; country: string;}
export interface CommitteeMember { name: string; address: Address; // Nested type}Restrict values to specific options:
export interface FAQItem { question: string; answer: string; category?: 'membership' | 'events' | 'general'; // Only these values allowed}Error message:
Type '{ name: string; photo: ImageMetadata; country: string; }' is missing the following properties from type 'CommitteeMember': positionSolution: Add the missing position field to the member object.
Error message:
Cannot find module '@/assets/images/committee/finland/john-doe.jpg'Solution:
.jpg vs .jpeg vs .png)@/assets/Error message:
Type 'string' is not assignable to type 'ImageMetadata'Solution: You’re passing a string instead of an imported image. Import the image first:
// ❌ Wrongphoto: '/images/john-doe.jpg'
// ✅ Correctimport photoJohnDoe from '@/assets/images/committee/finland/john-doe.jpg';// ...photo: photoJohnDoeAsset Management
Learn where to place images and how they’re optimized
Committee Management
Complete guide for adding and updating committee members
Creating Components
Learn how components consume this typed data