diff --git a/.dialyzer_ignore.exs b/.dialyzer_ignore.exs index 2ca332265..ffa9e4def 100644 --- a/.dialyzer_ignore.exs +++ b/.dialyzer_ignore.exs @@ -5,7 +5,7 @@ {"lib/mix/tasks/phoenix_kit.install.ex", :unknown_function}, {"lib/mix/tasks/phoenix_kit.update.ex", :unknown_function}, {"lib/mix/tasks/phoenix_kit.gen.admin_page.ex", :unknown_function}, - {"lib/mix/tasks/phoenix_kit.gen.dashboard_tab.ex", :unknown_function}, + {"lib/mix/tasks/phoenix_kit.gen.user.dashboard.ex", :unknown_function}, # Conditional compilation pattern match in update.ex (Code.ensure_loaded?) {"lib/mix/tasks/phoenix_kit.update.ex", :pattern_match, 1}, {"lib/mix/tasks/phoenix_kit.modernize_layouts.ex", :unknown_function}, @@ -22,7 +22,7 @@ {"lib/mix/tasks/phoenix_kit.install.ex", :callback_info_missing, 2}, {"lib/mix/tasks/phoenix_kit.update.ex", :callback_info_missing, 3}, {"lib/mix/tasks/phoenix_kit.gen.admin_page.ex", :callback_info_missing}, - {"lib/mix/tasks/phoenix_kit.gen.dashboard_tab.ex", :callback_info_missing}, + {"lib/mix/tasks/phoenix_kit.gen.user.dashboard.ex", :callback_info_missing}, {"lib/mix/tasks/phoenix_kit.modernize_layouts.ex", :callback_info_missing, 1}, {"lib/mix/tasks/phoenix_kit.assets.rebuild.ex", :callback_info_missing, 1}, {"lib/mix/tasks/phoenix_kit.status.ex", :callback_info_missing, 1}, diff --git a/lib/mix/tasks/phoenix_kit.gen.dashboard_tab.ex b/lib/mix/tasks/phoenix_kit.gen.dashboard_tab.ex deleted file mode 100644 index e4cba50a8..000000000 --- a/lib/mix/tasks/phoenix_kit.gen.dashboard_tab.ex +++ /dev/null @@ -1,254 +0,0 @@ -defmodule Mix.Tasks.PhoenixKit.Gen.DashboardTab do - @moduledoc """ - Igniter task that adds a tab to the user dashboard configuration. - - ## Usage - - mix phoenix_kit.gen.dashboard_tab "Category Name" "Tab Title" --url="/dashboard/path" - - ## Arguments - - - `category` - The category name (e.g., "Farm Management") - - `tab_title` - The display title for the tab - - ## Options - - - `--url` - The URL path for the tab (required) - - `--icon` - Heroicon name for the tab (optional, defaults to "hero-document-text") - - `--description` - Brief description for the tab (optional) - - `--category-icon` - Heroicon name for the category (optional, defaults to "hero-folder"). Only used when creating a new category. - - ## Examples - - # Add a History tab to Farm Management category - mix phoenix_kit.gen.dashboard_tab "Farm Management" "History" \\ - --url="/dashboard/history" \\ - --icon="hero-chart-bar" \\ - --category-icon="hero-cube" - - # Add a Settings tab to Account category - mix phoenix_kit.gen.dashboard_tab "Account" "Settings" \\ - --url="/dashboard/settings" \\ - --icon="hero-cog-6-tooth" \\ - --description="Manage your account settings" - - """ - - @shortdoc "Adds a tab to the user dashboard configuration" - - use Igniter.Mix.Task - - alias PhoenixKit.Install.IgniterConfig - - @impl Igniter.Mix.Task - def info(_argv, _composing_task) do - %Igniter.Mix.Task.Info{ - group: :phoenix_kit, - example: - "mix phoenix_kit.gen.dashboard_tab \"Farm Management\" \"History\" --url=\"/dashboard/history\" --icon=\"hero-chart-bar\"", - schema: [ - url: :string, - icon: :string, - description: :string, - category_icon: :string - ], - aliases: [u: :url, i: :icon, d: :description, ci: :category_icon] - } - end - - @impl Igniter.Mix.Task - def igniter(igniter) do - # Get options and arguments from igniter context - opts = igniter.args.options - argv = igniter.args.argv - - case parse_args(argv, opts) do - {:ok, {category, tab_title}} -> - igniter - |> add_dashboard_tab(category, tab_title, opts) - - {:error, message} -> - Igniter.add_notice(igniter, """ - ❌ Error: #{message} - - Usage: mix phoenix_kit.gen.dashboard_tab --url= - Example: mix phoenix_kit.gen.dashboard_tab "Farm Management" "History" --url="/dashboard/history" - """) - end - end - - @impl Mix.Task - def run(argv) do - # Handle --help flag manually - if "--help" in argv or "-h" in argv do - Mix.shell().info(""" - Adds a tab to the user dashboard configuration. - - Usage: - - mix phoenix_kit.gen.dashboard_tab "Category Name" "Tab Title" --url="/dashboard/path" - - Arguments: - - category - The category name (e.g., "Farm Management") - tab_title - The display title for the tab - - Options: - - --url - The URL path for the tab (required) - --icon - Heroicon name for the tab (optional, defaults to "hero-document-text") - --description - Brief description for the tab (optional) - --category-icon - Heroicon name for the category (optional, defaults to "hero-folder") - - Examples: - - # Add a History tab to Farm Management category - mix phoenix_kit.gen.dashboard_tab "Farm Management" "History" \\ - --url="/dashboard/history" \\ - --icon="hero-chart-bar" \\ - --category-icon="hero-cube" - - # Add a Settings tab to Account category - mix phoenix_kit.gen.dashboard_tab "Account" "Settings" \\ - --url="/dashboard/settings" \\ - --icon="hero-cog-6-tooth" \\ - --description="Manage your account settings" - - Notes: - - - If the category doesn't exist, it will be created automatically - - Tabs are added to config/config.exs under :user_dashboard_categories - - The dashboard will automatically pick up the new tab after server restart - """) - - :ok - else - # Delegate to Igniter.Mix.Task for standard execution - super(argv) - end - end - - defp parse_args(argv, opts) do - # Filter out option arguments (starting with --) from argv - positional_args = Enum.reject(argv, &String.starts_with?(&1, "--")) - - case positional_args do - [category, tab_title] -> - url = Keyword.get(opts, :url) - - if url do - {:ok, {category, tab_title}} - else - {:error, "--url option is required"} - end - - args when length(args) < 2 -> - {:error, "not enough arguments. Expected: "} - - _ -> - {:error, "invalid arguments"} - end - end - - defp add_dashboard_tab(igniter, category, tab_title, opts) do - url = Keyword.get(opts, :url) - icon = Keyword.get(opts, :icon, "hero-document-text") - description = Keyword.get(opts, :description) - - # Validate inputs - cond do - !url -> - Igniter.add_issue(igniter, {:fatal, "--url option is required", []}) - - !String.starts_with?(url, "/") -> - Igniter.add_issue(igniter, {:fatal, "URL must start with '/'", []}) - - byte_size(tab_title) > 100 -> - Igniter.add_issue(igniter, {:fatal, "Tab title must be less than 100 characters", []}) - - description && byte_size(description) > 200 -> - Igniter.add_issue(igniter, {:fatal, "Description must be less than 200 characters", []}) - - true -> - igniter - |> update_dashboard_categories_config(category, tab_title, url, icon, description, opts) - |> print_success_message(category, tab_title, url) - end - end - - defp update_dashboard_categories_config( - igniter, - category, - tab_title, - url, - icon, - description, - opts - ) do - new_tab = %{ - title: tab_title, - url: url, - icon: icon, - description: description - } - - # Get category icon from options or use default - category_icon = Keyword.get(opts, :category_icon, "hero-folder") - - # Use IgniterConfig to add the tab to the category (creates category if needed) - IgniterConfig.add_to_user_dashboard_category( - igniter, - category, - new_tab, - icon: category_icon - ) - end - - defp print_success_message(igniter, category, tab_title, url) do - Igniter.add_notice(igniter, """ - ✅ Dashboard tab added successfully! - - Tab: #{tab_title} - Category: #{category} - URL: #{url} - - What was done: - 1. ✓ Added tab to user dashboard configuration in config/config.exs - - 📝 Next Steps: - - 1. Create the LiveView for this tab (if not already created): - - defmodule YourAppWeb.DashboardLive.#{camelize(tab_title)} do - use YourAppWeb, :live_view - - def mount(_params, _session, socket) do - {:ok, socket} - end - - def render(assigns) do - ~H\"\"\" -
-

#{tab_title}

- <%!-- Your content here --%> -
- \"\"\" - end - end - - 2. Add the route to your router (inside a dashboard live_session): - - live "#{url}", YourAppWeb.DashboardLive.#{camelize(tab_title)}, :index - - 3. Restart your server to see the new tab in the dashboard sidebar. - - The tab will appear under the "#{category}" category in the user dashboard. - """) - end - - defp camelize(string) do - string - |> String.replace(~r/[^a-zA-Z0-9]+/, "_") - |> Macro.camelize() - end -end diff --git a/lib/mix/tasks/phoenix_kit.gen.user.dashboard.ex b/lib/mix/tasks/phoenix_kit.gen.user.dashboard.ex new file mode 100644 index 000000000..74888a8e2 --- /dev/null +++ b/lib/mix/tasks/phoenix_kit.gen.user.dashboard.ex @@ -0,0 +1,328 @@ +defmodule Mix.Tasks.PhoenixKit.Gen.User.Dashboard do + @moduledoc """ + Igniter task that generates a user dashboard page with tab configuration. + + ## Usage + + mix phoenix_kit.gen.user.dashboard "Example" + + ## Arguments + + - `tab_title` - The display title for the tab (e.g., "Example") + + ## Options + + - `--url` - The URL path for the tab (optional, derived from title if not provided) + - `--category` - The category name (optional, defaults to "Category") + - `--icon` - Heroicon name for the tab (optional, defaults to "hero-document") + - `--description` - Brief description for the tab (optional) + - `--category-icon` - Heroicon name for the category (optional, defaults to "hero-folder"). Only used when creating a new category. + + ## Examples + + # Simple - uses all defaults + mix phoenix_kit.gen.user.dashboard "Example" + + # With custom category + mix phoenix_kit.gen.user.dashboard "Example" --category="Category" + + # With custom icon + mix phoenix_kit.gen.user.dashboard "Example" --icon="hero-chart-bar" + + # Full control + mix phoenix_kit.gen.user.dashboard "Example" --url="/custom/path" --icon="hero-user" + + """ + + @shortdoc "Generates user dashboard page with tab configuration" + + use Igniter.Mix.Task + + alias PhoenixKit.Install.IgniterConfig + alias PhoenixKit.Install.IgniterHelpers + + @impl Igniter.Mix.Task + def info(_argv, _composing_task) do + %Igniter.Mix.Task.Info{ + group: :phoenix_kit, + example: "mix phoenix_kit.gen.user.dashboard \"Example\"", + schema: [ + url: :string, + category: :string, + icon: :string, + description: :string, + category_icon: :string + ], + aliases: [u: :url, c: :category, i: :icon, d: :description, ci: :category_icon] + } + end + + @impl Igniter.Mix.Task + def igniter(igniter) do + # Get options and arguments from igniter context + opts = igniter.args.options + argv = igniter.args.argv + + case parse_args(argv, opts) do + {:ok, {tab_title, category, url}} -> + igniter + |> create_live_view(tab_title, url, opts) + |> add_dashboard_tab(category, tab_title, url, opts) + + {:error, message} -> + Igniter.add_notice(igniter, """ + ❌ Error: #{message} + + Usage: mix phoenix_kit.gen.user.dashboard + Example: mix phoenix_kit.gen.user.dashboard "Example" + """) + end + end + + @impl Mix.Task + def run(argv) do + # Handle --help flag manually + if "--help" in argv or "-h" in argv do + Mix.shell().info(""" + Generates a user dashboard page with tab configuration. + + Usage: + + mix phoenix_kit.gen.user.dashboard "Example" + + Arguments: + + tab_title - The display title for the tab + + Options: + + --url - The URL path for the tab (optional, derived from title) + --category - The category name (optional, defaults to "Category") + --icon - Heroicon name for the tab (optional, defaults to "hero-document") + --description - Brief description for the tab (optional) + --category-icon - Heroicon name for the category (optional, defaults to "hero-folder") + + Examples: + + # Simple - uses all defaults + mix phoenix_kit.gen.user.dashboard "Example" + + # With custom category + mix phoenix_kit.gen.user.dashboard "Example" --category="Category" + + # With custom icon + mix phoenix_kit.gen.user.dashboard "Example" --icon="hero-chart-bar" + + # Full control + mix phoenix_kit.gen.user.dashboard "Example" --url="/custom/path" --icon="hero-user" + + Notes: + + - Creates a LiveView file for the dashboard page + - Adds tab configuration to config/config.exs under :user_dashboard_categories + - After adding the route, run: mix compile --force + """) + + :ok + else + # Delegate to Igniter.Mix.Task for standard execution + super(argv) + end + end + + defp parse_args(argv, opts) do + # Filter out option arguments (starting with --) from argv + positional_args = Enum.reject(argv, &String.starts_with?(&1, "--")) + + case positional_args do + [tab_title] -> + # Derive URL from tab title if not provided + url = Keyword.get(opts, :url, slugify(tab_title)) + category = Keyword.get(opts, :category, "Category") + + {:ok, {tab_title, category, url}} + + [] -> + {:error, "not enough arguments. Expected: "} + + _ -> + {:error, "invalid arguments"} + end + end + + defp create_live_view(igniter, tab_title, url, opts) do + app_name = IgniterHelpers.get_parent_app_name(igniter) + web_module = IgniterHelpers.get_parent_app_module_web(igniter) + + web_module_string = + web_module + |> to_string() + |> String.replace_prefix("Elixir.", "") + + page_name = camelize(tab_title) + description = Keyword.get(opts, :description, "Manage your dashboard content") + + # Read the EEx template file + template_path = + case :code.priv_dir(:phoenix_kit) do + priv_dir when is_list(priv_dir) or is_binary(priv_dir) -> + Path.join(priv_dir, "templates/user_dashboard_page.ex") + + _ -> + "priv/templates/user_dashboard_page.ex" + end + + case File.read(template_path) do + {:ok, template_content} -> + # Use string replacement to avoid EEx/HEEX conflicts + rendered_content = + template_content + |> String.replace("<%= @web_module_prefix %>", web_module_string) + |> String.replace("<%= @page_name %>", page_name) + |> String.replace("<%= @page_title %>", tab_title) + |> String.replace("<%= @url %>", url) + |> String.replace("<%= @description %>", description) + + # Build the correct path + file_path = build_live_view_file_path(app_name, page_name) + + # Use create_new_file to avoid module parsing that might corrupt HEEX syntax + # Also skip formatting to preserve HEEX template syntax + Igniter.create_new_file(igniter, file_path, rendered_content, on_format: :skip) + + {:error, reason} -> + igniter + |> Igniter.add_issue({:fatal, "Failed to read template file: #{reason}", []}) + end + end + + defp add_dashboard_tab(igniter, category, tab_title, url, opts) do + icon = Keyword.get(opts, :icon, "hero-document") + description = Keyword.get(opts, :description) + + # Validate inputs + cond do + !String.starts_with?(url, "/") -> + Igniter.add_issue(igniter, {:fatal, "URL must start with '/'", []}) + + byte_size(tab_title) > 100 -> + Igniter.add_issue(igniter, {:fatal, "Tab title must be less than 100 characters", []}) + + description && byte_size(description) > 200 -> + Igniter.add_issue(igniter, {:fatal, "Description must be less than 200 characters", []}) + + true -> + igniter + |> update_dashboard_categories_config(category, tab_title, url, icon, description, opts) + |> print_success_message(category, tab_title, url) + end + end + + defp update_dashboard_categories_config( + igniter, + category, + tab_title, + url, + icon, + description, + opts + ) do + new_tab = %{ + title: tab_title, + url: url, + icon: icon, + description: description + } + + # Get category icon from options or use default + category_icon = Keyword.get(opts, :category_icon, "hero-folder") + + # Use IgniterConfig to add the tab to the category (creates category if needed) + IgniterConfig.add_to_user_dashboard_category( + igniter, + category, + new_tab, + icon: category_icon + ) + end + + defp print_success_message(igniter, category, tab_title, url) do + app_name = IgniterHelpers.get_parent_app_name(igniter) + web_module = IgniterHelpers.get_parent_app_module_web(igniter) + + web_module_string = + web_module + |> to_string() + |> String.replace_prefix("Elixir.", "") + + page_name = camelize(tab_title) + live_view_module = "#{web_module_string}.PhoenixKit.Dashboard.#{page_name}" + + Igniter.add_notice(igniter, """ + ✅ Dashboard page generated successfully! + + Page Created: #{live_view_module} + Tab: #{tab_title} + Category: #{category} + URL: #{url} + + What was done: + 1. ✓ Created LiveView file at #{build_live_view_file_path(app_name, page_name)} + 2. ✓ Added tab to user dashboard configuration in config/config.exs + + 📝 Next Steps: + + 1. Add the route to your router (inside a dashboard live_session): + + scope "/" do + pipe_through :browser + + live_session :user_dashboard, + on_mount: [ + {PhoenixKitWeb.Users.Auth, :phoenix_kit_ensure_authenticated_scope}, + {PhoenixKitWeb.Dashboard.ContextProvider, :default} + ] do + live "#{url}", #{live_view_module}, :index + end + end + + 2. Force recompile: mix compile --force + + 3. Restart your server to see the new tab in the dashboard sidebar. + + The tab will appear under the "#{category}" category in the user dashboard. + """) + end + + # Builds the full file path for the LiveView + defp build_live_view_file_path(app_name, page_name) do + # Use the app_name to get the correct web directory name + # E.g., phoenix_kit_parent_project -> phoenix_kit_parent_project_web + web_path = + app_name + |> to_string() + |> Kernel.<>("_web") + |> String.downcase() + + # Convert page name to lowercase for the file + file_name = String.downcase(page_name) + + # Return the full file path + "lib/#{web_path}/phoenix_kit/dashboard/#{file_name}.ex" + end + + # Convert title to URL-safe slug + defp slugify(title) do + title + |> String.downcase() + |> String.replace(~r/[^a-z0-9\s-]/, "") + |> String.replace(~r/\s+/, "-") + |> then(&"/dashboard/#{&1}") + end + + defp camelize(string) do + string + |> String.replace(~r/[^a-zA-Z0-9]+/, "_") + |> Macro.camelize() + end +end diff --git a/lib/phoenix_kit/dashboard/README.md b/lib/phoenix_kit/dashboard/README.md index 1f03978dd..c764aba59 100644 --- a/lib/phoenix_kit/dashboard/README.md +++ b/lib/phoenix_kit/dashboard/README.md @@ -19,23 +19,25 @@ A comprehensive, extensible navigation system for the PhoenixKit user dashboard ### Using the Mix Generator (Recommended) -The easiest way to add tabs is using the Mix generator: +The easiest way to add dashboard pages is using the Mix generator: ```bash -# Add a History tab to Farm Management category -mix phoenix_kit.gen.dashboard_tab "Farm Management" "History" \ - --url="/dashboard/history" \ - --icon="hero-chart-bar" \ - --category-icon="hero-cube" +# Simple - uses all defaults (creates LiveView + tab config) +mix phoenix_kit.gen.user.dashboard "Example" -# Add a Settings tab to Account category -mix phoenix_kit.gen.dashboard_tab "Account" "Settings" \ - --url="/dashboard/settings" \ - --icon="hero-cog-6-tooth" \ - --description="Manage your account settings" +# With custom category +mix phoenix_kit.gen.user.dashboard "Example" --category="Category" + +# With custom icon +mix phoenix_kit.gen.user.dashboard "Example" --icon="hero-chart-bar" + +# Full control +mix phoenix_kit.gen.user.dashboard "Example" --url="/custom/path" --icon="hero-user" ``` -This will automatically add the tab configuration to your `config/config.exs`. +This will automatically: +1. Create a LiveView file for the dashboard page +2. Add the tab configuration to your `config/config.exs` ### Configure Categories in config.exs diff --git a/lib/phoenix_kit_web.ex b/lib/phoenix_kit_web.ex index da103b2a2..8a9fc9b65 100644 --- a/lib/phoenix_kit_web.ex +++ b/lib/phoenix_kit_web.ex @@ -145,6 +145,7 @@ defmodule PhoenixKitWeb do import PhoenixKitWeb.Components.Core.Modal import PhoenixKitWeb.Components.Core.MediaThumbnail import PhoenixKitWeb.Components.Core.AdminPageHeader + import PhoenixKitWeb.Components.Core.UserDashboardHeader import PhoenixKitWeb.Components.Core.DevNotice import PhoenixKitWeb.Components.Core.PhoenixKitGlobals end diff --git a/lib/phoenix_kit_web/components/core/user_dashboard_header.ex b/lib/phoenix_kit_web/components/core/user_dashboard_header.ex new file mode 100644 index 000000000..139ec630a --- /dev/null +++ b/lib/phoenix_kit_web/components/core/user_dashboard_header.ex @@ -0,0 +1,77 @@ +defmodule PhoenixKitWeb.Components.Core.UserDashboardHeader do + @moduledoc """ + Provides a unified user dashboard header component with title, subtitle, and action slots. + + Use this component in custom user dashboard pages for consistent page-level + headers with titles and action buttons. + + ## Examples + + <%!-- Basic --%> + <.user_dashboard_header title="My Profile" /> + + <%!-- With subtitle --%> + <.user_dashboard_header title="Security" subtitle="Manage your account security" /> + + <%!-- With actions --%> + <.user_dashboard_header title="My Posts"> + <:actions> + <.pk_link_button navigate={~p"/dashboard/posts/new"} variant="primary"> + New Post + + + + + <%!-- Rich title content --%> + <.user_dashboard_header> +

Order #123

+

Placed 2 days ago

+ + + ## Attributes + + - `title` - Page title as a string attribute + - `subtitle` - Page subtitle as a string attribute + + ## Slots + + - `:inner_block` - Custom title/subtitle markup (overrides `title`/`subtitle` attrs) + - `:actions` - Action buttons rendered on the right side + + """ + + use Phoenix.Component + + attr :title, :string, default: nil + attr :subtitle, :string, default: nil + + slot :inner_block + slot :actions + + def user_dashboard_header(assigns) do + ~H""" +
+
+
+ <%= if @title do %> +

+ {@title} +

+

+ {@subtitle} +

+ <% else %> + {render_slot(@inner_block)} + <% end %> +
+
+ {render_slot(@actions)} +
+
+
+ """ + end +end diff --git a/lib/phoenix_kit_web/live/dashboard/index.ex b/lib/phoenix_kit_web/live/dashboard/index.ex index f3c159dd2..e55856cd9 100644 --- a/lib/phoenix_kit_web/live/dashboard/index.ex +++ b/lib/phoenix_kit_web/live/dashboard/index.ex @@ -9,7 +9,6 @@ defmodule PhoenixKitWeb.Live.Dashboard.Index do socket = socket |> assign(:page_title, gettext("Dashboard")) - |> assign(:project_title, PhoenixKit.Settings.get_project_title()) {:ok, socket} end @@ -18,16 +17,20 @@ defmodule PhoenixKitWeb.Live.Dashboard.Index do def render(assigns) do ~H""" -
-
-

- {gettext("Welcome to your Dashboard")} -

-

- {gettext( - "Your personal dashboard is ready. Explore your account settings and manage your profile from here." - )} -

+
+ <.user_dashboard_header + title={@page_title} + subtitle={gettext("Welcome to your personal dashboard")} + /> + +
+
+

+ {gettext( + "Your personal dashboard is ready. Explore your account settings and manage your profile from here." + )} +

+
diff --git a/lib/phoenix_kit_web/live/dashboard/settings.ex b/lib/phoenix_kit_web/live/dashboard/settings.ex index c8d4bf467..c1929470b 100644 --- a/lib/phoenix_kit_web/live/dashboard/settings.ex +++ b/lib/phoenix_kit_web/live/dashboard/settings.ex @@ -49,10 +49,9 @@ defmodule PhoenixKitWeb.Live.Dashboard.Settings do def render(assigns) do ~H""" -
- <.admin_page_header - back={Routes.path("/dashboard")} - title="Settings" +
+ <.user_dashboard_header + title={@page_title} subtitle="Manage your account settings and preferences" /> diff --git a/priv/templates/user_dashboard_page.ex b/priv/templates/user_dashboard_page.ex new file mode 100644 index 000000000..9e7d3556b --- /dev/null +++ b/priv/templates/user_dashboard_page.ex @@ -0,0 +1,39 @@ +defmodule <%= @web_module_prefix %>.PhoenixKit.Dashboard.<%= @page_name %> do + @moduledoc """ + User dashboard LiveView for <%= @page_title %>. + """ + + use <%= @web_module_prefix %>, :live_view + + import PhoenixKitWeb.LayoutHelpers, only: [dashboard_assigns: 1] + import PhoenixKitWeb.Components.Core.UserDashboardHeader, only: [user_dashboard_header: 1] + + @impl true + def mount(_params, _session, socket) do + socket = assign(socket, :page_title, gettext("<%= @page_title %>")) + {:ok, socket} + end + + @impl true + def render(assigns) do + ~H""" + +
+ <.user_dashboard_header + title={@page_title} + subtitle={gettext("<%= @description %>")} + /> + +
+
+

+ This is a template for your {@page_title} dashboard page. + You can customize this page by modifying the LiveView module. +

+
+
+
+
+ """ + end +end