Enhance pop-up components with connection indicators and improve styling

- Refactored IncidentPopup, TimelinePopup, and UnitPopup components to include connection lines and dots for better visual indication of their relation to the map.
- Updated the layout and styling of the pop-ups for improved readability and consistency.
- Adjusted the TIME_ZONES data to reflect more accurate geographical locations.
- Enhanced the digital clock display in the TimeZonesDisplay component with improved styling and shadow effects.
- Added new CSS styles for digital clock presentation to enhance user experience.
This commit is contained in:
vergiLgood1 2025-05-07 07:21:38 +07:00
parent da94277f4d
commit 4cc01babf1
7 changed files with 669 additions and 536 deletions

View File

@ -82,101 +82,125 @@ export default function IncidentPopup({ longitude, latitude, onClose, incident }
maxWidth="320px" maxWidth="320px"
className="incident-popup z-50" className="incident-popup z-50"
> >
<Card <div className="relative">
className={`bg-background p-0 w-full max-w-[320px] shadow-xl border-0 overflow-hidden border-l-4 ${getBorderColor(incident.status)}`} <Card
> className={`bg-background p-0 w-full max-w-[320px] shadow-xl border-0 overflow-hidden border-l-4 ${getBorderColor(incident.status)}`}
<div className="p-4 relative"> >
{/* Custom close button */} <div className="p-4 relative">
<Button {/* Custom close button */}
variant="ghost" <Button
size="icon" variant="ghost"
className="absolute top-2 right-2 h-6 w-6 rounded-full bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700" size="icon"
onClick={onClose} className="absolute top-2 right-2 h-6 w-6 rounded-full bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700"
> onClick={onClose}
<X className="h-4 w-4" /> >
<span className="sr-only">Close</span> <X className="h-4 w-4" />
</Button> <span className="sr-only">Close</span>
</Button>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h3 className="font-bold text-base flex items-center gap-1.5"> <h3 className="font-bold text-base flex items-center gap-1.5">
<AlertTriangle className="h-4 w-4 text-red-500" /> <AlertTriangle className="h-4 w-4 text-red-500" />
{incident.category || "Unknown Incident"} {incident.category || "Unknown Incident"}
</h3> </h3>
{getStatusBadge(incident.status)} {getStatusBadge(incident.status)}
</div>
{incident.description && (
<div className="mb-3 bg-slate-50 dark:bg-slate-900/40 p-3 rounded-lg">
<p className="text-sm">
<FileText className="inline-block h-3.5 w-3.5 mr-1.5 align-text-top text-slate-500" />
{incident.description}
</p>
</div> </div>
)}
<Separator className="my-3" /> {incident.description && (
<div className="mb-3 bg-slate-50 dark:bg-slate-900/40 p-3 rounded-lg">
{/* Improved section headers */} <p className="text-sm">
<div className="grid grid-cols-2 gap-2 text-sm"> <FileText className="inline-block h-3.5 w-3.5 mr-1.5 align-text-top text-slate-500" />
{incident.district && ( {incident.description}
<div className="col-span-2">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">District</p>
<p className="flex items-center">
<Bookmark className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-purple-500" />
<span className="font-medium">{incident.district}</span>
</p> </p>
</div> </div>
)} )}
{incident.address && ( <Separator className="my-3" />
<div className="col-span-2">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Location</p>
<p className="flex items-center">
<MapPin className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-red-500" />
<span className="font-medium">{incident.address}</span>
</p>
</div>
)}
{incident.timestamp && ( {/* Improved section headers */}
<> <div className="grid grid-cols-2 gap-2 text-sm">
<div> {incident.district && (
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Date</p> <div className="col-span-2">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">District</p>
<p className="flex items-center"> <p className="flex items-center">
<Calendar className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-blue-500" /> <Bookmark className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-purple-500" />
<span className="font-medium">{formatDate(incident.timestamp)}</span> <span className="font-medium">{incident.district}</span>
</p> </p>
</div> </div>
<div> )}
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Time</p>
{incident.address && (
<div className="col-span-2">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Location</p>
<p className="flex items-center"> <p className="flex items-center">
<Clock className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-amber-500" /> <MapPin className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-red-500" />
<span className="font-medium">{formatTime(incident.timestamp)}</span> <span className="font-medium">{incident.address}</span>
</p> </p>
</div> </div>
</> )}
)}
{incident.type_category && ( {incident.timestamp && (
<div className="col-span-2"> <>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Type</p> <div>
<p className="flex items-center"> <p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Date</p>
<Tag className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-green-500" /> <p className="flex items-center">
<span className="font-medium">{incident.type_category}</span> <Calendar className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-blue-500" />
</p> <span className="font-medium">{formatDate(incident.timestamp)}</span>
</div> </p>
)} </div>
</div> <div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Time</p>
<p className="flex items-center">
<Clock className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-amber-500" />
<span className="font-medium">{formatTime(incident.timestamp)}</span>
</p>
</div>
</>
)}
<div className="mt-3 pt-3 border-t border-border"> {incident.type_category && (
<p className="text-xs text-muted-foreground flex items-center"> <div className="col-span-2">
<Navigation className="inline-block h-3 w-3 mr-1 shrink-0" /> <p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Type</p>
Coordinates: {latitude.toFixed(6)}, {longitude.toFixed(6)} <p className="flex items-center">
</p> <Tag className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-green-500" />
<p className="text-xs text-muted-foreground mt-1">ID: {incident.id}</p> <span className="font-medium">{incident.type_category}</span>
</p>
</div>
)}
</div>
<div className="mt-3 pt-3 border-t border-border">
<p className="text-xs text-muted-foreground flex items-center">
<Navigation className="inline-block h-3 w-3 mr-1 shrink-0" />
Coordinates: {latitude.toFixed(6)}, {longitude.toFixed(6)}
</p>
<p className="text-xs text-muted-foreground mt-1">ID: {incident.id}</p>
</div>
</div> </div>
</div> </Card>
</Card> {/* Connection line */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '2px',
height: '20px',
backgroundColor: 'red',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
{/* Connection dot */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '6px',
height: '6px',
backgroundColor: 'red',
borderRadius: '50%',
marginTop: '20px',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
</div>
</Popup> </Popup>
) )
} }

View File

@ -108,235 +108,253 @@ export default function DistrictPopup({
maxWidth="300px" maxWidth="300px"
className="district-popup z-50" className="district-popup z-50"
> >
<Card className="bg-background p-0 w-full max-w-[300px] shadow-xl border-0 overflow-hidden"> <div className="relative">
<div className="bg-tertiary text-white p-3 relative"> <Card className="bg-background p-0 w-full max-w-[300px] shadow-xl border-0 overflow-hidden">
{/* Custom close button */} <div className="bg-tertiary text-white p-3 relative">
<Button {/* Custom close button */}
variant="ghost" <Button
size="icon" variant="ghost"
className="absolute top-2 right-2 h-5 w-5 rounded-full bg-white/20 hover:bg-white/30 text-white" size="icon"
onClick={onClose} className="absolute top-2 right-2 h-5 w-5 rounded-full bg-white/20 hover:bg-white/30 text-white"
> onClick={onClose}
<X className="h-3 w-3" />
<span className="sr-only">Close</span>
</Button>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Building className="h-4 w-4" />
<h3 className="font-bold text-base">{district.name}</h3>
</div>
{getCrimeRateBadge(district.level)}
</div>
{/* <div className="mt-1 text-white/80 text-xs flex items-center gap-2">
<Calendar className="h-3 w-3" />
<span>{getTimePeriod()}</span>
</div> */}
</div>
<div className="grid grid-cols-3 gap-1 p-2 bg-background">
<div className="flex flex-col items-center justify-center p-1.5 bg-accent rounded-lg shadow-sm">
<AlertTriangle className="h-3.5 w-3.5 text-amber-500 mb-0.5" />
<span className="text-base font-bold">{formatNumber(district.number_of_crime || 0)}</span>
<span className="text-[10px] text-muted-foreground">Incidents</span>
</div>
<div className="flex flex-col items-center justify-center p-1.5 bg-accent rounded-lg shadow-sm">
<Users className="h-3.5 w-3.5 text-blue-500 mb-0.5" />
<span className="text-base font-bold">{formatNumber(district.demographics?.population || 0)}</span>
<span className="text-[10px] text-muted-foreground">Population</span>
</div>
<div className="flex flex-col items-center justify-center p-1.5 bg-accent rounded-lg shadow-sm">
<Home className="h-3.5 w-3.5 text-green-500 mb-0.5" />
<span className="text-base font-bold">{formatNumber(district.geographics?.land_area || 0)}</span>
<span className="text-[10px] text-muted-foreground">km²</span>
</div>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
{/* Improved tab headers */}
<TabsList className="w-full grid grid-cols-3 h-10 rounded-none bg-background border-b">
<TabsTrigger
value="overview"
className="rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:text-primary-foreground dark:data-[state=active]:text-primary-foreground data-[state=active]:shadow-none font-medium text-xs"
> >
Overview <X className="h-3 w-3" />
</TabsTrigger> <span className="sr-only">Close</span>
<TabsTrigger </Button>
value="demographics"
className="rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:text-primary-foreground dark:data-[state=active]:text-primary-foreground data-[state=active]:shadow-none font-medium text-xs"
>
Demographics
</TabsTrigger>
<TabsTrigger
value="crime_incidents"
className="rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:text-primary-foreground dark:data-[state=active]:text-primary-foreground data-[state=active]:shadow-none font-medium text-xs"
>
Incidents
</TabsTrigger>
</TabsList>
{/* Tab content with improved section headers */} <div className="flex items-center justify-between">
<TabsContent value="overview" className="mt-0 p-4"> <div className="flex items-center gap-2">
<div className="text-sm space-y-3"> <Building className="h-4 w-4" />
<div className="flex items-start gap-3"> <h3 className="font-bold text-base">{district.name}</h3>
<div className="bg-amber-100 dark:bg-amber-950/30 p-2 rounded-full">
<AlertTriangle className="w-5 h-5 text-amber-600 dark:text-amber-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Crime Level</p>
<p className="text-muted-foreground text-xs">
This area has a {district.level || "unknown"} level of crime based on incident reports.
</p>
</div>
</div>
{district.geographics && district.geographics.land_area && (
<div className="flex items-start gap-3">
<div className="bg-emerald-100 dark:bg-emerald-950/30 p-2 rounded-full">
<Home className="w-5 h-5 text-emerald-600 dark:text-emerald-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Geography</p>
<p className="text-muted-foreground text-xs">
Land area: {formatNumber(district.geographics.land_area)} km²
</p>
{district.geographics.address && (
<p className="text-muted-foreground text-xs">Address: {district.geographics.address}</p>
)}
</div>
</div>
)}
<div className="flex items-start gap-3">
<div className="bg-blue-100 dark:bg-blue-950/30 p-2 rounded-full">
<Calendar className="w-5 h-5 text-blue-600 dark:text-blue-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Time Period</p>
<p className="text-muted-foreground text-xs">
Data shown for {getTimePeriod()}
{filterCategory !== "all" ? ` (${filterCategory} category)` : ""}
</p>
</div>
</div> </div>
{getCrimeRateBadge(district.level)}
</div> </div>
</TabsContent> </div>
<TabsContent value="demographics" className="mt-0 p-4"> <div className="grid grid-cols-3 gap-1 p-2 bg-background">
{district.demographics ? ( <div className="flex flex-col items-center justify-center p-1.5 bg-accent rounded-lg shadow-sm">
<AlertTriangle className="h-3.5 w-3.5 text-amber-500 mb-0.5" />
<span className="text-base font-bold">{formatNumber(district.number_of_crime || 0)}</span>
<span className="text-[10px] text-muted-foreground">Incidents</span>
</div>
<div className="flex flex-col items-center justify-center p-1.5 bg-accent rounded-lg shadow-sm">
<Users className="h-3.5 w-3.5 text-blue-500 mb-0.5" />
<span className="text-base font-bold">{formatNumber(district.demographics?.population || 0)}</span>
<span className="text-[10px] text-muted-foreground">Population</span>
</div>
<div className="flex flex-col items-center justify-center p-1.5 bg-accent rounded-lg shadow-sm">
<Home className="h-3.5 w-3.5 text-green-500 mb-0.5" />
<span className="text-base font-bold">{formatNumber(district.geographics?.land_area || 0)}</span>
<span className="text-[10px] text-muted-foreground">km²</span>
</div>
</div>
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
<TabsList className="w-full grid grid-cols-3 h-10 rounded-none bg-background border-b">
<TabsTrigger
value="overview"
className="rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:text-primary-foreground dark:data-[state=active]:text-primary-foreground data-[state=active]:shadow-none font-medium text-xs"
>
Overview
</TabsTrigger>
<TabsTrigger
value="demographics"
className="rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:text-primary-foreground dark:data-[state=active]:text-primary-foreground data-[state=active]:shadow-none font-medium text-xs"
>
Demographics
</TabsTrigger>
<TabsTrigger
value="crime_incidents"
className="rounded-none data-[state=active]:border-b-2 data-[state=active]:border-primary data-[state=active]:text-primary-foreground dark:data-[state=active]:text-primary-foreground data-[state=active]:shadow-none font-medium text-xs"
>
Incidents
</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="mt-0 p-4">
<div className="text-sm space-y-3"> <div className="text-sm space-y-3">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<div className="bg-blue-100 dark:bg-blue-950/30 p-2 rounded-full"> <div className="bg-amber-100 dark:bg-amber-950/30 p-2 rounded-full">
<Users className="w-5 h-5 text-blue-600 dark:text-blue-400" /> <AlertTriangle className="w-5 h-5 text-amber-600 dark:text-amber-400" />
</div> </div>
<div> <div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Population</p> <p className="font-semibold text-base text-slate-800 dark:text-slate-200">Crime Level</p>
<p className="text-muted-foreground text-xs"> <p className="text-muted-foreground text-xs">
Total: {formatNumber(district.demographics.population || 0)} This area has a {district.level || "unknown"} level of crime based on incident reports.
</p>
<p className="text-muted-foreground text-xs">
Density: {formatNumber(district.demographics.population_density || 0)} people/km²
</p> </p>
</div> </div>
</div> </div>
<div className="flex items-start gap-3"> {district.geographics && district.geographics.land_area && (
<div className="bg-red-100 dark:bg-red-950/30 p-2 rounded-full"> <div className="flex items-start gap-3">
<BarChart className="w-5 h-5 text-red-600 dark:text-red-400" /> <div className="bg-emerald-100 dark:bg-emerald-950/30 p-2 rounded-full">
</div> <Home className="w-5 h-5 text-emerald-600 dark:text-emerald-400" />
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Unemployment</p>
<p className="text-muted-foreground text-xs">
{formatNumber(district.demographics.number_of_unemployed || 0)} unemployed people
</p>
{district.demographics.population && district.demographics.number_of_unemployed && (
<p className="text-muted-foreground text-xs">
Rate:{" "}
{(
(district.demographics.number_of_unemployed / district.demographics.population) *
100
).toFixed(1)}
%
</p>
)}
</div>
</div>
<div className="flex items-start gap-3">
<div className="bg-purple-100 dark:bg-purple-950/30 p-2 rounded-full">
<AlertTriangle className="w-5 h-5 text-purple-600 dark:text-purple-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Crime Rate</p>
{district.number_of_crime && district.demographics.population ? (
<p className="text-muted-foreground text-xs">
{((district.number_of_crime / district.demographics.population) * 10000).toFixed(2)} crime
incidents per 10,000 people
</p>
) : (
<p className="text-muted-foreground text-xs">No data available</p>
)}
</div>
</div>
</div>
) : (
<div className="text-center p-4 text-sm text-muted-foreground">
<Users className="w-8 h-8 mx-auto mb-2 opacity-50" />
<p>No demographic data available for this district.</p>
</div>
)}
</TabsContent>
<TabsContent value="crime_incidents" className="mt-0 max-h-[250px] overflow-y-auto">
{allCrimeIncidents && allCrimeIncidents.length > 0 ? (
<div className="divide-y divide-border">
{allCrimeIncidents.map((incident, index) => (
<div
key={incident.id || index}
className="p-3 text-xs hover:bg-slate-50 dark:hover:bg-slate-900/30 transition-colors"
>
<div className="flex justify-between items-center">
<span className="font-medium flex items-center gap-1">
<AlertTriangle className="w-3 h-3 text-amber-500" />
{incident.category || incident.type || "Unknown"}
</span>
<Badge variant="outline" className="text-[10px] h-5">
{incident.status || "unknown"}
</Badge>
</div> </div>
<p className="text-muted-foreground mt-1 truncate">{incident.description || "No description"}</p> <div>
<div className="flex justify-between items-center mt-1"> <p className="font-semibold text-base text-slate-800 dark:text-slate-200">Geography</p>
<p className="text-muted-foreground"> <p className="text-muted-foreground text-xs">
{incident.timestamp ? new Date(incident.timestamp).toLocaleString() : "Unknown date"} Land area: {formatNumber(district.geographics.land_area)} km²
</p> </p>
<ChevronRight className="w-3 h-3 text-muted-foreground" /> {district.geographics.address && (
<p className="text-muted-foreground text-xs">Address: {district.geographics.address}</p>
)}
</div> </div>
</div> </div>
))}
{district.number_of_crime > allCrimeIncidents.length && (
<div className="p-3 text-xs text-center text-muted-foreground bg-muted/50">
<p>
Showing {allCrimeIncidents.length} of {district.number_of_crime} total incidents
{filterCategory !== "all" ? ` for ${filterCategory} category` : ""}
</p>
</div>
)} )}
<div className="flex items-start gap-3">
<div className="bg-blue-100 dark:bg-blue-950/30 p-2 rounded-full">
<Calendar className="w-5 h-5 text-blue-600 dark:text-blue-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Time Period</p>
<p className="text-muted-foreground text-xs">
Data shown for {getTimePeriod()}
{filterCategory !== "all" ? ` (${filterCategory} category)` : ""}
</p>
</div>
</div>
</div> </div>
) : ( </TabsContent>
<div className="text-center p-4 text-sm text-muted-foreground">
<AlertTriangle className="w-8 h-8 mx-auto mb-2 opacity-50" /> <TabsContent value="demographics" className="mt-0 p-4">
{district.demographics ? (
<div className="text-sm space-y-3">
<div className="flex items-start gap-3">
<div className="bg-blue-100 dark:bg-blue-950/30 p-2 rounded-full">
<Users className="w-5 h-5 text-blue-600 dark:text-blue-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Population</p>
<p className="text-muted-foreground text-xs">
Total: {formatNumber(district.demographics.population || 0)}
</p>
<p className="text-muted-foreground text-xs">
Density: {formatNumber(district.demographics.population_density || 0)} people/km²
</p>
</div>
</div>
<div className="flex items-start gap-3">
<div className="bg-red-100 dark:bg-red-950/30 p-2 rounded-full">
<BarChart className="w-5 h-5 text-red-600 dark:text-red-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Unemployment</p>
<p className="text-muted-foreground text-xs">
{formatNumber(district.demographics.number_of_unemployed || 0)} unemployed people
</p>
{district.demographics.population && district.demographics.number_of_unemployed && (
<p className="text-muted-foreground text-xs">
Rate:{" "}
{(
(district.demographics.number_of_unemployed / district.demographics.population) *
100
).toFixed(1)}
%
</p>
)}
</div>
</div>
<div className="flex items-start gap-3">
<div className="bg-purple-100 dark:bg-purple-950/30 p-2 rounded-full">
<AlertTriangle className="w-5 h-5 text-purple-600 dark:text-purple-400" />
</div>
<div>
<p className="font-semibold text-base text-slate-800 dark:text-slate-200">Crime Rate</p>
{district.number_of_crime && district.demographics.population ? (
<p className="text-muted-foreground text-xs">
{((district.number_of_crime / district.demographics.population) * 10000).toFixed(2)} crime
incidents per 10,000 people
</p>
) : (
<p className="text-muted-foreground text-xs">No data available</p>
)}
</div>
</div>
</div>
) : (
<div className="text-center p-4 text-sm text-muted-foreground">
<Users className="w-8 h-8 mx-auto mb-2 opacity-50" />
<p>No demographic data available for this district.</p>
</div>
)}
</TabsContent>
<TabsContent value="crime_incidents" className="mt-0 max-h-[250px] overflow-y-auto">
{allCrimeIncidents && allCrimeIncidents.length > 0 ? (
<div className="divide-y divide-border">
{allCrimeIncidents.map((incident, index) => (
<div
key={incident.id || index}
className="p-3 text-xs hover:bg-slate-50 dark:hover:bg-slate-900/30 transition-colors"
>
<div className="flex justify-between items-center">
<span className="font-medium flex items-center gap-1">
<AlertTriangle className="w-3 h-3 text-amber-500" />
{incident.category || incident.type || "Unknown"}
</span>
<Badge variant="outline" className="text-[10px] h-5">
{incident.status || "unknown"}
</Badge>
</div>
<p className="text-muted-foreground mt-1 truncate">{incident.description || "No description"}</p>
<div className="flex justify-between items-center mt-1">
<p className="text-muted-foreground">
{incident.timestamp ? new Date(incident.timestamp).toLocaleString() : "Unknown date"}
</p>
<ChevronRight className="w-3 h-3 text-muted-foreground" />
</div>
</div>
))}
{district.number_of_crime > allCrimeIncidents.length && (
<div className="p-3 text-xs text-center text-muted-foreground bg-muted/50">
<p>
Showing {allCrimeIncidents.length} of {district.number_of_crime} total incidents
{filterCategory !== "all" ? ` for ${filterCategory} category` : ""}
</p>
</div>
)}
</div>
) : (
<div className="text-center p-4 text-sm text-muted-foreground">
<AlertTriangle className="w-8 h-8 mx-auto mb-2 opacity-50" />
<p> <p>
No crime incidents available to display{filterCategory !== "all" ? ` for ${filterCategory}` : ""}. No crime incidents available to display{filterCategory !== "all" ? ` for ${filterCategory}` : ""}.
</p> </p>
<p className="text-xs mt-2">Total reported incidents: {district.number_of_crime || 0}</p> <p className="text-xs mt-2">Total reported incidents: {district.number_of_crime || 0}</p>
</div> </div>
)} )}
</TabsContent> </TabsContent>
</Tabs> </Tabs>
</Card> </Card>
{/* Connection line */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '2px',
height: '20px',
backgroundColor: 'red',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
{/* Connection dot */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '6px',
height: '6px',
backgroundColor: 'red',
borderRadius: '50%',
marginTop: '20px',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
</div>
</Popup> </Popup>
) )
} }

View File

@ -65,116 +65,140 @@ export default function IncidentPopup({
maxWidth="320px" maxWidth="320px"
className="incident-popup z-50" className="incident-popup z-50"
> >
<Card <div className="relative">
className="bg-background p-0 w-full max-w-[320px] shadow-xl border-0 overflow-hidden border-l-4 border-l-red-600" <Card
> className="bg-background p-0 w-full max-w-[320px] shadow-xl border-0 overflow-hidden border-l-4 border-l-red-600"
<div className="p-4 relative"> >
{/* Custom close button */} <div className="p-4 relative">
<Button {/* Custom close button */}
variant="ghost" <Button
size="icon" variant="ghost"
className="absolute top-2 right-2 h-6 w-6 rounded-full bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700" size="icon"
onClick={onClose} className="absolute top-2 right-2 h-6 w-6 rounded-full bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700"
> onClick={onClose}
<X className="h-4 w-4" /> >
<span className="sr-only">Close</span> <X className="h-4 w-4" />
</Button> <span className="sr-only">Close</span>
</Button>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h3 className="font-bold text-base flex items-center gap-1.5"> <h3 className="font-bold text-base flex items-center gap-1.5">
<AlertTriangle className="h-4 w-4 text-red-500" /> <AlertTriangle className="h-4 w-4 text-red-500" />
{incident.category || "Unknown Incident"} {incident.category || "Unknown Incident"}
</h3> </h3>
</div>
{incident.description && (
<div className="mb-3 bg-slate-50 dark:bg-slate-900/40 p-3 rounded-lg">
<p className="text-sm">
<FileText className="inline-block h-3.5 w-3.5 mr-1.5 align-text-top text-slate-500" />
{incident.description}
</p>
</div> </div>
)}
<Separator className="my-3" /> {incident.description && (
<div className="mb-3 bg-slate-50 dark:bg-slate-900/40 p-3 rounded-lg">
<div className="grid grid-cols-2 gap-2 text-sm"> <p className="text-sm">
{incident.district && ( <FileText className="inline-block h-3.5 w-3.5 mr-1.5 align-text-top text-slate-500" />
<div className="col-span-2"> {incident.description}
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">District</p>
<p className="flex items-center">
<Bookmark className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-purple-500" />
<span className="font-medium">{incident.district}</span>
</p> </p>
</div> </div>
)} )}
{incident.date && ( <Separator className="my-3" />
<>
<div> <div className="grid grid-cols-2 gap-2 text-sm">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Date</p> {incident.district && (
<div className="col-span-2">
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">District</p>
<p className="flex items-center"> <p className="flex items-center">
<Calendar className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-blue-500" /> <Bookmark className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-purple-500" />
<span className="font-medium">{formatDate(incident.date)}</span> <span className="font-medium">{incident.district}</span>
</p> </p>
</div> </div>
<div> )}
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Time</p>
<p className="flex items-center">
<Clock className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-amber-500" />
<span className="font-medium">{formatTime(incident.date)}</span>
</p>
</div>
</>
)}
</div>
{/* Distances to police units section */} {incident.date && (
<Separator className="my-3" /> <>
<div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Date</p>
<p className="flex items-center">
<Calendar className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-blue-500" />
<span className="font-medium">{formatDate(incident.date)}</span>
</p>
</div>
<div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Time</p>
<p className="flex items-center">
<Clock className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-amber-500" />
<span className="font-medium">{formatTime(incident.date)}</span>
</p>
</div>
</>
)}
</div>
<div> {/* Distances to police units section */}
<h4 className="text-sm font-medium mb-2">Nearby Police Units</h4> <Separator className="my-3" />
{isLoadingDistances ? ( <div>
<div className="space-y-2"> <h4 className="text-sm font-medium mb-2">Nearby Police Units</h4>
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" /> {isLoadingDistances ? (
<Skeleton className="h-6 w-full" />
</div>
) : distances.length > 0 ? (
<ScrollArea className="h-[120px] rounded-md border p-2">
<div className="space-y-2"> <div className="space-y-2">
{distances.map((item) => ( <Skeleton className="h-6 w-full" />
<div key={item.unit_code} className="flex justify-between items-center text-xs border-b pb-1"> <Skeleton className="h-6 w-full" />
<div> <Skeleton className="h-6 w-full" />
<p className="font-medium">{item.unit_name || "Unknown Unit"}</p>
<p className="text-muted-foreground text-[10px]">
{item.unit_type || "Police Unit"}
</p>
</div>
<Badge variant="outline" className="ml-2">
{formatDistance(item.distance_meters)}
</Badge>
</div>
))}
</div> </div>
</ScrollArea> ) : distances.length > 0 ? (
) : ( <ScrollArea className="h-[120px] rounded-md border p-2">
<p className="text-xs text-muted-foreground text-center p-2"> <div className="space-y-2">
No police units data available {distances.map((item) => (
</p> <div key={item.unit_code} className="flex justify-between items-center text-xs border-b pb-1">
)} <div>
</div> <p className="font-medium">{item.unit_name || "Unknown Unit"}</p>
<p className="text-muted-foreground text-[10px]">
{item.unit_type || "Police Unit"}
</p>
</div>
<Badge variant="outline" className="ml-2">
{formatDistance(item.distance_meters)}
</Badge>
</div>
))}
</div>
</ScrollArea>
) : (
<p className="text-xs text-muted-foreground text-center p-2">
No police units data available
</p>
)}
</div>
<div className="mt-3 pt-3 border-t border-border"> <div className="mt-3 pt-3 border-t border-border">
<p className="text-xs text-muted-foreground flex items-center"> <p className="text-xs text-muted-foreground flex items-center">
<Navigation className="inline-block h-3 w-3 mr-1 shrink-0" /> <Navigation className="inline-block h-3 w-3 mr-1 shrink-0" />
Coordinates: {latitude.toFixed(6)}, {longitude.toFixed(6)} Coordinates: {latitude.toFixed(6)}, {longitude.toFixed(6)}
</p> </p>
<p className="text-xs text-muted-foreground mt-1">ID: {incident.id}</p> <p className="text-xs text-muted-foreground mt-1">ID: {incident.id}</p>
</div>
</div> </div>
</div> </Card>
</Card> {/* Connection line */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '2px',
height: '20px',
backgroundColor: 'red',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
{/* Connection dot */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '6px',
height: '6px',
backgroundColor: 'red',
borderRadius: '50%',
marginTop: '20px',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
</div>
</Popup> </Popup>
) )
} }

View File

@ -7,7 +7,6 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../..
import { Button } from "../../ui/button" import { Button } from "../../ui/button"
import { Badge } from "../../ui/badge" import { Badge } from "../../ui/badge"
interface TimelinePopupProps { interface TimelinePopupProps {
longitude: number longitude: number
latitude: number latitude: number
@ -63,60 +62,84 @@ export default function TimelinePopup({
className="z-10" className="z-10"
maxWidth="300px" maxWidth="300px"
> >
<Card className="border-0 shadow-none"> <div className="relative">
<CardHeader className="p-3 pb-2"> <Card className="border-0 shadow-none">
<div className="flex items-center justify-between"> <CardHeader className="p-3 pb-2">
<CardTitle className="text-base">{district.name}</CardTitle> <div className="flex items-center justify-between">
<Button <CardTitle className="text-base">{district.name}</CardTitle>
variant="ghost" <Button
size="icon" variant="ghost"
className="h-6 w-6" size="icon"
onClick={onClose} className="h-6 w-6"
> onClick={onClose}
<X className="h-4 w-4" /> >
</Button> <X className="h-4 w-4" />
</div> </Button>
<CardDescription className="text-xs">
Average incident time analysis
</CardDescription>
</CardHeader>
<CardContent className="p-3 pt-0">
<div className="mb-3">
<div className="flex items-center gap-2 mb-1">
<div className="text-xl font-bold font-mono">{district.formattedTime}</div>
<Badge variant="outline" className={`${getTimeOfDayColor(district.timeOfDay)}`}>
{district.timeDescription}
</Badge>
</div> </div>
<div className="text-xs text-muted-foreground"> <CardDescription className="text-xs">
Based on {district.totalIncidents} incidents Average incident time analysis
</CardDescription>
</CardHeader>
<CardContent className="p-3 pt-0">
<div className="mb-3">
<div className="flex items-center gap-2 mb-1">
<div className="text-xl font-bold font-mono">{district.formattedTime}</div>
<Badge variant="outline" className={`${getTimeOfDayColor(district.timeOfDay)}`}>
{district.timeDescription}
</Badge>
</div>
<div className="text-xs text-muted-foreground">
Based on {district.totalIncidents} incidents
</div>
</div> </div>
</div>
<div className="text-sm space-y-1 mb-3"> <div className="text-sm space-y-1 mb-3">
<div className="flex justify-between"> <div className="flex justify-between">
<span>Earliest incident:</span> <span>Earliest incident:</span>
<span className="font-medium">{district.earliestTime}</span> <span className="font-medium">{district.earliestTime}</span>
</div>
<div className="flex justify-between">
<span>Latest incident:</span>
<span className="font-medium">{district.latestTime}</span>
</div>
</div> </div>
<div className="flex justify-between">
<span>Latest incident:</span>
<span className="font-medium">{district.latestTime}</span>
</div>
</div>
<div className="border-t border-border pt-2"> <div className="border-t border-border pt-2">
<div className="text-xs font-medium mb-1">Top incident types:</div> <div className="text-xs font-medium mb-1">Top incident types:</div>
<div className="space-y-1"> <div className="space-y-1">
{topCategories.map(([category, count]) => ( {topCategories.map(([category, count]) => (
<div key={category} className="flex justify-between"> <div key={category} className="flex justify-between">
<span className="text-xs truncate mr-2">{category}</span> <span className="text-xs truncate mr-2">{category}</span>
<span className="text-xs font-semibold">{count}</span> <span className="text-xs font-semibold">{count}</span>
</div> </div>
))} ))}
</div>
</div> </div>
</div> </CardContent>
</CardContent> </Card>
</Card> {/* Connection line */}
<div
className="absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-full"
style={{
width: '2px',
height: '20px',
backgroundColor: 'red',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
{/* Connection dot */}
<div
className="absolute top-0 left-1/2 transform -translate-x-1/2 -translate-y-full"
style={{
width: '6px',
height: '6px',
backgroundColor: 'red',
borderRadius: '50%',
marginBottom: '20px',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
</div>
</Popup> </Popup>
) )
} }

View File

@ -56,112 +56,136 @@ export default function UnitPopup({
maxWidth="320px" maxWidth="320px"
className="unit-popup z-50" className="unit-popup z-50"
> >
<Card <div className="relative">
className="bg-background p-0 w-full max-w-[320px] shadow-xl border-0 overflow-hidden border-l-4 border-l-blue-700" <Card
> className="bg-background p-0 w-full max-w-[320px] shadow-xl border-0 overflow-hidden border-l-4 border-l-blue-700"
<div className="p-4 relative"> >
{/* Custom close button */} <div className="p-4 relative">
<Button {/* Custom close button */}
variant="ghost" <Button
size="icon" variant="ghost"
className="absolute top-2 right-2 h-6 w-6 rounded-full bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700" size="icon"
onClick={onClose} className="absolute top-2 right-2 h-6 w-6 rounded-full bg-slate-100 hover:bg-slate-200 dark:bg-slate-800 dark:hover:bg-slate-700"
> onClick={onClose}
<X className="h-4 w-4" /> >
<span className="sr-only">Close</span> <X className="h-4 w-4" />
</Button> <span className="sr-only">Close</span>
</Button>
<div className="flex items-center justify-between mb-3"> <div className="flex items-center justify-between mb-3">
<h3 className="font-bold text-base flex items-center gap-1.5"> <h3 className="font-bold text-base flex items-center gap-1.5">
<Shield className="h-4 w-4 text-blue-700" /> <Shield className="h-4 w-4 text-blue-700" />
{unit.name || "Police Unit"} {unit.name || "Police Unit"}
</h3> </h3>
<Badge variant="outline" className="bg-blue-100 text-blue-800 border-blue-200"> <Badge variant="outline" className="bg-blue-100 text-blue-800 border-blue-200">
{unit.type || "Unit"} {unit.type || "Unit"}
</Badge> </Badge>
</div> </div>
<div className="grid grid-cols-1 gap-2 text-sm"> <div className="grid grid-cols-1 gap-2 text-sm">
{unit.address && ( {unit.address && (
<div> <div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Address</p> <p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Address</p>
<p className="flex items-center"> <p className="flex items-center">
<MapPin className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-red-500" /> <MapPin className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-red-500" />
<span className="font-medium">{unit.address}</span> <span className="font-medium">{unit.address}</span>
</p> </p>
</div>
)}
{unit.phone && (
<div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Contact</p>
<p className="flex items-center">
<Phone className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-green-500" />
<span className="font-medium">{unit.phone}</span>
</p>
</div>
)}
{unit.district && (
<div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">District</p>
<p className="flex items-center">
<Building2 className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-purple-500" />
<span className="font-medium">{unit.district}</span>
</p>
</div>
)}
</div>
{/* Distances to incidents section */}
<Separator className="my-3" />
<div>
<h4 className="text-sm font-medium mb-2 flex items-center">
<Compass className="h-4 w-4 mr-1.5 text-blue-600" />
Nearby Incidents
</h4>
{isLoadingDistances ? (
<div className="space-y-2">
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
</div>
) : distances.length > 0 ? (
<ScrollArea className="h-[120px] rounded-md border p-2">
<div className="space-y-2">
{distances.map((item) => (
<div key={item.incident_id} className="flex justify-between items-center text-xs border-b pb-1">
<div>
<p className="font-medium">{item.category_name || "Unknown"}</p>
<p className="text-muted-foreground text-[10px] truncate" style={{ maxWidth: "160px" }}>
{item.incident_description || "No description"}
</p>
</div>
<Badge variant="outline" className="ml-2 whitespace-nowrap">
{formatDistance(item.distance_meters)}
</Badge>
</div>
))}
</div> </div>
</ScrollArea> )}
) : (
<p className="text-xs text-muted-foreground text-center p-2">
No incident data available
</p>
)}
</div>
<div className="mt-3 pt-3 border-t border-border"> {unit.phone && (
<p className="text-xs text-muted-foreground flex items-center"> <div>
<Navigation className="inline-block h-3 w-3 mr-1 shrink-0" /> <p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">Contact</p>
Coordinates: {latitude.toFixed(6)}, {longitude.toFixed(6)} <p className="flex items-center">
</p> <Phone className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-green-500" />
<p className="text-xs text-muted-foreground mt-1">ID: {unit.id}</p> <span className="font-medium">{unit.phone}</span>
</p>
</div>
)}
{unit.district && (
<div>
<p className="text-xs font-medium text-slate-500 dark:text-slate-400 mb-1">District</p>
<p className="flex items-center">
<Building2 className="inline-block h-3.5 w-3.5 mr-1.5 shrink-0 text-purple-500" />
<span className="font-medium">{unit.district}</span>
</p>
</div>
)}
</div>
{/* Distances to incidents section */}
<Separator className="my-3" />
<div>
<h4 className="text-sm font-medium mb-2 flex items-center">
<Compass className="h-4 w-4 mr-1.5 text-blue-600" />
Nearby Incidents
</h4>
{isLoadingDistances ? (
<div className="space-y-2">
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
<Skeleton className="h-6 w-full" />
</div>
) : distances.length > 0 ? (
<ScrollArea className="h-[120px] rounded-md border p-2">
<div className="space-y-2">
{distances.map((item) => (
<div key={item.incident_id} className="flex justify-between items-center text-xs border-b pb-1">
<div>
<p className="font-medium">{item.category_name || "Unknown"}</p>
<p className="text-muted-foreground text-[10px] truncate" style={{ maxWidth: "160px" }}>
{item.incident_description || "No description"}
</p>
</div>
<Badge variant="outline" className="ml-2 whitespace-nowrap">
{formatDistance(item.distance_meters)}
</Badge>
</div>
))}
</div>
</ScrollArea>
) : (
<p className="text-xs text-muted-foreground text-center p-2">
No incident data available
</p>
)}
</div>
<div className="mt-3 pt-3 border-t border-border">
<p className="text-xs text-muted-foreground flex items-center">
<Navigation className="inline-block h-3 w-3 mr-1 shrink-0" />
Coordinates: {latitude.toFixed(6)}, {longitude.toFixed(6)}
</p>
<p className="text-xs text-muted-foreground mt-1">ID: {unit.id}</p>
</div>
</div> </div>
</div> </Card>
</Card> {/* Connection line */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '2px',
height: '20px',
backgroundColor: 'red',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
{/* Connection dot */}
<div
className="absolute bottom-0 left-1/2 transform -translate-x-1/2 translate-y-full"
style={{
width: '6px',
height: '6px',
backgroundColor: 'red',
borderRadius: '50%',
marginTop: '20px',
boxShadow: '0 0 4px rgba(0, 0, 0, 0.3)'
}}
/>
</div>
</Popup> </Popup>
) )
} }

View File

@ -11,9 +11,9 @@ interface TimeZoneMarker {
} }
const TIME_ZONES: TimeZoneMarker[] = [ const TIME_ZONES: TimeZoneMarker[] = [
{ name: "WIB", offset: 7, longitude: 106.8456, latitude: -6.2088 }, // Jakarta { name: "WIB", offset: 7, longitude: 110.5, latitude: -3.3 }, // Between Java and Sumatra
{ name: "WITA", offset: 8, longitude: 115.1889, latitude: -8.4095 }, // Denpasar { name: "WITA", offset: 8, longitude: 118.8, latitude: -2.5 }, // Between Java and Kalimantan
{ name: "WIT", offset: 9, longitude: 140.7887, latitude: -2.5916 }, // Jayapura { name: "WIT", offset: 9, longitude: 128.0, latitude: -2.0 }, // Between Sulawesi and Papua
] ]
export default function TimeZonesDisplay() { export default function TimeZonesDisplay() {
@ -49,12 +49,19 @@ export default function TimeZonesDisplay() {
<> <>
{TIME_ZONES.map((zone) => ( {TIME_ZONES.map((zone) => (
<Marker key={zone.name} longitude={zone.longitude} latitude={zone.latitude}> <Marker key={zone.name} longitude={zone.longitude} latitude={zone.latitude}>
<div className="relative group"> <div className="relative">
<div className="absolute -translate-x-1/2 -translate-y-full mb-2 pointer-events-none"> <div className="absolute -translate-x-1/2 -translate-y-1/2 pointer-events-none">
<div className="bg-black/80 text-white px-2 py-1 rounded-md text-xs font-mono"> <div className="bg-black/90 border-2 border-orange-600/70 rounded-lg p-2 shadow-lg">
<div className="text-center font-bold">{zone.name}</div> <div className="text-center text-orange-500 text-xs font-bold">{zone.name} / GMT+{zone.offset}</div>
<div className="digital-clock">{currentTimes[zone.name] || "00:00:00"}</div> <div
<div className="text-center text-xs text-gray-300">GMT+{zone.offset}</div> className="digital-clock font-mono font-bold text-amber-500 text-xl md:text-2xl tracking-wider"
style={{
textShadow: '0 0 5px rgba(255,170,0,0.7)',
fontFamily: "'Digital', monospace"
}}
>
{currentTimes[zone.name] || "00:00:00"}
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -217,3 +217,16 @@
text-align: center; text-align: center;
color: #ccc; color: #ccc;
} }
/* Digital Clock Styling */
.digital-clock {
font-variant-numeric: tabular-nums;
letter-spacing: 0.05em;
background-color: rgba(0, 0, 0, 0.7);
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);
display: inline-block;
margin: 0.25rem 0;
}