My-Weekly-ToDo-List/src/components/FlagIcon.tsx
mARTin-B78 ffe2f46c64 feat: flag icons, real timezone picker, multi-timezone display
Wave-2 user feedback (points 4–6):
- Language picker: replace emoji flags (which don't render reliably on
  Windows) with inline-SVG flag components for GB/DE/FR/ES/IT. Used
  in both the Settings localisation tab and the onboarding wizard.
- Timezone: replace the read-only Intl.DateTimeFormat display with a
  real <select> over a curated list of major IANA zones. Each option
  shows "(UTC±hh:mm) CODE — Region" and the list is sorted by current
  offset, then code, then IANA name.
- Multi-timezone: new ExtraTimezonesEditor in the localisation tab lets
  users pin additional zones (stored in user.viewSettings.extraTimezones
  to avoid a migration). The time-grid axis now renders the equivalent
  hour for each pinned zone next to the local label, helpful for
  scheduling across regions.

v1.100.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:00:53 +02:00

95 lines
3.1 KiB
TypeScript

"use client";
import React from "react";
// Tiny inline SVG country flags. Used by the language pickers so flags
// render identically on every OS (Windows ships without the regional
// emoji glyphs that "🇬🇧" relies on).
type FlagCode = "gb" | "de" | "fr" | "es" | "it";
const flags: Record<FlagCode, React.ReactNode> = {
// United Kingdom
gb: (
<svg viewBox="0 0 60 30" width="100%" height="100%">
<clipPath id="fl_gb_t"><path d="M30,15h30v15z v15h-30z h-30v-15z v-15h30z"/></clipPath>
<path d="M0,0v30h60v-30z" fill="#012169"/>
<path d="M0,0 60,30 M60,0 0,30" stroke="#fff" strokeWidth="6"/>
<path d="M0,0 60,30 M60,0 0,30" clipPath="url(#fl_gb_t)" stroke="#C8102E" strokeWidth="4"/>
<path d="M30,0v30 M0,15h60" stroke="#fff" strokeWidth="10"/>
<path d="M30,0v30 M0,15h60" stroke="#C8102E" strokeWidth="6"/>
</svg>
),
// Germany
de: (
<svg viewBox="0 0 5 3" width="100%" height="100%" preserveAspectRatio="none">
<rect width="5" height="3" fill="#000"/>
<rect width="5" height="2" y="1" fill="#D00"/>
<rect width="5" height="1" y="2" fill="#FFCE00"/>
</svg>
),
// France
fr: (
<svg viewBox="0 0 3 2" width="100%" height="100%" preserveAspectRatio="none">
<rect width="1" height="2" x="0" fill="#0055A4"/>
<rect width="1" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#EF4135"/>
</svg>
),
// Spain
es: (
<svg viewBox="0 0 5 3" width="100%" height="100%" preserveAspectRatio="none">
<rect width="5" height="3" fill="#AA151B"/>
<rect width="5" height="1.5" y="0.75" fill="#F1BF00"/>
</svg>
),
// Italy
it: (
<svg viewBox="0 0 3 2" width="100%" height="100%" preserveAspectRatio="none">
<rect width="1" height="2" x="0" fill="#009246"/>
<rect width="1" height="2" x="1" fill="#fff"/>
<rect width="1" height="2" x="2" fill="#CE2B37"/>
</svg>
),
};
// Map UI language codes to flag codes (English uses the British flag per user request).
const LANG_FLAG: Record<string, FlagCode> = {
en: "gb",
de: "de",
fr: "fr",
es: "es",
it: "it",
};
interface FlagIconProps {
code: string;
width?: number;
height?: number;
className?: string;
}
export default function FlagIcon({ code, width = 22, height = 16, className }: FlagIconProps) {
const c = (LANG_FLAG[code] || code) as FlagCode;
const flag = flags[c];
if (!flag) return null;
return (
<span
className={className}
style={{
display: "inline-block",
width,
height,
lineHeight: 0,
borderRadius: 2,
overflow: "hidden",
boxShadow: "0 0 0 1px rgba(0,0,0,0.06)",
flexShrink: 0,
verticalAlign: "middle",
}}
aria-hidden="true"
>
{flag}
</span>
);
}