-
- <.icon name="hero-server" class="h-4 w-4" /> Devices
-
-
- {format_number(@site_summary.device_count)}
- <%= if @site_summary.devices_down > 0 do %>
-
- ({@site_summary.devices_down} down)
-
- <% end %>
-
+
+
+ <.icon name="hero-server" class="h-4 w-4" /> {t("Devices")}
+
+ {format_number(@site_summary.device_count)}
+ <%= if @site_summary.devices_down > 0 do %>
+
+ ({@site_summary.devices_down} {t("down")})
+
+ <% end %>
+
<%!-- Active Alerts --%>
-
-
-
- <.icon name="hero-bell-alert" class="h-4 w-4" /> Active Alerts
-
-
- {length(@active_alerts)}
-
+
0,
+ do: "border-red-200 dark:border-red-900/50",
+ else: "border-gray-200 dark:border-white/10"
+ )
+ ]}>
+
+ <.icon name="hero-bell-alert" class="h-4 w-4" /> {t("Active Alerts")}
+
0,
+ do: "text-red-600 dark:text-red-400",
+ else: "text-gray-900 dark:text-white"
+ )
+ ]}>
+ {length(@active_alerts)}
+
@@ -145,9 +161,11 @@
<%!-- Left Column --%>
<%!-- Site Details --%>
-
-
-
{t("Site Details")}
+
+
+
+ {t("Site Details")}
+
<%= if @site.parent_site do %>
@@ -193,12 +211,14 @@
<%!-- Active Alerts Panel --%>
-
-
-
+
+
+
<.icon name="hero-bell-alert" class="h-5 w-5" /> Active Alerts
<%= if @active_alerts != [] do %>
- {length(@active_alerts)}
+
+ {length(@active_alerts)}
+
<% end %>
<%= if @active_alerts == [] do %>
@@ -210,7 +230,7 @@
<.icon
name={insight_urgency_icon(alert_severity(alert.alert_type))}
@@ -232,9 +252,9 @@
<%!-- Recent Config Changes Panel --%>
-
-
-
+
+
+
<.icon name="hero-document-text" class="h-5 w-5" /> Recent Config Changes
<%= if @config_changes == [] do %>
@@ -245,7 +265,7 @@
@@ -268,10 +288,10 @@
<%!-- Right Column --%>
<%!-- Device Health Grid --%>
-
-
+
+
-
+
<.icon name="hero-server" class="h-5 w-5" /> Device Health
<.button
@@ -283,7 +303,7 @@
<%= if @device == [] do %>
-
+
<.icon
name="hero-server"
class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500"
@@ -301,23 +321,49 @@
<% else %>
-
- <.link
- :for={eq <- @device}
- navigate={~p"/devices/#{eq.id}"}
- class="flex items-center gap-3 rounded-lg border border-base-300 p-3 hover:bg-base-200 transition-colors cursor-pointer"
- >
-
-
-
- {eq.name}
-
-
{eq.ip_address}
-
-
- {format_response_time(@response_times[eq.id])}
-
-
+
+
+
+
+ {t("Device")}
+ {t("IP Address")}
+ {t("Latency")}
+
+
+
+
+
+
+
+
+ {eq.name}
+
+
+
+
+ {eq.ip_address}
+
+ "text-gray-400"
+ ms when ms < 50 -> "text-green-600 dark:text-green-400"
+ ms when ms < 200 -> "text-yellow-600 dark:text-yellow-400"
+ _ -> "text-red-600 dark:text-red-400"
+ end
+ ]}>
+ {format_response_time(@response_times[eq.id])}
+
+
+
+
<% end %>
@@ -325,15 +371,15 @@
<%!-- Insights Panel --%>
<%= if @insights != [] do %>
-
-
-
+
+
+
<.icon name="hero-light-bulb" class="h-5 w-5" /> Preseem Insights
<.icon
name={insight_urgency_icon(insight.urgency)}
@@ -358,22 +404,30 @@
<%!-- Latency Chart --%>
<%= if @latency_chart_data do %>
-
-
-
- <.icon name="hero-chart-bar" class="h-5 w-5" /> Site Latency — Last 24 Hours
+
+
+
+ <.icon name="hero-chart-bar" class="h-4 w-4" /> {t("Site Latency — Last 24 Hours")}
-
-
-
+
+
+
+
+
+
+
+
{t("Loading chart...")}
+
+
diff --git a/lib/towerops_web/live/user_settings_live.html.heex b/lib/towerops_web/live/user_settings_live.html.heex
index 201c5f4c..167d9ee3 100644
--- a/lib/towerops_web/live/user_settings_live.html.heex
+++ b/lib/towerops_web/live/user_settings_live.html.heex
@@ -11,95 +11,108 @@
-
-
-
+
+ <.link
+ patch={~p"/users/settings?tab=personal"}
+ class={[
+ "whitespace-nowrap py-4 px-1 border-b-2 text-sm transition-colors",
+ if(@active_tab == "personal",
+ do: "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-semibold",
+ else:
+ "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 font-medium"
+ )
+ ]}
>
-
- <.link
- patch={~p"/users/settings?tab=personal"}
- class={
- if @active_tab == "personal",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
- >
- {t("Personal")}
-
-
-
- <.link
- patch={~p"/users/settings?tab=account"}
- class={
- if @active_tab == "account",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
- >
- {t("Account")}
-
-
-
- <.link
- patch={~p"/users/settings?tab=sessions"}
- class={
- if @active_tab == "sessions",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
- >
- {t("Sessions")}
-
-
-
- <.link
- patch={~p"/users/settings?tab=api"}
- class={
- if @active_tab == "api",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
- >
- {t("API")}
-
-
-
- <.link
- patch={~p"/users/settings?tab=notifications"}
- class={
- if @active_tab == "notifications",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
- >
- {t("Notifications")}
-
-
-
- <.link
- patch={~p"/users/settings?tab=security"}
- class={
- if @active_tab == "security",
- do: "text-indigo-600 dark:text-indigo-400",
- else: ""
- }
- >
- {t("Security")}
-
-
-
- <.link
- navigate={~p"/users/my-data"}
- class="text-gray-500 hover:text-indigo-600 dark:text-gray-400 dark:hover:text-indigo-400"
- >
- {t("My Data")}
-
-
-
+
+ <.icon name="hero-user" class="h-4 w-4" /> {t("Personal")}
+
+
+ <.link
+ patch={~p"/users/settings?tab=account"}
+ class={[
+ "whitespace-nowrap py-4 px-1 border-b-2 text-sm transition-colors",
+ if(@active_tab == "account",
+ do: "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-semibold",
+ else:
+ "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 font-medium"
+ )
+ ]}
+ >
+
+ <.icon name="hero-envelope" class="h-4 w-4" /> {t("Account")}
+
+
+ <.link
+ patch={~p"/users/settings?tab=sessions"}
+ class={[
+ "whitespace-nowrap py-4 px-1 border-b-2 text-sm transition-colors",
+ if(@active_tab == "sessions",
+ do: "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-semibold",
+ else:
+ "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 font-medium"
+ )
+ ]}
+ >
+
+ <.icon name="hero-computer-desktop" class="h-4 w-4" /> {t("Sessions")}
+
+
+ <.link
+ patch={~p"/users/settings?tab=api"}
+ class={[
+ "whitespace-nowrap py-4 px-1 border-b-2 text-sm transition-colors",
+ if(@active_tab == "api",
+ do: "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-semibold",
+ else:
+ "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 font-medium"
+ )
+ ]}
+ >
+
+ <.icon name="hero-code-bracket" class="h-4 w-4" /> {t("API")}
+
+
+ <.link
+ patch={~p"/users/settings?tab=notifications"}
+ class={[
+ "whitespace-nowrap py-4 px-1 border-b-2 text-sm transition-colors",
+ if(@active_tab == "notifications",
+ do: "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-semibold",
+ else:
+ "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 font-medium"
+ )
+ ]}
+ >
+
+ <.icon name="hero-bell" class="h-4 w-4" /> {t("Notifications")}
+
+
+ <.link
+ patch={~p"/users/settings?tab=security"}
+ class={[
+ "whitespace-nowrap py-4 px-1 border-b-2 text-sm transition-colors",
+ if(@active_tab == "security",
+ do: "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-semibold",
+ else:
+ "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 font-medium"
+ )
+ ]}
+ >
+
+ <.icon name="hero-shield-check" class="h-4 w-4" /> {t("Security")}
+
+
+ <.link
+ navigate={~p"/users/my-data"}
+ class="whitespace-nowrap py-4 px-1 border-b-2 border-transparent text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300 transition-colors"
+ >
+
+ <.icon name="hero-arrow-down-tray" class="h-4 w-4" /> {t("My Data")}
+
+
-
+
@@ -777,27 +790,38 @@
<%= for session <- @browser_sessions do %>
<% is_current = current_session?(session, get_current_token_id(assigns)) %>
-
-
-
- {format_browser_info(session)}
-
- <%= if is_current do %>
-
- {t("Current Session")}
-
+
+
+ <%= if String.contains?(String.downcase(session.user_agent || ""), ["mobile", "android", "iphone", "ipad"]) do %>
+ <.icon name="hero-device-phone-mobile" class="h-6 w-6 text-gray-400" />
+ <% else %>
+ <.icon name="hero-computer-desktop" class="h-6 w-6 text-gray-400" />
<% end %>
-
-
- <.icon name="hero-map-pin" class="h-3 w-3" />
-
{format_location(session)}
-
•
-
{session.ip_address}
+
+
+
+ {format_browser_info(session)}
+
+ <%= if is_current do %>
+
+ {t("Current Session")}
+
+ <% end %>
-
- <.icon name="hero-clock" class="h-3 w-3" />
-
Last active {format_relative_time(session.last_activity_at)}
+
+
+ <.icon name="hero-map-pin" class="h-3 w-3" />
+ {format_location(session)}
+ •
+ {session.ip_address}
+
+
+ <.icon name="hero-clock" class="h-3 w-3" />
+
+ Last active {format_relative_time(session.last_activity_at)}
+
+
@@ -1572,12 +1596,35 @@
>
{t("Scan QR Code")}
-
-
- {t(
- "Scan this QR code with your authenticator app (Google Authenticator, Authy, 1Password, etc.)."
- )}
-
+
+
+
+
+ 1
+
+
+ {t(
+ "Install an authenticator app (Google Authenticator, Authy, 1Password, etc.)"
+ )}
+
+
+
+
+ 2
+
+
+ {t("Scan the QR code below with your authenticator app")}
+
+
+
+
+ 3
+
+
+ {t("Enter the 6-digit code from your app to verify setup")}
+
+
+