towerops/lib/towerops_web/live/map_live/index.html.heex
Graham McIntire 5a7cdc7138 refactor: apply custom color palette across entire codebase
- 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
2026-06-23 10:58:48 -05:00

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>