Packages
phoenix_kit
1.7.23
1.7.210
1.7.209
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit_web/components/layouts/dashboard.html.heex
<%!--
PhoenixKit User Dashboard Layout
This layout is specifically designed for authenticated user dashboard pages.
It provides a clean interface for regular users to view their profile and activities.
Features:
- Dynamic tab navigation from PhoenixKit.Dashboard.Registry
- Support for custom tabs via config or runtime registration
- Real-time badge updates via PubSub
- Presence tracking for viewer counts
- Attention animations for important tabs
- Mobile-friendly navigation
Note: This layout does NOT use LayoutWrapper.app_layout as that's for admin pages only.
--%>
<% project_title = assigns[:project_title] || PhoenixKit.Config.get(:project_title, "PhoenixKit") %>
<% # Get tabs from registry (with active state based on current path)
dashboard_tabs =
assigns[:dashboard_tabs] ||
PhoenixKit.Dashboard.Registry.get_tabs_with_active(
assigns[:url_path] || "/dashboard",
scope: assigns[:phoenix_kit_current_scope]
)
# Get viewer counts if presence is enabled
viewer_counts = assigns[:tab_viewer_counts] || %{}
# Get collapsed groups
collapsed_groups = assigns[:collapsed_dashboard_groups] || MapSet.new()
# Get context selector data (may be nil if not configured)
show_context_selector = assigns[:show_context_selector] || false
dashboard_contexts = assigns[:dashboard_contexts] || []
current_context = assigns[:current_context]
context_selector_config =
assigns[:context_selector_config] || %PhoenixKit.Dashboard.ContextSelector{enabled: false} %> <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={Plug.CSRFProtection.get_csrf_token()} />
<meta name="phoenix-kit-prefix" content={PhoenixKit.Utils.Routes.url_prefix()} />
<.live_title default={"#{project_title} Dashboard"}>
{assigns[:page_title] || "Dashboard"}
</.live_title>
<link phx-track-static rel="stylesheet" href="/assets/css/app.css" />
<%!-- Dashboard animations CSS --%>
<style>
/* Shake animation for attention */
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-2px); }
20%, 40%, 60%, 80% { transform: translateX(2px); }
}
.animate-shake { animation: shake 0.5s ease-in-out; }
/* Glow animation for highlighting */
@keyframes glow {
0%, 100% { box-shadow: 0 0 5px currentColor; }
50% { box-shadow: 0 0 20px currentColor; }
}
.animate-glow { animation: glow 2s ease-in-out infinite; }
/* Badge pop animation */
@keyframes badge-pop {
0% { transform: scale(0); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.animate-badge-pop { animation: badge-pop 0.3s ease-out; }
/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}
</style>
</head>
<body class="bg-base-100 antialiased">
<div class="min-h-screen bg-base-100">
<%!-- User Dashboard Header --%>
<header class="bg-base-100 shadow-sm border-b border-base-300 fixed top-0 left-0 right-0 z-50">
<div class="flex items-center justify-between h-16 px-4">
<%!-- Left: Logo and Title --%>
<div class="flex items-center gap-3">
<.link
navigate="/"
class="flex items-center gap-3 hover:opacity-80 transition-opacity"
>
<div class="w-8 h-8 bg-primary rounded-lg flex items-center justify-center">
<.icon name="hero-home" class="w-5 h-5 text-primary-content" />
</div>
<span class="font-bold text-base-content hidden sm:inline">
{gettext("%{project_title} Dashboard", project_title: project_title)}
</span>
</.link>
<%!-- Context Selector (header start - after logo) --%>
<%= if show_context_selector and context_selector_config.position == :header and context_selector_config.sub_position == :start do %>
<div class="hidden sm:flex items-center">
<%= if context_selector_config.separator do %>
<span class="text-base-content/30 mx-2">
{context_selector_config.separator}
</span>
<% end %>
<PhoenixKitWeb.Components.Dashboard.ContextSelector.context_selector
contexts={dashboard_contexts}
current={current_context}
config={context_selector_config}
/>
</div>
<% end %>
</div>
<%!-- Right: User Dropdown --%>
<div class="flex items-center gap-3">
<%!-- Context Selector (header end - before user menu) --%>
<%= if show_context_selector and context_selector_config.position == :header and context_selector_config.sub_position == :end do %>
<PhoenixKitWeb.Components.Dashboard.ContextSelector.context_selector
contexts={dashboard_contexts}
current={current_context}
config={context_selector_config}
class="hidden sm:flex"
/>
<% end %>
<PhoenixKitWeb.Components.UserDashboardNav.user_dropdown
scope={assigns[:phoenix_kit_current_scope]}
current_path={assigns[:url_path] || "/dashboard"}
current_locale={assigns[:current_locale]}
/>
</div>
</div>
</header>
<%!-- Main Content Area --%>
<div class="pt-16">
<div class="flex">
<%!-- Left Sidebar Navigation (Desktop) --%>
<aside class="w-64 h-[calc(100vh-4rem)] bg-base-100 border-r border-base-300 hidden lg:flex flex-col sticky top-16">
<div class="p-4 flex-1">
<PhoenixKitWeb.Components.Dashboard.Sidebar.dashboard_sidebar
current_path={assigns[:url_path] || "/dashboard"}
scope={assigns[:phoenix_kit_current_scope]}
locale={assigns[:current_locale_base]}
tabs={dashboard_tabs}
viewer_counts={viewer_counts}
collapsed_groups={collapsed_groups}
show_context_selector={show_context_selector}
dashboard_contexts={dashboard_contexts}
current_context={current_context}
context_selector_config={context_selector_config}
/>
</div>
<%!-- Bottom Context Selector (when sub_position: :end) --%>
<%= if show_context_selector and context_selector_config && context_selector_config.enabled and context_selector_config.position == :sidebar and context_selector_config.sub_position == :end do %>
<div class="p-4 border-t border-base-300 mt-auto">
<PhoenixKitWeb.Components.Dashboard.ContextSelector.sidebar_context_selector
contexts={dashboard_contexts}
current={current_context}
config={context_selector_config}
/>
</div>
<% end %>
</aside>
<%!-- Mobile FAB Menu --%>
<PhoenixKitWeb.Components.Dashboard.Sidebar.mobile_fab_menu
current_path={assigns[:url_path] || "/dashboard"}
scope={assigns[:phoenix_kit_current_scope]}
locale={assigns[:current_locale_base]}
show_context_selector={show_context_selector}
dashboard_contexts={dashboard_contexts}
current_context={current_context}
context_selector_config={context_selector_config}
/>
<%!-- Main Content --%>
<main class="flex-1 px-4 py-8">
<div class="max-w-6xl mx-auto">
{render_slot(@inner_block)}
</div>
</main>
</div>
</div>
</div>
</body>
</html>