diff --git a/assets/js/app.ts b/assets/js/app.ts
index 323b417f..74d2cd86 100644
--- a/assets/js/app.ts
+++ b/assets/js/app.ts
@@ -885,35 +885,50 @@ const NetworkMap = {
}
}
-// Dynamic Favicon - alternates favicon between status indicator SVGs
+// Dynamic Favicon - sets favicon color based on data-status from LiveView
const DynamicFavicon = {
- interval: null as ReturnType | null,
- isGreen: true,
+ statusColors: { green: '#22c55e', yellow: '#eab308', red: '#ef4444' } as Record,
+ cache: {} as Record,
+ originalHref: null as string | null,
- mounted(this: any) {
- const greenSvg = ``
- const redSvg = ``
-
- const greenDataUri = 'data:image/svg+xml,' + encodeURIComponent(greenSvg)
- const redDataUri = 'data:image/svg+xml,' + encodeURIComponent(redSvg)
+ getFaviconPng(this: any, status: string): string {
+ if (this.cache[status]) return this.cache[status]
+ const color = this.statusColors[status] || this.statusColors.green
+ const canvas = document.createElement('canvas')
+ canvas.width = 64
+ canvas.height = 64
+ const ctx = canvas.getContext('2d')!
+ ctx.beginPath()
+ ctx.arc(32, 32, 32, 0, Math.PI * 2)
+ ctx.fillStyle = color
+ ctx.fill()
+ this.cache[status] = canvas.toDataURL('image/png')
+ return this.cache[status]
+ },
+ applyStatus(this: any) {
const faviconEl = document.getElementById('favicon') as HTMLLinkElement
if (!faviconEl) return
+ const status = this.el.dataset.status || 'green'
+ faviconEl.type = 'image/png'
+ faviconEl.href = this.getFaviconPng(status)
+ },
- this.isGreen = true
- faviconEl.type = 'image/svg+xml'
- faviconEl.href = greenDataUri
+ mounted(this: any) {
+ const faviconEl = document.getElementById('favicon') as HTMLLinkElement
+ if (faviconEl) this.originalHref = faviconEl.href
+ this.applyStatus()
+ },
- this.interval = setInterval(() => {
- this.isGreen = !this.isGreen
- faviconEl.href = this.isGreen ? greenDataUri : redDataUri
- }, 1000)
+ updated(this: any) {
+ this.applyStatus()
},
destroyed(this: any) {
- if (this.interval) {
- clearInterval(this.interval)
- this.interval = null
+ const faviconEl = document.getElementById('favicon') as HTMLLinkElement
+ if (faviconEl && this.originalHref) {
+ faviconEl.type = 'image/png'
+ faviconEl.href = this.originalHref
}
}
}
diff --git a/lib/towerops_web/controllers/user_session_html/new.html.heex b/lib/towerops_web/controllers/user_session_html/new.html.heex
index 9fd0d0ba..2f888bdf 100644
--- a/lib/towerops_web/controllers/user_session_html/new.html.heex
+++ b/lib/towerops_web/controllers/user_session_html/new.html.heex
@@ -65,7 +65,12 @@
{t_auth("You are running the local mail adapter.")}
- <%= t_auth("To see sent emails, visit %{link}.", link: raw(~s(#{t_auth("the mailbox page")}))) %>
+ {t_auth("To see sent emails, visit %{link}.",
+ link:
+ raw(
+ ~s(#{t_auth("the mailbox page")})
+ )
+ )}
diff --git a/lib/towerops_web/live/dashboard_live.ex b/lib/towerops_web/live/dashboard_live.ex
index 76c9d32a..da200b8e 100644
--- a/lib/towerops_web/live/dashboard_live.ex
+++ b/lib/towerops_web/live/dashboard_live.ex
@@ -156,6 +156,7 @@ defmodule ToweropsWeb.DashboardLive do
|> assign(:uptime_percentage, uptime_percentage)
|> assign(:recent_activity, recent_activity)
|> assign(:last_updated, DateTime.utc_now())
+ |> assign(:favicon_status, favicon_status(Map.get(status_counts, :down, 0), length(active_alerts)))
|> load_insights(organization_id)
|> load_recent_config_changes(organization_id)
end
@@ -185,6 +186,10 @@ defmodule ToweropsWeb.DashboardLive do
assign(socket, :insights, insights)
end
+ defp favicon_status(devices_down, _alert_count) when devices_down > 0, do: "red"
+ defp favicon_status(_devices_down, alert_count) when alert_count > 0, do: "yellow"
+ defp favicon_status(_devices_down, _alert_count), do: "green"
+
defp health_score_color(score) when score > 80, do: "text-green-600 dark:text-green-400"
defp health_score_color(score) when score > 50, do: "text-yellow-600 dark:text-yellow-400"
defp health_score_color(_score), do: "text-red-600 dark:text-red-400"
diff --git a/lib/towerops_web/live/dashboard_live.html.heex b/lib/towerops_web/live/dashboard_live.html.heex
index 72823402..5f412f52 100644
--- a/lib/towerops_web/live/dashboard_live.html.heex
+++ b/lib/towerops_web/live/dashboard_live.html.heex
@@ -3,7 +3,8 @@
current_scope={@current_scope}
active_page="dashboard"
>
-
+
+
<%!-- ═══════════════════════════════════════════════
NOC HEADER — dense, zero chrome
═══════════════════════════════════════════════ --%>