diff --git a/assets/css/app.css b/assets/css/app.css index f3ba08d3..2ab1ed1c 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -105,4 +105,61 @@ /* Hide 1Password live region */ [id="1p-live-region"] { display: none !important; } +/* Page transition animation */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} +.page-fade-in { + animation: fadeIn 0.15s ease-out; +} + /* This file is for your main application CSS */ + +/* Smooth page transitions */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(4px); } + to { opacity: 1; transform: translateY(0); } +} +.page-fade-in { animation: fadeIn 0.15s ease-out; } + +/* Smooth transitions on interactive elements */ +.card, .btn, .badge, .alert { + transition: box-shadow 0.15s ease, transform 0.15s ease; +} + +/* Subtle hover lift on cards */ +.card-hover:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + transform: translateY(-1px); +} +@media (prefers-color-scheme: dark) { + .card-hover:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); + } +} + +/* Status pulse animation for live indicators */ +@keyframes statusPulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } +} +.status-pulse { animation: statusPulse 2s ease-in-out infinite; } + +/* Scrollbar styling for webkit */ +::-webkit-scrollbar { width: 6px; height: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.15); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.25); } +[data-theme="dark"] ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.15); } +[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.25); } + +/* Table row hover highlight */ +tbody tr:hover td { background-color: rgba(59, 130, 246, 0.04); } +[data-theme="dark"] tbody tr:hover td { background-color: rgba(59, 130, 246, 0.08); } + +/* Focus ring styling */ +:focus-visible { + outline: 2px solid oklch(58% 0.233 277.117); + outline-offset: 2px; +} diff --git a/lib/towerops_web.ex b/lib/towerops_web.ex index 1a839f20..ff42afaa 100644 --- a/lib/towerops_web.ex +++ b/lib/towerops_web.ex @@ -84,6 +84,7 @@ defmodule ToweropsWeb do import Phoenix.HTML import ToweropsWeb.CoreComponents + import ToweropsWeb.Components.Skeletons import ToweropsWeb.GettextHelpers # HTML escaping functionality diff --git a/lib/towerops_web/components/breadcrumbs.ex b/lib/towerops_web/components/breadcrumbs.ex new file mode 100644 index 00000000..cb24c454 --- /dev/null +++ b/lib/towerops_web/components/breadcrumbs.ex @@ -0,0 +1,50 @@ +defmodule ToweropsWeb.Components.Breadcrumbs do + @moduledoc """ + Reusable breadcrumb navigation component using DaisyUI. + """ + use Phoenix.Component + + import ToweropsWeb.CoreComponents, only: [icon: 1] + + @doc """ + Renders a breadcrumb navigation bar. + + Each item in `items` should be a map with: + - `:label` (required) — the display text + - `:navigate` (optional) — path for navigation; omit for the current (last) page + + ## Examples + + <.breadcrumb items={[ + %{label: "Dashboard", navigate: ~p"/dashboard"}, + %{label: "Devices", navigate: ~p"/devices"}, + %{label: "My Device"} + ]} /> + """ + attr :items, :list, required: true + + def breadcrumb(assigns) do + ~H""" +
+ """ + end +end diff --git a/lib/towerops_web/components/layouts.ex b/lib/towerops_web/components/layouts.ex index 98429368..f3512066 100644 --- a/lib/towerops_web/components/layouts.ex +++ b/lib/towerops_web/components/layouts.ex @@ -457,7 +457,7 @@ defmodule ToweropsWeb.Layouts do -