feat: add initial application structure with configuration, UI components, and state management

This commit is contained in:
Jennie Robinson Faber 2025-08-09 18:13:16 +01:00
parent fadf94002c
commit 0af6b17792
56 changed files with 6137 additions and 129 deletions

View file

@ -0,0 +1,127 @@
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
// Get configuration from environment
const currency = config.public.appCurrency || 'EUR'
const locale = config.public.appLocale || 'en-CA'
const decimalPlaces = parseInt(config.public.appDecimalPlaces || '2')
// Create formatters with centralized configuration
const currencyFormatter = new Intl.NumberFormat(locale, {
style: 'currency',
currency: currency,
minimumFractionDigits: decimalPlaces,
maximumFractionDigits: decimalPlaces
})
const numberFormatter = new Intl.NumberFormat(locale, {
minimumFractionDigits: 0,
maximumFractionDigits: decimalPlaces
})
const percentFormatter = new Intl.NumberFormat(locale, {
style: 'percent',
minimumFractionDigits: 0,
maximumFractionDigits: 1
})
const dateFormatter = new Intl.DateTimeFormat(locale, {
dateStyle: 'medium'
})
const shortDateFormatter = new Intl.DateTimeFormat(locale, {
dateStyle: 'short'
})
// Helper functions
const formatters = {
/**
* Format currency amount
*/
currency: (amount: number): string => {
return currencyFormatter.format(amount)
},
/**
* Format number with locale-specific formatting
*/
number: (value: number): string => {
return numberFormatter.format(value)
},
/**
* Format percentage (expects decimal, e.g., 0.65 for 65%)
*/
percent: (value: number): string => {
return percentFormatter.format(value)
},
/**
* Format percentage from whole number (e.g., 65 for 65%)
*/
percentFromWhole: (value: number): string => {
return `${Math.round(value)}%`
},
/**
* Format date
*/
date: (date: Date | string): string => {
const dateObj = typeof date === 'string' ? new Date(date) : date
return dateFormatter.format(dateObj)
},
/**
* Format date in short format
*/
shortDate: (date: Date | string): string => {
const dateObj = typeof date === 'string' ? new Date(date) : date
return shortDateFormatter.format(dateObj)
},
/**
* Format compact number for large amounts
*/
compact: (value: number): string => {
return new Intl.NumberFormat(locale, {
notation: 'compact',
maximumFractionDigits: 1
}).format(value)
},
/**
* Format currency without symbol (for inputs)
*/
currencyNumber: (amount: number): string => {
return numberFormatter.format(amount)
},
/**
* Get currency symbol
*/
getCurrencySymbol: (): string => {
return currencyFormatter.formatToParts(1)
.find(part => part.type === 'currency')?.value || currency
},
/**
* Parse currency string back to number
*/
parseCurrency: (value: string): number => {
// Remove currency symbols and formatting, parse as float
const cleaned = value.replace(/[^\d.,\-]/g, '')
.replace(/,/g, '.') // Handle comma as decimal separator
return parseFloat(cleaned) || 0
}
}
// Make formatters available globally
return {
provide: {
format: formatters,
currency,
locale,
decimalPlaces
}
}
})

View file

@ -0,0 +1,7 @@
import { defineNuxtPlugin } from "#app";
import { createPersistedState } from "pinia-plugin-persistedstate";
export default defineNuxtPlugin((nuxtApp) => {
// Register persisted state plugin for Pinia on client
nuxtApp.$pinia.use(createPersistedState());
});