- Replace gray->cool-steel, blue/indigo->cerulean, red->sweet-salmon, yellow/amber->wheat - Dark sidebar: sidebar/footer use cool-steel-800 bg, text lightened for contrast - ~11,600 color replacements across ~99 files - Update tests for new color class names
178 lines
7.1 KiB
Text
178 lines
7.1 KiB
Text
<Layouts.authenticated
|
|
flash={@flash}
|
|
current_scope={@current_scope}
|
|
active_page="sites-map"
|
|
unresolved_alert_count={assigns[:unresolved_alert_count] || 0}
|
|
>
|
|
<.header>
|
|
<span class="flex items-center gap-2">
|
|
{t("Sites Map")}
|
|
<span class="inline-flex items-center rounded-full bg-cerulean-50 px-2 py-0.5 text-xs font-medium text-cerulean-700 ring-1 ring-inset ring-cerulean-700/10 dark:bg-cerulean-400/10 dark:text-cerulean-400 dark:ring-cerulean-400/30">
|
|
{t("Geographic")}
|
|
</span>
|
|
</span>
|
|
<:subtitle>{t("Geographic locations of your sites")}</:subtitle>
|
|
<:actions>
|
|
<.button phx-click="refresh_map">
|
|
<.icon name="hero-arrow-path" class="h-5 w-5" /> Refresh
|
|
</.button>
|
|
<.button navigate={~p"/sites/new"} variant="primary">
|
|
<.icon name="hero-plus" class="h-5 w-5" /> Add Site
|
|
</.button>
|
|
</:actions>
|
|
</.header>
|
|
|
|
<div class="mb-6">
|
|
<div class="bg-white dark:bg-cool-steel-800 rounded-lg border border-cool-steel-200 dark:border-white/10 overflow-hidden">
|
|
<div class="p-4 border-b border-cool-steel-200 dark:border-white/10">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h3 class="text-sm font-medium text-cool-steel-900 dark:text-white">
|
|
{t("Geographic Site Locations")}
|
|
</h3>
|
|
<p class="mt-1 text-xs text-cool-steel-500 dark:text-cool-steel-400">
|
|
{t("Click markers to view site details")}
|
|
</p>
|
|
</div>
|
|
<div class="flex items-center space-x-2">
|
|
<span class="text-xs text-cool-steel-500 dark:text-cool-steel-400">
|
|
Showing {length(@sites)} sites with coordinates
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Map Container -->
|
|
<div
|
|
id="leaflet-map"
|
|
phx-hook="SitesMap"
|
|
phx-update="ignore"
|
|
class="w-full"
|
|
style="height: 600px;"
|
|
data-sites={Jason.encode!(@sites)}
|
|
>
|
|
<!-- Loading State -->
|
|
<div class="flex items-center justify-center h-full">
|
|
<div class="text-center">
|
|
<.icon
|
|
name="hero-arrow-path"
|
|
class="h-8 w-8 text-cool-steel-400 animate-spin mx-auto"
|
|
/>
|
|
<p class="mt-2 text-sm text-cool-steel-600 dark:text-cool-steel-400">
|
|
Loading map...
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats and Site List -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<!-- Site Statistics -->
|
|
<div class="bg-white dark:bg-cool-steel-800 rounded-lg border border-cool-steel-200 dark:border-white/10 p-6">
|
|
<h3 class="text-lg font-medium text-cool-steel-900 dark:text-white mb-4">
|
|
{t("Statistics")}
|
|
</h3>
|
|
<div class="space-y-4">
|
|
<div>
|
|
<div class="text-sm font-medium text-cool-steel-500 dark:text-cool-steel-400">
|
|
Total Sites
|
|
</div>
|
|
<div class="text-2xl font-semibold text-cool-steel-900 dark:text-white">
|
|
{Sites.count_organization_sites(@organization.id)}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="text-sm font-medium text-cool-steel-500 dark:text-cool-steel-400">
|
|
Geocoded Sites
|
|
</div>
|
|
<div class="text-2xl font-semibold text-cool-steel-900 dark:text-white">
|
|
{length(@sites)}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="text-sm font-medium text-cool-steel-500 dark:text-cool-steel-400">
|
|
Coverage
|
|
</div>
|
|
<div class="text-lg font-semibold text-cool-steel-900 dark:text-white">
|
|
<%= if Sites.count_organization_sites(@organization.id) > 0 do %>
|
|
{round(length(@sites) / Sites.count_organization_sites(@organization.id) * 100)}%
|
|
<% else %>
|
|
0%
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sites with Coordinates -->
|
|
<div class="lg:col-span-2 bg-white dark:bg-cool-steel-800 rounded-lg border border-cool-steel-200 dark:border-white/10">
|
|
<div class="px-6 py-4 border-b border-cool-steel-200 dark:border-white/10">
|
|
<h3 class="text-lg font-medium text-cool-steel-900 dark:text-white">
|
|
{t("Sites with Geographic Data")}
|
|
</h3>
|
|
</div>
|
|
<div class="max-h-96 overflow-y-auto">
|
|
<%= if length(@sites) > 0 do %>
|
|
<div class="divide-y divide-cool-steel-200 dark:divide-white/10">
|
|
<%= for site <- @sites do %>
|
|
<div class="px-6 py-4 hover:bg-cool-steel-50 dark:hover:bg-cool-steel-700/50">
|
|
<div class="flex items-start justify-between">
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center">
|
|
<h4 class="text-sm font-medium text-cool-steel-900 dark:text-white truncate">
|
|
{site.name}
|
|
</h4>
|
|
<%= if site.device_count > 0 do %>
|
|
<span class="ml-2 inline-flex items-center rounded-full bg-cerulean-100 px-2 py-0.5 text-xs font-medium text-cerulean-700 dark:bg-cerulean-900 dark:text-cerulean-300">
|
|
{site.device_count} devices
|
|
</span>
|
|
<% end %>
|
|
</div>
|
|
<%= if site.address do %>
|
|
<p class="mt-1 text-sm text-cool-steel-500 dark:text-cool-steel-400">
|
|
{site.address}
|
|
</p>
|
|
<% end %>
|
|
<%= if site.description do %>
|
|
<p class="mt-1 text-sm text-cool-steel-500 dark:text-cool-steel-400">
|
|
{site.description}
|
|
</p>
|
|
<% end %>
|
|
<p class="mt-1 text-xs text-cool-steel-400">
|
|
{Float.round(site.latitude, 4)}, {Float.round(site.longitude, 4)}
|
|
</p>
|
|
</div>
|
|
<div class="ml-4">
|
|
<.link
|
|
navigate={~p"/sites/#{site.id}"}
|
|
class="text-cerulean-600 hover:text-cerulean-500 dark:text-cerulean-400 dark:hover:text-cerulean-300 text-sm font-medium"
|
|
>
|
|
View →
|
|
</.link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
<% else %>
|
|
<div class="px-6 py-8 text-center">
|
|
<.icon name="hero-map-pin" class="mx-auto h-12 w-12 text-cool-steel-400" />
|
|
<h3 class="mt-2 text-sm font-medium text-cool-steel-900 dark:text-white">
|
|
{t("No geocoded sites")}
|
|
</h3>
|
|
<p class="mt-1 text-sm text-cool-steel-500 dark:text-cool-steel-400">
|
|
{t("Add addresses and coordinates to your sites to see them on the map.")}
|
|
</p>
|
|
<div class="mt-4">
|
|
<.button navigate={~p"/sites"}>
|
|
{t("Manage Sites")}
|
|
</.button>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Layouts.authenticated>
|