Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Run it on a Raspberry Pi, a home server, or a $5 VPS. Your data stays yours.
- **Expenses & reports** — See what your vehicles actually cost you.
- **Dashboard** — A fleet-wide overview with widgets you can rearrange to your liking.
- **Auth & feature toggles** — Username/password login with sessions, and the ability to turn off features you don't need.
- **11 languages** — English, Hindi, Spanish, French, German, Italian, Arabic, Romanian, Hungarian, Finnish, and Russian.
- **11 languages** — English, Hindi, Spanish, French, German, Italian, Arabic, Romanian, Hungarian, Finnish, Russian and Czech.

## Tech stack

Expand Down
877 changes: 877 additions & 0 deletions i18n/messages/cs.json

Large diffs are not rendered by default.

66 changes: 65 additions & 1 deletion i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,15 @@
"common_date_from": "From",
"common_date_to": "To",
"common_export_csv": "Export CSV",
"nav_garage": "Garage",
"nav_dashboard": "Dashboard",
"nav_overview": "Overview",
"nav_fuel_logs": "Fuel Logs",
"nav_logs": "Logs",
"nav_insights": "Insights",
"nav_maintenance": "Maintenance",
"nav_reminders": "Reminders",
"nav_reports": "Reports",
"tools_export_data": "Export Data",
"tools_import_data": "Import Data",
"vehicle_form_make_label": "Make",
Expand Down Expand Up @@ -672,6 +677,7 @@
"fuel_stat_spent": "Total Spent",
"fuel_stat_avg_mileage": "Avg Mileage",
"fuel_stat_entries": "Total Entries",
"donut_chart_no_data": "No data available",
"maintenance_page_title": "Maintenance",
"maintenance_page_description": "Track service history and upcoming maintenance",
"maintenance_stat_last_service": "Last Service",
Expand Down Expand Up @@ -715,6 +721,7 @@
"reports_section_costs": "Costs",
"reports_section_details": "Detailed Report",
"reports_section_exports": "Exports",
"reports_no_expense_data": "No expense data yet",
"reports_stat_fuel_costs": "Fuel Costs",
"reports_stat_maintenance_costs": "Maintenance Costs",
"reports_chart_breakdown_title": "Expense Breakdown",
Expand Down Expand Up @@ -809,5 +816,62 @@
"reports_stat_compliance_costs": "Compliance Costs",
"compliance_col_document": "Compliance",
"compliance_col_status": "Status",
"compliance_col_days_left": "Days Left"
"compliance_col_days_left": "Days Left",
"vehicles_title": "Vehicles",
"vehicles_description": "Manage your fleet",
"no_data_yet": "No data yet",
"dashboard_title": "Dashboard",
"dashboard_reset_to_default": "Reset to Default",
"dashboard_reset_confirm_title": "Reset dashboard?",
"dashboard_reset_confirm_message": "This restores the default set of widgets and layout, replacing your current customization.",
"dashboard_reset_confirm_reset": "Reset",
"dashboard_add_widget": "Add Widget",
"dashboard_good_morning": "Good morning",
"dashboard_good_afternoon": "Good afternoon",
"dashboard_good_evening": "Good evening",
"dashboard_cta_heading": "Get detailed insights",
"dashboard_cta_description": "View comprehensive reports and analytics for your fleet",
"dashboard_cta_button_label": "View Reports",
"all_widgets_used": "All available widgets are already on your dashboard.",
"widget_total_vehicles": "Total Vehicles",
"widget_total_vehicles_description": "Number of vehicles in your garage",
"widget_total_distance": "Total Distance",
"widget_total_distance_description": "Distance driven across the whole fleet",
"widget_total_fuel_used": "Total Fuel Used",
"widget_total_fuel_used_description": "Fuel consumed across the whole fleet",
"widget_total_expenses": "Total Expenses",
"widget_total_expenses_description": "Fuel, maintenance and insurance spend combined",
"widget_cost_per_distance": "Cost / Distance",
"widget_cost_per_distance_description": "Overall running cost per unit distance",
"widget_expense_breakdown": "Expenses by Category",
"widget_expense_breakdown_description": "Fuel vs. maintenance vs. compliance spend",
"widget_monthly_expense_trend": "Monthly Expense Trend",
"widget_monthly_expense_trend_description": "Last 12 months of spend by category",
"widget_cost_by_vehicle": "Cost by Vehicle",
"widget_cost_by_vehicle_description": "Which vehicles cost the most to run",
"widget_fleet_fuel_trend": "Fleet Fuel Trend",
"widget_fleet_fuel_trend_description": "Daily fuel usage across the fleet",
"widget_fuel_consumption_trend": "Fuel Consumption Trend",
"widget_fuel_consumption_trend_description": "Fuel usage over time, one line per vehicle",
"widget_mileage_overview": "Mileage Overview",
"widget_mileage_overview_description": "Mileage over time, one line per vehicle",
"widget_efficiency_leaderboard": "Efficiency Leaderboard",
"widget_efficiency_leaderboard_description": "Vehicles ranked by fuel efficiency",
"widget_compliance_status": "Other Compliance Status",
"widget_compliance_status_description": "Emissions, roadworthiness & registration status across the fleet",
"widget_insurance_status": "Insurance Status",
"widget_insurance_status_description": "Insurance policy status across the fleet",
"widget_vehicle_health": "Vehicle Health",
"widget_vehicle_health_description": "Overall good/attention/needs-action breakdown",
"widget_upcoming_reminders": "Upcoming Reminders",
"widget_upcoming_reminders_description": "Reminders coming due soon",
"widget_no_upcoming_reminders": "No upcoming reminders",
"widget_vehicles_quick_list": "My Vehicles",
"widget_vehicles_quick_list_description": "Quick access to your vehicles",
"widget_no_vehicles_yet": "No vehicles yet",
"widget_recent_activity": "Recent Activity",
"widget_recent_activity_description": "Latest fuel and maintenance logs across the fleet",
"widget_activity_calendar": "Activity Calendar",
"widget_activity_calendar_description": "Upcoming reminders and past fuel/maintenance activity by date",
"widget_calendar_no_activity_or_reminders": "No activity or reminders on this date."
}
2 changes: 1 addition & 1 deletion i18n/project.inlang/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"pathPattern": "./messages/{locale}.json"
},
"baseLocale": "en",
"locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro", "ru", "pt-PT"]
"locales": ["en", "ar", "hi", "es", "fr", "de", "it", "hu", "fi", "ro", "ru", "pt-PT", "cs"]
}
3 changes: 2 additions & 1 deletion src/lib/components/dashboard/ActivityFeed.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import Skeleton from '$lib/components/ui/skeleton/skeleton.svelte';
import { formatCurrency, formatDate } from '$lib/helper/format.helper';
import { ACCENT } from '$lib/helper/accent-color.helper';
import { vehicle_hub_activity_empty } from '$lib/paraglide/messages/_index.js';

let {
entries,
Expand All @@ -27,7 +28,7 @@
</div>
{:else if entries.length === 0}
<div class="text-muted-foreground flex h-full items-center justify-center text-sm">
No recent activity
{vehicle_hub_activity_empty()}
</div>
{:else}
<div class="divide-y">
Expand Down
3 changes: 2 additions & 1 deletion src/lib/components/dashboard/DonutChart.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import * as Chart from '$ui/chart/index.js';
import { PieChart } from 'layerchart';
import Skeleton from '$lib/components/ui/skeleton/skeleton.svelte';
import { donut_chart_no_data } from '$lib/paraglide/messages/_index.js';

interface DonutDataPoint {
name: string;
Expand Down Expand Up @@ -125,7 +126,7 @@
class="flex flex-col items-center justify-center gap-2 {chartAreaClass}"
style={chartStyle}
>
<span class="text-muted-foreground text-sm">No data available</span>
<span class="text-muted-foreground text-sm">{donut_chart_no_data()}</span>
</div>
{:else if data.length === 1}
{@const size = ringSize}
Expand Down
14 changes: 10 additions & 4 deletions src/lib/components/dashboard/StackedAreaChart.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
import LegendInfoGroup from '$appui/LegendInfoGroup.svelte';
import CircleSlash2 from '@lucide/svelte/icons/circle-slash-2';
import Skeleton from '$lib/components/ui/skeleton/skeleton.svelte';
import {
reports_no_expense_data,
reports_type_fuel,
reports_type_maintenance,
reports_type_compliance
} from '$lib/paraglide/messages/_index.js';
import { formatCurrency } from '$lib/helper/format.helper';

let {
Expand All @@ -25,9 +31,9 @@
} = $props();

const SERIES = [
{ key: 'fuel', label: 'Fuel', color: 'var(--chart-1)' },
{ key: 'maintenance', label: 'Maintenance', color: 'var(--chart-2)' },
{ key: 'compliance', label: 'Compliance', color: 'var(--chart-3)' }
{ key: 'fuel', label: reports_type_fuel(), color: 'var(--chart-1)' },
{ key: 'maintenance', label: reports_type_maintenance(), color: 'var(--chart-2)' },
{ key: 'compliance', label: reports_type_compliance(), color: 'var(--chart-3)' }
] as const;

const chartData = $derived(data.map((point) => ({ ...point, x: new Date(`${point.month}-01`) })));
Expand Down Expand Up @@ -137,7 +143,7 @@
</Chart.Container>
{:else}
<div class="flex h-full flex-col items-center justify-center">
<LabelWithIcon icon={CircleSlash2} iconClass="h-4 w-4" label="No expense data yet" />
<LabelWithIcon icon={CircleSlash2} iconClass="h-4 w-4" label={reports_no_expense_data()} />
</div>
{/if}
</div>
7 changes: 4 additions & 3 deletions src/lib/components/dashboard/VehicleFilterDropdown.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import type { Vehicle } from '$lib/domain/vehicle';
import VehicleTypeBadge from '$feature/vehicle/VehicleTypeBadge.svelte';
import { cn } from '$lib/utils';
import { vehicle_scope_all } from '$lib/paraglide/messages/_index.js';

let {
vehicles,
Expand All @@ -23,9 +24,9 @@
);

const triggerLabel = $derived.by(() => {
if (selectedIds.length === 0) return 'All Vehicles';
if (selectedIds.length === 0) return vehicle_scope_all();
if (selectedIds.length === 1)
return singleSelected ? vehicleLabel(singleSelected) : 'All Vehicles';
return singleSelected ? vehicleLabel(singleSelected) : vehicle_scope_all();
return `${selectedIds.length} vehicles`;
});

Expand Down Expand Up @@ -57,7 +58,7 @@
<DropdownMenu.Content align="end" class="min-w-56">
<DropdownMenu.Item class="gap-2" onclick={() => (selectedIds = [])}>
<Check class={cn('size-4 shrink-0', selectedIds.length > 0 && 'text-transparent')} />
<span>All Vehicles</span>
<span>{vehicle_scope_all()}</span>
</DropdownMenu.Item>
{#if vehicles.length > 0}
<DropdownMenu.Separator />
Expand Down
3 changes: 2 additions & 1 deletion src/lib/components/dashboard/VehicleLeaderboard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import Skeleton from '$lib/components/ui/skeleton/skeleton.svelte';
import { cn } from '$lib/utils';
import { ACCENT } from '$lib/helper/accent-color.helper';
import { no_data_yet } from '$lib/paraglide/messages/_index.js';

interface Entry {
id: string;
Expand All @@ -13,7 +14,7 @@
let {
entries,
loading = false,
emptyLabel = 'No data yet'
emptyLabel = no_data_yet()
}: {
entries: Entry[];
loading?: boolean;
Expand Down
Loading
Loading