v2.5.0 — Addon System, Vacay, Atlas, Dashboard Widgets & Mobile Overhaul
The biggest NOMAD update yet. Introduces a modular addon architecture and three major new features. Addon System: - Admin panel addon management with enable/disable toggles - Trip addons (Packing List, Budget, Documents) dynamically show/hide in trip tabs - Global addons appear in the main navigation for all users Vacay — Vacation Day Planner (Global Addon): - Monthly calendar view with international public holidays (100+ countries via Nager.Date API) - Company holidays with auto-cleanup of conflicting entries - User-based system: each NOMAD user is a person in the calendar - Fusion system: invite other users to share a combined calendar with real-time WebSocket sync - Vacation entitlement tracking with automatic carry-over to next year - Full settings: block weekends, public holidays, company holidays, carry-over toggle - Invite/accept/decline flow with forced confirmation modal - Color management per user with collision detection on fusion - Dissolve fusion with preserved entries Atlas — Travel World Map (Global Addon): - Fullscreen Leaflet world map with colored country polygons (GeoJSON) - Glass-effect bottom panel with stats, continent breakdown, streak tracking - Country tooltips with trip count, places visited, first/last visit dates - Liquid glass hover effect on the stats panel - Canvas renderer with tile preloading for maximum performance - Responsive: mobile stats bars, no zoom controls on touch Dashboard Widgets: - Currency converter with 50 currencies, CustomSelect dropdowns, localStorage persistence - Timezone widget with customizable city list, live updating clock - Per-user toggle via settings button, bottom sheet on mobile Admin Panel: - Consistent dark mode across all tabs (CSS variable overrides) - Online/offline status badges on user list via WebSocket - Unified heading sizes and subtitles across all sections - Responsive tab grid on mobile Mobile Improvements: - Vacay: slide-in sidebar drawer, floating toolbar, responsive calendar grid - Atlas: top/bottom glass stat bars, no popups - Trip Planner: fixed position content container prevents overscroll, portal-based sidebar buttons - Dashboard: fixed viewport container, mobile widget bottom sheet - Admin: responsive tab grid, compact buttons - Global: overscroll-behavior fixes, modal scroll containment Other: - Trip tab labels: Planung→Karte, Packliste→Liste, Buchungen→Buchung (DE mobile) - Reservation form responsive layout - Backup panel responsive buttons
This commit is contained in:
@@ -211,6 +211,82 @@ function initDb() {
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Addon system
|
||||
CREATE TABLE IF NOT EXISTS addons (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
type TEXT NOT NULL DEFAULT 'global',
|
||||
icon TEXT DEFAULT 'Puzzle',
|
||||
enabled INTEGER DEFAULT 0,
|
||||
config TEXT DEFAULT '{}',
|
||||
sort_order INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
-- Vacay addon tables
|
||||
CREATE TABLE IF NOT EXISTS vacay_plans (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
owner_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
block_weekends INTEGER DEFAULT 1,
|
||||
holidays_enabled INTEGER DEFAULT 0,
|
||||
holidays_region TEXT DEFAULT '',
|
||||
company_holidays_enabled INTEGER DEFAULT 1,
|
||||
carry_over_enabled INTEGER DEFAULT 1,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(owner_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vacay_plan_members (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plan_id INTEGER NOT NULL REFERENCES vacay_plans(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
status TEXT DEFAULT 'pending',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(plan_id, user_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vacay_user_colors (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
plan_id INTEGER NOT NULL REFERENCES vacay_plans(id) ON DELETE CASCADE,
|
||||
color TEXT DEFAULT '#6366f1',
|
||||
UNIQUE(user_id, plan_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vacay_years (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plan_id INTEGER NOT NULL REFERENCES vacay_plans(id) ON DELETE CASCADE,
|
||||
year INTEGER NOT NULL,
|
||||
UNIQUE(plan_id, year)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vacay_user_years (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
plan_id INTEGER NOT NULL REFERENCES vacay_plans(id) ON DELETE CASCADE,
|
||||
year INTEGER NOT NULL,
|
||||
vacation_days INTEGER DEFAULT 30,
|
||||
carried_over INTEGER DEFAULT 0,
|
||||
UNIQUE(user_id, plan_id, year)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vacay_entries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plan_id INTEGER NOT NULL REFERENCES vacay_plans(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
date TEXT NOT NULL,
|
||||
note TEXT DEFAULT '',
|
||||
UNIQUE(user_id, plan_id, date)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vacay_company_holidays (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
plan_id INTEGER NOT NULL REFERENCES vacay_plans(id) ON DELETE CASCADE,
|
||||
date TEXT NOT NULL,
|
||||
note TEXT DEFAULT '',
|
||||
UNIQUE(plan_id, date)
|
||||
);
|
||||
`);
|
||||
|
||||
// Create indexes for performance
|
||||
@@ -307,6 +383,25 @@ function initDb() {
|
||||
} catch (err) {
|
||||
console.error('Error seeding categories:', err.message);
|
||||
}
|
||||
|
||||
// Seed: default addons
|
||||
try {
|
||||
const existingAddons = _db.prepare('SELECT COUNT(*) as count FROM addons').get();
|
||||
if (existingAddons.count === 0) {
|
||||
const defaultAddons = [
|
||||
{ id: 'packing', name: 'Packing List', description: 'Pack your bags with checklists per trip', type: 'trip', icon: 'ListChecks', sort_order: 0 },
|
||||
{ id: 'budget', name: 'Budget Planner', description: 'Track expenses and plan your travel budget', type: 'trip', icon: 'Wallet', sort_order: 1 },
|
||||
{ id: 'documents', name: 'Documents', description: 'Store and manage travel documents', type: 'trip', icon: 'FileText', sort_order: 2 },
|
||||
{ id: 'vacay', name: 'Vacay', description: 'Personal vacation day planner with calendar view', type: 'global', icon: 'CalendarDays', sort_order: 10 },
|
||||
{ id: 'atlas', name: 'Atlas', description: 'World map of your visited countries with travel stats', type: 'global', icon: 'Globe', sort_order: 11 },
|
||||
];
|
||||
const insertAddon = _db.prepare('INSERT INTO addons (id, name, description, type, icon, enabled, sort_order) VALUES (?, ?, ?, ?, ?, 1, ?)');
|
||||
for (const a of defaultAddons) insertAddon.run(a.id, a.name, a.description, a.type, a.icon, a.sort_order);
|
||||
console.log('Default addons seeded');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error seeding addons:', err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on module load
|
||||
|
||||
Reference in New Issue
Block a user