public inbox for [email protected]
 help / color / mirror / Atom feed
From: Muhammad Rizki <[email protected]>
To: Ammar Faizi <[email protected]>
Cc: Muhammad Rizki <[email protected]>,
	Alviro Iskandar Setiawan <[email protected]>,
	GNU/Weeb Mailing List <[email protected]>
Subject: [PATCH v1 06/17] fix(breadcrumb): Move settingsNav to settings items navigations
Date: Wed,  5 Mar 2025 21:40:05 +0700	[thread overview]
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>

Move settingsNav items to navigations settings items to make breadcrumb
works properly.

Signed-off-by: Muhammad Rizki <[email protected]>
---
 src/lib/components/customs/header.svelte      | 39 +++++++++++++++----
 src/lib/constants/navigations.ts              | 31 +++++++--------
 src/lib/typings/common.d.ts                   |  1 +
 src/lib/utilities/index.ts                    |  3 +-
 src/lib/utilities/navigation.ts               |  5 +++
 .../(components)/settings-header.svelte       |  3 +-
 .../(protected)/settings/+layout.svelte       |  5 +--
 src/routes/(protected)/settings/+page.ts      |  6 ++-
 8 files changed, 63 insertions(+), 30 deletions(-)
 create mode 100644 src/lib/utilities/navigation.ts

diff --git a/src/lib/components/customs/header.svelte b/src/lib/components/customs/header.svelte
index 44c681e..6a343d5 100644
--- a/src/lib/components/customs/header.svelte
+++ b/src/lib/components/customs/header.svelte
@@ -4,12 +4,28 @@
   import { page } from "$app/state";
   import { navigations } from "$constants";
   import Separator from "$components/ui/separator/separator.svelte";
+  import * as typing from "$typings";
 
-  const getRouteName = () => {
-    const pathname = page.url.pathname;
-    const found = navigations.find((path) => path.url === pathname);
+  const getParentRoute = (
+    path: string,
+    items: typing.Navigations[],
+    routePath: typing.Navigations[] = []
+  ): typing.Navigations[] => {
+    for (const item of items) {
+      if (path === item.url) {
+        return [...routePath, item];
+      }
 
-    return found?.name ?? "";
+      if (item.items) {
+        const foundPath = getParentRoute(path, item.items, [...routePath, item]);
+        if (foundPath.length) return foundPath;
+      }
+    }
+    return [];
+  };
+
+  const getRouteName = () => {
+    return getParentRoute(page.url.pathname, navigations);
   };
 </script>
 
@@ -23,9 +39,18 @@
           <Breadcrumb.Link href="/">G/W Mail</Breadcrumb.Link>
         </Breadcrumb.Item>
         <Breadcrumb.Separator />
-        <Breadcrumb.Item class="select-none">
-          <Breadcrumb.Page>{getRouteName()}</Breadcrumb.Page>
-        </Breadcrumb.Item>
+        {#each getRouteName() as route, index (route.url)}
+          {#if index === getRouteName().length - 1}
+            <Breadcrumb.Item class="select-none">
+              <Breadcrumb.Page>{route.name}</Breadcrumb.Page>
+            </Breadcrumb.Item>
+          {:else}
+            <Breadcrumb.Item class="hidden md:block">
+              <Breadcrumb.Link href={route.url}>{route.name}</Breadcrumb.Link>
+            </Breadcrumb.Item>
+            <Breadcrumb.Separator />
+          {/if}
+        {/each}
       </Breadcrumb.List>
     </Breadcrumb.Root>
   </div>
diff --git a/src/lib/constants/navigations.ts b/src/lib/constants/navigations.ts
index ca5e77b..4266930 100644
--- a/src/lib/constants/navigations.ts
+++ b/src/lib/constants/navigations.ts
@@ -1,6 +1,6 @@
 import * as typing from "$typings";
-import Home from "lucide-svelte/icons/home"
-import Settings from "lucide-svelte/icons/settings"
+import Home from "lucide-svelte/icons/home";
+import Settings from "lucide-svelte/icons/settings";
 
 export const navigations: typing.Navigations[] = [
   {
@@ -11,19 +11,18 @@ export const navigations: typing.Navigations[] = [
   {
     name: "Settings",
     icon: Settings,
-    url: "/settings"
+    url: "/settings",
+    items: [
+      {
+        name: "Profile",
+        description: "Manage your profile.",
+        url: "/settings/profile"
+      },
+      {
+        name: "Account",
+        description: "Manage your account credentials.",
+        url: "/settings/account"
+      }
+    ]
   }
 ] as const;
-
-export const settingsNav: typing.Navigations[] = [
-  {
-    name: "Profile",
-    description: "Manage your profile.",
-    url: "/settings/profile"
-  },
-  {
-    name: "Account",
-    description: "Manage your account credentials.",
-    url: "/settings/account"
-  }
-];
diff --git a/src/lib/typings/common.d.ts b/src/lib/typings/common.d.ts
index cdbe0d4..1f4a795 100644
--- a/src/lib/typings/common.d.ts
+++ b/src/lib/typings/common.d.ts
@@ -8,6 +8,7 @@ export interface Navigations {
   icon?: typeof IconType;
   url: string;
   disabled?: boolean;
+  items?: Navigations[]
 }
 
 export interface LabelAndValue {
diff --git a/src/lib/utilities/index.ts b/src/lib/utilities/index.ts
index ed0291d..48c622d 100644
--- a/src/lib/utilities/index.ts
+++ b/src/lib/utilities/index.ts
@@ -1,3 +1,4 @@
+import { getSettingsNav } from "./navigation";
 import { cn } from "./styling";
 
-export { cn };
+export { cn, getSettingsNav };
diff --git a/src/lib/utilities/navigation.ts b/src/lib/utilities/navigation.ts
new file mode 100644
index 0000000..4b84eca
--- /dev/null
+++ b/src/lib/utilities/navigation.ts
@@ -0,0 +1,5 @@
+import { navigations } from "$constants";
+
+export const getSettingsNav = () => {
+  return navigations.find((nav) => nav.url.includes("/settings"))?.items ?? [];
+};
diff --git a/src/routes/(protected)/settings/(components)/settings-header.svelte b/src/routes/(protected)/settings/(components)/settings-header.svelte
index cc13950..34e5900 100644
--- a/src/routes/(protected)/settings/(components)/settings-header.svelte
+++ b/src/routes/(protected)/settings/(components)/settings-header.svelte
@@ -1,8 +1,9 @@
 <script lang="ts">
   import { page } from "$app/state";
-  import { settingsNav } from "$constants/navigations";
   import Separator from "$components/ui/separator/separator.svelte";
+  import { getSettingsNav } from "$utils";
 
+  const settingsNav = getSettingsNav();
   const activeNav = $derived(settingsNav.find((e) => page.url.pathname === e.url));
 </script>
 
diff --git a/src/routes/(protected)/settings/+layout.svelte b/src/routes/(protected)/settings/+layout.svelte
index 71e30d8..80d306a 100644
--- a/src/routes/(protected)/settings/+layout.svelte
+++ b/src/routes/(protected)/settings/+layout.svelte
@@ -1,9 +1,8 @@
 <script lang="ts">
   import { Separator } from "$lib/components/ui/separator";
-
-  import { settingsNav } from "$constants/navigations";
   import SettingsNavigation from "./(components)/settings-nav.svelte";
   import SettingsHeader from "./(components)/settings-header.svelte";
+  import { getSettingsNav } from "$utils";
 
   let { children } = $props();
 </script>
@@ -16,7 +15,7 @@
   <Separator class="my-6" />
   <div class="flex flex-col space-y-8 xl:flex-row xl:space-x-8 xl:space-y-0">
     <aside class="xl:w-[12%]">
-      <SettingsNavigation items={settingsNav} />
+      <SettingsNavigation items={getSettingsNav()} />
     </aside>
     <div class="flex-1">
       <div class="space-y-6">
diff --git a/src/routes/(protected)/settings/+page.ts b/src/routes/(protected)/settings/+page.ts
index 3c846ad..c29023a 100644
--- a/src/routes/(protected)/settings/+page.ts
+++ b/src/routes/(protected)/settings/+page.ts
@@ -1,11 +1,13 @@
 import { redirect } from "@sveltejs/kit";
 import type { PageLoad } from "./$types";
-import { settingsNav } from "$constants/navigations";
+import { getSettingsNav } from "$utils";
 
 export const load: PageLoad = async () => {
   // get first page that are not disabled.
+  const settingsNav = getSettingsNav();
   const firstPage = settingsNav.find((e) => !e.disabled);
+  const url = firstPage?.items?.[0].url ?? firstPage?.url;
 
   // if it don't exist, redirect to index page.
-  return redirect(307, firstPage?.url ?? "/");
+  return redirect(307, url ?? "/settings/profile");
 };
-- 
Muhammad Rizki


  parent reply	other threads:[~2025-03-05 14:40 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-05 14:39 [PATCH v1 00/17] Profile Page, SEO, Fixed API structure, Docs Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 01/17] fix(typing): add user_info type prop Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 02/17] refactor: optimize icon imports to reduce bundle size Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 03/17] chore(change-pwd): adjust change password heading styling Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 04/17] chore(settings/layout): use prose: for " Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 05/17] fix(profile): fix edit avatar button position Muhammad Rizki
2025-03-05 14:40 ` Muhammad Rizki [this message]
2025-03-05 14:40 ` [PATCH v1 07/17] chore(responsive): adjust styling Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 08/17] chore(navigations): Replace index /settings url Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 09/17] feat(ui): Add popover and dialog UI component Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 10/17] feat(http): Use PUBLIC_BASE_URL for each environment Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 11/17] feat(icons): Add social icons Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 12/17] feat(typing/enum): add Gender and IsActive enum Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 13/17] refactor!:feat: update API response structure, update profile page Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 14/17] chore(meta): rename favicon.png to favicon.ico Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 15/17] feat(seo): add SEO for site metadata Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 16/17] chore(login): use $derived() instead of function based Muhammad Rizki
2025-03-05 14:40 ` [PATCH v1 17/17] docs: update README.md Muhammad Rizki
2025-03-05 16:54 ` [PATCH v1 00/17] Profile Page, SEO, Fixed API structure, Docs Ammar Faizi
2025-03-05 16:57   ` Alviro Iskandar Setiawan
2025-03-06  7:01     ` Muhammad Rizki
2025-03-06  7:02       ` Alviro Iskandar Setiawan
2025-03-06  7:04         ` Muhammad Rizki
2025-03-06  2:02   ` Muhammad Rizki
2025-03-06  3:37     ` Ammar Faizi
2025-03-05 17:04 ` Ammar Faizi
2025-03-05 18:14 ` Alviro Iskandar Setiawan
2025-03-06  1:59   ` Muhammad Rizki
2025-03-06  3:35     ` Ammar Faizi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    [email protected] \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox