Преглед изворни кода

refactor!: replace tabler icons with lucide icons (#183)

* refactor: replace tabler icons with lucide icons

This update removes the dependency on @tabler/icons-react
and replaces all instances with corresponding icons from
lucide-react across various components, ensuring a consistent
icon library is used throughout the application.

* refactor: transform tabler icons into custom brand icon components

This update replaces all instances of Tabler icons
with custom brand icons from the assets directory
in the apps, sign-in, and sign-up components, ensuring
a consistent icon usage across the application.

In other words, remove @tabler/icons-react dependency
for brand icons and transform those icons into custom
React components instead.

* docs: update README to reflect icon library changes

This update modifies the README to replace references
to Tabler Icons with Lucide Icons, clarifying the use
of Lucide Icons alongside Tabler Icons for brand purposes.
Sat Naing пре 11 месеци
родитељ
комит
969dba1079
52 измењених фајлова са 652 додато и 245 уклоњено
  1. 0 1
      .prettierrc
  2. 1 1
      README.md
  3. 0 1
      package.json
  4. 0 18
      pnpm-lock.yaml
  5. 28 0
      src/assets/brand-icons/icon-discord.tsx
  6. 33 0
      src/assets/brand-icons/icon-docker.tsx
  7. 25 0
      src/assets/brand-icons/icon-facebook.tsx
  8. 27 0
      src/assets/brand-icons/icon-figma.tsx
  9. 25 0
      src/assets/brand-icons/icon-github.tsx
  10. 25 0
      src/assets/brand-icons/icon-gitlab.tsx
  11. 28 0
      src/assets/brand-icons/icon-gmail.tsx
  12. 30 0
      src/assets/brand-icons/icon-medium.tsx
  13. 28 0
      src/assets/brand-icons/icon-notion.tsx
  14. 26 0
      src/assets/brand-icons/icon-skype.tsx
  15. 28 0
      src/assets/brand-icons/icon-slack.tsx
  16. 25 0
      src/assets/brand-icons/icon-stripe.tsx
  17. 25 0
      src/assets/brand-icons/icon-telegram.tsx
  18. 27 0
      src/assets/brand-icons/icon-trello.tsx
  19. 26 0
      src/assets/brand-icons/icon-whatsapp.tsx
  20. 26 0
      src/assets/brand-icons/icon-zoom.tsx
  21. 16 0
      src/assets/brand-icons/index.ts
  22. 3 3
      src/components/coming-soon.tsx
  23. 7 13
      src/components/command-menu.tsx
  24. 3 3
      src/components/dir-switch.tsx
  25. 39 39
      src/components/layout/data/sidebar-data.ts
  26. 2 2
      src/components/layout/top-nav.tsx
  27. 2 2
      src/components/learn-more.tsx
  28. 2 2
      src/components/password-input.tsx
  29. 3 2
      src/components/search.tsx
  30. 2 2
      src/components/select-dropdown.tsx
  31. 6 6
      src/components/theme-switch.tsx
  32. 31 31
      src/features/apps/data/apps.tsx
  33. 4 8
      src/features/apps/index.tsx
  34. 3 3
      src/features/auth/sign-in/components/user-auth-form.tsx
  35. 3 3
      src/features/auth/sign-up/components/sign-up-form.tsx
  36. 3 3
      src/features/chats/components/new-chat.tsx
  37. 25 28
      src/features/chats/index.tsx
  38. 6 12
      src/features/settings/index.tsx
  39. 2 2
      src/features/tasks/components/data-table-row-actions.tsx
  40. 3 3
      src/features/tasks/components/tasks-primary-buttons.tsx
  41. 23 17
      src/features/tasks/data/data.tsx
  42. 3 3
      src/features/users/components/data-table-row-actions.tsx
  43. 2 2
      src/features/users/components/data-table-toolbar.tsx
  44. 2 2
      src/features/users/components/users-action-dialog.tsx
  45. 2 2
      src/features/users/components/users-columns.tsx
  46. 2 2
      src/features/users/components/users-delete-dialog.tsx
  47. 5 5
      src/features/users/components/users-invite-dialog.tsx
  48. 3 3
      src/features/users/components/users-primary-buttons.tsx
  49. 6 11
      src/features/users/data/data.ts
  50. 3 3
      src/routes/clerk/_authenticated/user-management.tsx
  51. 3 3
      src/routes/clerk/route.tsx
  52. 0 4
      vite.config.ts

+ 0 - 1
.prettierrc

@@ -31,7 +31,6 @@
     "^@tanstack/react-query$",
     "^@tanstack/react-router$",
     "^@tanstack/react-table$",
-    "^@tabler/icons-react$",
     "<THIRD_PARTY_MODULES>",
     "^@/assets/(.*)",
     "^@/api/(.*)$",

+ 1 - 1
README.md

@@ -67,7 +67,7 @@ If you want to update components using the Shadcn CLI (e.g., `npx shadcn@latest
 
 **Linting/Formatting:** [Eslint](https://eslint.org/) & [Prettier](https://prettier.io/)
 
-**Icons:** [Tabler Icons](https://tabler.io/icons)
+**Icons:** [Lucide Icons](https://lucide.dev/icons/), [Tabler Icons](https://tabler.io/icons) (Brand icons only)
 
 **Auth (partial):** [Clerk](https://go.clerk.com/GttUAaK)
 

+ 0 - 1
package.json

@@ -33,7 +33,6 @@
     "@radix-ui/react-switch": "^1.2.5",
     "@radix-ui/react-tabs": "^1.1.12",
     "@radix-ui/react-tooltip": "^1.2.7",
-    "@tabler/icons-react": "^3.34.1",
     "@tailwindcss/vite": "^4.1.11",
     "@tanstack/react-query": "^5.83.0",
     "@tanstack/react-router": "^1.129.0",

+ 0 - 18
pnpm-lock.yaml

@@ -68,9 +68,6 @@ importers:
       '@radix-ui/react-tooltip':
         specifier: ^1.2.7
         version: 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
-      '@tabler/icons-react':
-        specifier: ^3.34.1
-        version: 3.34.1(react@19.1.0)
       '@tailwindcss/vite':
         specifier: ^4.1.11
         version: 4.1.11(vite@7.0.5(@types/node@24.0.15)(jiti@2.4.2)(lightningcss@1.30.1)(tsx@4.20.3))
@@ -1420,14 +1417,6 @@ packages:
   '@swc/types@0.1.23':
     resolution: {integrity: sha512-u1iIVZV9Q0jxY+yM2vw/hZGDNudsN85bBpTqzAQ9rzkxW9D+e3aEM4Han+ow518gSewkXgjmEK0BD79ZcNVgPw==}
 
-  '@tabler/icons-react@3.34.1':
-    resolution: {integrity: sha512-Ld6g0NqOO05kyyHsfU8h787PdHBm7cFmOycQSIrGp45XcXYDuOK2Bs0VC4T2FWSKZ6bx5g04imfzazf/nqtk1A==}
-    peerDependencies:
-      react: '>= 16'
-
-  '@tabler/icons@3.34.1':
-    resolution: {integrity: sha512-9gTnUvd7Fd/DmQgr3MKY+oJLa1RfNsQo8c/ir3TJAWghOuZXodbtbVp0QBY2DxWuuvrSZFys0HEbv1CoiI5y6A==}
-
   '@tailwindcss/node@4.1.11':
     resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==}
 
@@ -4174,13 +4163,6 @@ snapshots:
     dependencies:
       '@swc/counter': 0.1.3
 
-  '@tabler/icons-react@3.34.1(react@19.1.0)':
-    dependencies:
-      '@tabler/icons': 3.34.1
-      react: 19.1.0
-
-  '@tabler/icons@3.34.1': {}
-
   '@tailwindcss/node@4.1.11':
     dependencies:
       '@ampproject/remapping': 2.3.0

+ 28 - 0
src/assets/brand-icons/icon-discord.tsx

@@ -0,0 +1,28 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconDiscord({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Discord</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M8 12a1 1 0 1 0 2 0a1 1 0 0 0 -2 0' />
+      <path d='M14 12a1 1 0 1 0 2 0a1 1 0 0 0 -2 0' />
+      <path d='M15.5 17c0 1 1.5 3 2 3c1.5 0 2.833 -1.667 3.5 -3c.667 -1.667 .5 -5.833 -1.5 -11.5c-1.457 -1.015 -3 -1.34 -4.5 -1.5l-.972 1.923a11.913 11.913 0 0 0 -4.053 0l-.975 -1.923c-1.5 .16 -3.043 .485 -4.5 1.5c-2 5.667 -2.167 9.833 -1.5 11.5c.667 1.333 2 3 3.5 3c.5 0 2 -2 2 -3' />
+      <path d='M7 16.5c3.5 1 6.5 1 10 0' />
+    </svg>
+  )
+}

+ 33 - 0
src/assets/brand-icons/icon-docker.tsx

@@ -0,0 +1,33 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconDocker({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Docker</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M22 12.54c-1.804 -.345 -2.701 -1.08 -3.523 -2.94c-.487 .696 -1.102 1.568 -.92 2.4c.028 .238 -.32 1 -.557 1h-14c0 5.208 3.164 7 6.196 7c4.124 .022 7.828 -1.376 9.854 -5c1.146 -.101 2.296 -1.505 2.95 -2.46z' />
+      <path d='M5 10h3v3h-3z' />
+      <path d='M8 10h3v3h-3z' />
+      <path d='M11 10h3v3h-3z' />
+      <path d='M8 7h3v3h-3z' />
+      <path d='M11 7h3v3h-3z' />
+      <path d='M11 4h3v3h-3z' />
+      <path d='M4.571 18c1.5 0 2.047 -.074 2.958 -.78' />
+      <path d='M10 16l0 .01' />
+    </svg>
+  )
+}

+ 25 - 0
src/assets/brand-icons/icon-facebook.tsx

@@ -0,0 +1,25 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconFacebook({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Facebook</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M7 10v4h3v7h4v-7h3l1 -4h-4v-2a1 1 0 0 1 1 -1h3v-4h-3a5 5 0 0 0 -5 5v2h-3' />
+    </svg>
+  )
+}

+ 27 - 0
src/assets/brand-icons/icon-figma.tsx

@@ -0,0 +1,27 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconFigma({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Figma</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M15 12m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0' />
+      <path d='M6 3m0 3a3 3 0 0 1 3 -3h6a3 3 0 0 1 3 3v0a3 3 0 0 1 -3 3h-6a3 3 0 0 1 -3 -3z' />
+      <path d='M9 9a3 3 0 0 0 0 6h3m-3 0a3 3 0 1 0 3 3v-15' />
+    </svg>
+  )
+}

+ 25 - 0
src/assets/brand-icons/icon-github.tsx

@@ -0,0 +1,25 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconGithub({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>GitHub</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5' />
+    </svg>
+  )
+}

+ 25 - 0
src/assets/brand-icons/icon-gitlab.tsx

@@ -0,0 +1,25 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconGitlab({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>GitLab</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M21 14l-9 7l-9 -7l3 -11l3 7h6l3 -7z' />
+    </svg>
+  )
+}

+ 28 - 0
src/assets/brand-icons/icon-gmail.tsx

@@ -0,0 +1,28 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconGmail({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Gmail</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M16 20h3a1 1 0 0 0 1 -1v-14a1 1 0 0 0 -1 -1h-3v16z' />
+      <path d='M5 20h3v-16h-3a1 1 0 0 0 -1 1v14a1 1 0 0 0 1 1z' />
+      <path d='M16 4l-4 4l-4 -4' />
+      <path d='M4 6.5l8 7.5l8 -7.5' />
+    </svg>
+  )
+}

+ 30 - 0
src/assets/brand-icons/icon-medium.tsx

@@ -0,0 +1,30 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconMedium({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Medium</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z' />
+      <path d='M8 9h1l3 3l3 -3h1' />
+      <path d='M8 15l2 0' />
+      <path d='M14 15l2 0' />
+      <path d='M9 9l0 6' />
+      <path d='M15 9l0 6' />
+    </svg>
+  )
+}

+ 28 - 0
src/assets/brand-icons/icon-notion.tsx

@@ -0,0 +1,28 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconNotion({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Notion</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M11 17.5v-6.5h.5l4 6h.5v-6.5' />
+      <path d='M19.077 20.071l-11.53 .887a1 1 0 0 1 -.876 -.397l-2.471 -3.294a1 1 0 0 1 -.2 -.6v-10.741a1 1 0 0 1 .923 -.997l11.389 -.876a2 2 0 0 1 1.262 .33l1.535 1.023a2 2 0 0 1 .891 1.664v12.004a1 1 0 0 1 -.923 .997z' />
+      <path d='M4.5 5.5l2.5 2.5' />
+      <path d='M20 7l-13 1v12.5' />
+    </svg>
+  )
+}

+ 26 - 0
src/assets/brand-icons/icon-skype.tsx

@@ -0,0 +1,26 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconSkype({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Skype</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M12 3a9 9 0 0 1 8.603 11.65a4.5 4.5 0 0 1 -5.953 5.953a9 9 0 0 1 -11.253 -11.253a4.5 4.5 0 0 1 5.953 -5.954a8.987 8.987 0 0 1 2.65 -.396z' />
+      <path d='M8 14.5c.5 2 2.358 2.5 4 2.5c2.905 0 4 -1.187 4 -2.5c0 -1.503 -1.927 -2.5 -4 -2.5s-4 -1 -4 -2.5c0 -1.313 1.095 -2.5 4 -2.5c1.642 0 3.5 .5 4 2.5' />
+    </svg>
+  )
+}

+ 28 - 0
src/assets/brand-icons/icon-slack.tsx

@@ -0,0 +1,28 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconSlack({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Slack</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M12 12v-6a2 2 0 0 1 4 0v6m0 -2a2 2 0 1 1 2 2h-6' />
+      <path d='M12 12h6a2 2 0 0 1 0 4h-6m2 0a2 2 0 1 1 -2 2v-6' />
+      <path d='M12 12v6a2 2 0 0 1 -4 0v-6m0 2a2 2 0 1 1 -2 -2h6' />
+      <path d='M12 12h-6a2 2 0 0 1 0 -4h6m-2 0a2 2 0 1 1 2 -2v6' />
+    </svg>
+  )
+}

+ 25 - 0
src/assets/brand-icons/icon-stripe.tsx

@@ -0,0 +1,25 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconStripe({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Stripe</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M11.453 8.056c0 -.623 .518 -.979 1.442 -.979c1.69 0 3.41 .343 4.605 .923l.5 -4c-.948 -.449 -2.82 -1 -5.5 -1c-1.895 0 -3.373 .087 -4.5 1c-1.172 .956 -2 2.33 -2 4c0 3.03 1.958 4.906 5 6c1.961 .69 3 .743 3 1.5c0 .735 -.851 1.5 -2 1.5c-1.423 0 -3.963 -.609 -5.5 -1.5l-.5 4c1.321 .734 3.474 1.5 6 1.5c2 0 3.957 -.468 5.084 -1.36c1.263 -.979 1.916 -2.268 1.916 -4.14c0 -3.096 -1.915 -4.547 -5 -5.637c-1.646 -.605 -2.544 -1.07 -2.544 -1.807z' />
+    </svg>
+  )
+}

+ 25 - 0
src/assets/brand-icons/icon-telegram.tsx

@@ -0,0 +1,25 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconTelegram({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Telegram</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4' />
+    </svg>
+  )
+}

+ 27 - 0
src/assets/brand-icons/icon-trello.tsx

@@ -0,0 +1,27 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconTrello({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Trello</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z' />
+      <path d='M7 7h3v10h-3z' />
+      <path d='M14 7h3v6h-3z' />
+    </svg>
+  )
+}

+ 26 - 0
src/assets/brand-icons/icon-whatsapp.tsx

@@ -0,0 +1,26 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconWhatsapp({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>WhatsApp</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M3 21l1.65 -3.8a9 9 0 1 1 3.4 2.9l-5.05 .9' />
+      <path d='M9 10a.5 .5 0 0 0 1 0v-1a.5 .5 0 0 0 -1 0v1a5 5 0 0 0 5 5h1a.5 .5 0 0 0 0 -1h-1a.5 .5 0 0 0 0 1' />
+    </svg>
+  )
+}

+ 26 - 0
src/assets/brand-icons/icon-zoom.tsx

@@ -0,0 +1,26 @@
+import { SVGProps } from 'react'
+import { cn } from '@/lib/utils'
+
+export function IconZoom({ className, ...props }: SVGProps<SVGSVGElement>) {
+  return (
+    <svg
+      role='img'
+      viewBox='0 0 24 24'
+      xmlns='http://www.w3.org/2000/svg'
+      width='24'
+      height='24'
+      className={cn('[&>path]:stroke-current', className)}
+      fill='none'
+      stroke='currentColor'
+      strokeWidth='2'
+      strokeLinecap='round'
+      strokeLinejoin='round'
+      {...props}
+    >
+      <title>Zoom</title>
+      <path strokeWidth='0' d='M0 0h24v24H0z' fill='none' />
+      <path d='M17.011 9.385v5.128l3.989 3.487v-12z' />
+      <path d='M3.887 6h10.08c1.468 0 3.033 1.203 3.033 2.803v8.196a.991 .991 0 0 1 -.975 1h-10.373c-1.667 0 -2.652 -1.5 -2.652 -3l.01 -8a.882 .882 0 0 1 .208 -.71a.841 .841 0 0 1 .67 -.287z' />
+    </svg>
+  )
+}

+ 16 - 0
src/assets/brand-icons/index.ts

@@ -0,0 +1,16 @@
+export { IconDiscord } from './icon-discord'
+export { IconDocker } from './icon-docker'
+export { IconFacebook } from './icon-facebook'
+export { IconFigma } from './icon-figma'
+export { IconGithub } from './icon-github'
+export { IconGitlab } from './icon-gitlab'
+export { IconGmail } from './icon-gmail'
+export { IconMedium } from './icon-medium'
+export { IconNotion } from './icon-notion'
+export { IconSkype } from './icon-skype'
+export { IconSlack } from './icon-slack'
+export { IconStripe } from './icon-stripe'
+export { IconTelegram } from './icon-telegram'
+export { IconTrello } from './icon-trello'
+export { IconWhatsapp } from './icon-whatsapp'
+export { IconZoom } from './icon-zoom'

+ 3 - 3
src/components/coming-soon.tsx

@@ -1,11 +1,11 @@
-import { IconPlanet } from '@tabler/icons-react'
+import { Telescope } from 'lucide-react'
 
 export default function ComingSoon() {
   return (
     <div className='h-svh'>
       <div className='m-auto flex h-full w-full flex-col items-center justify-center gap-2'>
-        <IconPlanet size={72} />
-        <h1 className='text-4xl leading-tight font-bold'>Coming Soon 👀</h1>
+        <Telescope size={72} />
+        <h1 className='text-4xl leading-tight font-bold'>Coming Soon!</h1>
         <p className='text-muted-foreground text-center'>
           This page has not been created yet. <br />
           Stay tuned though!

+ 7 - 13
src/components/command-menu.tsx

@@ -1,12 +1,6 @@
 import React from 'react'
 import { useNavigate } from '@tanstack/react-router'
-import {
-  IconArrowRightDashed,
-  IconChevronRight,
-  IconDeviceLaptop,
-  IconMoon,
-  IconSun,
-} from '@tabler/icons-react'
+import { ArrowRight, ChevronRight, Laptop, Moon, Sun } from 'lucide-react'
 import { useSearch } from '@/context/search-context'
 import { useTheme } from '@/context/theme-context'
 import {
@@ -53,7 +47,7 @@ export function CommandMenu() {
                       }}
                     >
                       <div className='me-2 flex h-4 w-4 items-center justify-center'>
-                        <IconArrowRightDashed className='text-muted-foreground/80 size-2' />
+                        <ArrowRight className='text-muted-foreground/80 size-2' />
                       </div>
                       {navItem.title}
                     </CommandItem>
@@ -68,9 +62,9 @@ export function CommandMenu() {
                     }}
                   >
                     <div className='me-2 flex h-4 w-4 items-center justify-center'>
-                      <IconArrowRightDashed className='text-muted-foreground/80 size-2' />
+                      <ArrowRight className='text-muted-foreground/80 size-2' />
                     </div>
-                    {navItem.title} <IconChevronRight /> {subItem.title}
+                    {navItem.title} <ChevronRight /> {subItem.title}
                   </CommandItem>
                 ))
               })}
@@ -79,14 +73,14 @@ export function CommandMenu() {
           <CommandSeparator />
           <CommandGroup heading='Theme'>
             <CommandItem onSelect={() => runCommand(() => setTheme('light'))}>
-              <IconSun /> <span>Light</span>
+              <Sun /> <span>Light</span>
             </CommandItem>
             <CommandItem onSelect={() => runCommand(() => setTheme('dark'))}>
-              <IconMoon className='scale-90' />
+              <Moon className='scale-90' />
               <span>Dark</span>
             </CommandItem>
             <CommandItem onSelect={() => runCommand(() => setTheme('system'))}>
-              <IconDeviceLaptop />
+              <Laptop />
               <span>System</span>
             </CommandItem>
           </CommandGroup>

+ 3 - 3
src/components/dir-switch.tsx

@@ -1,4 +1,4 @@
-import { IconCheck } from '@tabler/icons-react'
+import { Check } from 'lucide-react'
 import { PilcrowLeftIcon, PilcrowRightIcon } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { useDirection } from '@/context/direction-context'
@@ -25,14 +25,14 @@ export function DirSwitch() {
       <DropdownMenuContent align='end'>
         <DropdownMenuItem onClick={() => setDir('ltr')}>
           Left to Right (LTR)
-          <IconCheck
+          <Check
             size={14}
             className={cn('ms-auto', dir !== 'ltr' && 'hidden')}
           />
         </DropdownMenuItem>
         <DropdownMenuItem onClick={() => setDir('rtl')}>
           Right to Left (RTL)
-          <IconCheck
+          <Check
             size={14}
             className={cn('ms-auto', dir !== 'rtl' && 'hidden')}
           />

+ 39 - 39
src/components/layout/data/sidebar-data.ts

@@ -1,24 +1,24 @@
 import {
-  IconBarrierBlock,
-  IconBrowserCheck,
-  IconBug,
-  IconChecklist,
-  IconError404,
-  IconHelp,
-  IconLayoutDashboard,
-  IconLock,
-  IconLockAccess,
-  IconMessages,
-  IconNotification,
-  IconPackages,
-  IconPalette,
-  IconServerOff,
-  IconSettings,
-  IconTool,
-  IconUserCog,
-  IconUserOff,
-  IconUsers,
-} from '@tabler/icons-react'
+  Construction,
+  LayoutDashboard,
+  Monitor,
+  Bug,
+  ListTodo,
+  FileX,
+  HelpCircle,
+  Lock,
+  Bell,
+  Package,
+  Palette,
+  ServerOff,
+  Settings,
+  Wrench,
+  UserCog,
+  UserX,
+  Users,
+  MessagesSquare,
+  ShieldCheck,
+} from 'lucide-react'
 import { AudioWaveform, Command, GalleryVerticalEnd } from 'lucide-react'
 import { ClerkLogo } from '@/assets/clerk-logo'
 import { type SidebarData } from '../types'
@@ -53,28 +53,28 @@ export const sidebarData: SidebarData = {
         {
           title: 'Dashboard',
           url: '/',
-          icon: IconLayoutDashboard,
+          icon: LayoutDashboard,
         },
         {
           title: 'Tasks',
           url: '/tasks',
-          icon: IconChecklist,
+          icon: ListTodo,
         },
         {
           title: 'Apps',
           url: '/apps',
-          icon: IconPackages,
+          icon: Package,
         },
         {
           title: 'Chats',
           url: '/chats',
           badge: '3',
-          icon: IconMessages,
+          icon: MessagesSquare,
         },
         {
           title: 'Users',
           url: '/users',
-          icon: IconUsers,
+          icon: Users,
         },
         {
           title: 'Secured by Clerk',
@@ -101,7 +101,7 @@ export const sidebarData: SidebarData = {
       items: [
         {
           title: 'Auth',
-          icon: IconLockAccess,
+          icon: ShieldCheck,
           items: [
             {
               title: 'Sign In',
@@ -127,32 +127,32 @@ export const sidebarData: SidebarData = {
         },
         {
           title: 'Errors',
-          icon: IconBug,
+          icon: Bug,
           items: [
             {
               title: 'Unauthorized',
               url: '/401',
-              icon: IconLock,
+              icon: Lock,
             },
             {
               title: 'Forbidden',
               url: '/403',
-              icon: IconUserOff,
+              icon: UserX,
             },
             {
               title: 'Not Found',
               url: '/404',
-              icon: IconError404,
+              icon: FileX,
             },
             {
               title: 'Internal Server Error',
               url: '/500',
-              icon: IconServerOff,
+              icon: ServerOff,
             },
             {
               title: 'Maintenance Error',
               url: '/503',
-              icon: IconBarrierBlock,
+              icon: Construction,
             },
           ],
         },
@@ -163,39 +163,39 @@ export const sidebarData: SidebarData = {
       items: [
         {
           title: 'Settings',
-          icon: IconSettings,
+          icon: Settings,
           items: [
             {
               title: 'Profile',
               url: '/settings',
-              icon: IconUserCog,
+              icon: UserCog,
             },
             {
               title: 'Account',
               url: '/settings/account',
-              icon: IconTool,
+              icon: Wrench,
             },
             {
               title: 'Appearance',
               url: '/settings/appearance',
-              icon: IconPalette,
+              icon: Palette,
             },
             {
               title: 'Notifications',
               url: '/settings/notifications',
-              icon: IconNotification,
+              icon: Bell,
             },
             {
               title: 'Display',
               url: '/settings/display',
-              icon: IconBrowserCheck,
+              icon: Monitor,
             },
           ],
         },
         {
           title: 'Help Center',
           url: '/help-center',
-          icon: IconHelp,
+          icon: HelpCircle,
         },
       ],
     },

+ 2 - 2
src/components/layout/top-nav.tsx

@@ -1,5 +1,5 @@
 import { Link } from '@tanstack/react-router'
-import { IconMenu } from '@tabler/icons-react'
+import { Menu } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { Button } from '@/components/ui/button'
 import {
@@ -25,7 +25,7 @@ export function TopNav({ className, links, ...props }: TopNavProps) {
         <DropdownMenu modal={false}>
           <DropdownMenuTrigger asChild>
             <Button size='icon' variant='outline'>
-              <IconMenu />
+              <Menu />
             </Button>
           </DropdownMenuTrigger>
           <DropdownMenuContent side='bottom' align='start'>

+ 2 - 2
src/components/learn-more.tsx

@@ -1,5 +1,5 @@
 import { Root, Content, Trigger } from '@radix-ui/react-popover'
-import { IconQuestionMark } from '@tabler/icons-react'
+import { CircleQuestionMark } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { Button } from '@/components/ui/button'
 import {
@@ -28,7 +28,7 @@ export function LearnMore({
       >
         <Button variant='outline' size='icon'>
           <span className='sr-only'>Learn more</span>
-          <IconQuestionMark className='size-3' />
+          <CircleQuestionMark className='size-4 [&>circle]:hidden' />
         </Button>
       </PopoverTrigger>
       <PopoverContent

+ 2 - 2
src/components/password-input.tsx

@@ -1,5 +1,5 @@
 import * as React from 'react'
-import { IconEye, IconEyeOff } from '@tabler/icons-react'
+import { Eye, EyeOff } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { Button } from './ui/button'
 
@@ -28,7 +28,7 @@ const PasswordInput = React.forwardRef<HTMLInputElement, PasswordInputProps>(
           className='text-muted-foreground absolute end-1 top-1/2 h-6 w-6 -translate-y-1/2 rounded-md'
           onClick={() => setShowPassword((prev) => !prev)}
         >
-          {showPassword ? <IconEye size={18} /> : <IconEyeOff size={18} />}
+          {showPassword ? <Eye size={18} /> : <EyeOff size={18} />}
         </Button>
       </div>
     )

+ 3 - 2
src/components/search.tsx

@@ -1,4 +1,4 @@
-import { IconSearch } from '@tabler/icons-react'
+import { SearchIcon } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { useSearch } from '@/context/search-context'
 import { Button } from './ui/button'
@@ -20,9 +20,10 @@ export function Search({ className = '', placeholder = 'Search' }: Props) {
       )}
       onClick={() => setOpen(true)}
     >
-      <IconSearch
+      <SearchIcon
         aria-hidden='true'
         className='absolute start-1.5 top-1/2 -translate-y-1/2'
+        size={16}
       />
       <span className='ms-3'>{placeholder}</span>
       <kbd className='bg-muted pointer-events-none absolute end-[0.3rem] top-[0.3rem] hidden h-5 items-center gap-1 rounded border px-1.5 font-mono text-[10px] font-medium opacity-100 select-none sm:flex'>

+ 2 - 2
src/components/select-dropdown.tsx

@@ -1,4 +1,4 @@
-import { IconLoader } from '@tabler/icons-react'
+import { Loader } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { FormControl } from '@/components/ui/form'
 import {
@@ -44,7 +44,7 @@ export function SelectDropdown({
         {isPending ? (
           <SelectItem disabled value='loading' className='h-14'>
             <div className='flex items-center justify-center gap-2'>
-              <IconLoader className='h-5 w-5 animate-spin' />
+              <Loader className='h-5 w-5 animate-spin' />
               {'  '}
               Loading...
             </div>

+ 6 - 6
src/components/theme-switch.tsx

@@ -1,5 +1,5 @@
 import { useEffect } from 'react'
-import { IconCheck, IconMoon, IconSun } from '@tabler/icons-react'
+import { Check, Moon, Sun } from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { useTheme } from '@/context/theme-context'
 import { Button } from '@/components/ui/button'
@@ -25,29 +25,29 @@ export function ThemeSwitch() {
     <DropdownMenu modal={false}>
       <DropdownMenuTrigger asChild>
         <Button variant='ghost' size='icon' className='scale-95 rounded-full'>
-          <IconSun className='size-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90' />
-          <IconMoon className='absolute size-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0' />
+          <Sun className='size-[1.2rem] scale-100 rotate-0 transition-all dark:scale-0 dark:-rotate-90' />
+          <Moon className='absolute size-[1.2rem] scale-0 rotate-90 transition-all dark:scale-100 dark:rotate-0' />
           <span className='sr-only'>Toggle theme</span>
         </Button>
       </DropdownMenuTrigger>
       <DropdownMenuContent align='end'>
         <DropdownMenuItem onClick={() => setTheme('light')}>
           Light{' '}
-          <IconCheck
+          <Check
             size={14}
             className={cn('ms-auto', theme !== 'light' && 'hidden')}
           />
         </DropdownMenuItem>
         <DropdownMenuItem onClick={() => setTheme('dark')}>
           Dark
-          <IconCheck
+          <Check
             size={14}
             className={cn('ms-auto', theme !== 'dark' && 'hidden')}
           />
         </DropdownMenuItem>
         <DropdownMenuItem onClick={() => setTheme('system')}>
           System
-          <IconCheck
+          <Check
             size={14}
             className={cn('ms-auto', theme !== 'system' && 'hidden')}
           />

+ 31 - 31
src/features/apps/data/apps.tsx

@@ -1,109 +1,109 @@
 import {
-  IconBrandDiscord,
-  IconBrandDocker,
-  IconBrandFigma,
-  IconBrandGithub,
-  IconBrandGitlab,
-  IconBrandGmail,
-  IconBrandMedium,
-  IconBrandNotion,
-  IconBrandSkype,
-  IconBrandSlack,
-  IconBrandStripe,
-  IconBrandTelegram,
-  IconBrandTrello,
-  IconBrandWhatsapp,
-  IconBrandZoom,
-} from '@tabler/icons-react'
+  IconTelegram,
+  IconNotion,
+  IconFigma,
+  IconTrello,
+  IconSlack,
+  IconZoom,
+  IconStripe,
+  IconGmail,
+  IconMedium,
+  IconSkype,
+  IconDocker,
+  IconGithub,
+  IconGitlab,
+  IconDiscord,
+  IconWhatsapp,
+} from '@/assets/brand-icons'
 
 export const apps = [
   {
     name: 'Telegram',
-    logo: <IconBrandTelegram />,
+    logo: <IconTelegram />,
     connected: false,
     desc: 'Connect with Telegram for real-time communication.',
   },
   {
     name: 'Notion',
-    logo: <IconBrandNotion />,
+    logo: <IconNotion />,
     connected: true,
     desc: 'Effortlessly sync Notion pages for seamless collaboration.',
   },
   {
     name: 'Figma',
-    logo: <IconBrandFigma />,
+    logo: <IconFigma />,
     connected: true,
     desc: 'View and collaborate on Figma designs in one place.',
   },
   {
     name: 'Trello',
-    logo: <IconBrandTrello />,
+    logo: <IconTrello />,
     connected: false,
     desc: 'Sync Trello cards for streamlined project management.',
   },
   {
     name: 'Slack',
-    logo: <IconBrandSlack />,
+    logo: <IconSlack />,
     connected: false,
     desc: 'Integrate Slack for efficient team communication',
   },
   {
     name: 'Zoom',
-    logo: <IconBrandZoom />,
+    logo: <IconZoom />,
     connected: true,
     desc: 'Host Zoom meetings directly from the dashboard.',
   },
   {
     name: 'Stripe',
-    logo: <IconBrandStripe />,
+    logo: <IconStripe />,
     connected: false,
     desc: 'Easily manage Stripe transactions and payments.',
   },
   {
     name: 'Gmail',
-    logo: <IconBrandGmail />,
+    logo: <IconGmail />,
     connected: true,
     desc: 'Access and manage Gmail messages effortlessly.',
   },
   {
     name: 'Medium',
-    logo: <IconBrandMedium />,
+    logo: <IconMedium />,
     connected: false,
     desc: 'Explore and share Medium stories on your dashboard.',
   },
   {
     name: 'Skype',
-    logo: <IconBrandSkype />,
+    logo: <IconSkype />,
     connected: false,
     desc: 'Connect with Skype contacts seamlessly.',
   },
   {
     name: 'Docker',
-    logo: <IconBrandDocker />,
+    logo: <IconDocker />,
     connected: false,
     desc: 'Effortlessly manage Docker containers on your dashboard.',
   },
   {
     name: 'GitHub',
-    logo: <IconBrandGithub />,
+    logo: <IconGithub />,
     connected: false,
     desc: 'Streamline code management with GitHub integration.',
   },
   {
     name: 'GitLab',
-    logo: <IconBrandGitlab />,
+    logo: <IconGitlab />,
     connected: false,
     desc: 'Efficiently manage code projects with GitLab integration.',
   },
   {
     name: 'Discord',
-    logo: <IconBrandDiscord />,
+    logo: <IconDiscord />,
     connected: false,
     desc: 'Connect with Discord for seamless team communication.',
   },
   {
     name: 'WhatsApp',
-    logo: <IconBrandWhatsapp />,
+    logo: <IconWhatsapp />,
     connected: false,
     desc: 'Easily integrate WhatsApp for direct messaging.',
   },

+ 4 - 8
src/features/apps/index.tsx

@@ -1,9 +1,5 @@
 import { useState } from 'react'
-import {
-  IconAdjustmentsHorizontal,
-  IconSortAscendingLetters,
-  IconSortDescendingLetters,
-} from '@tabler/icons-react'
+import { SlidersHorizontal, ArrowUpAZ, ArrowDownAZ } from 'lucide-react'
 import { Button } from '@/components/ui/button'
 import { Input } from '@/components/ui/input'
 import {
@@ -91,19 +87,19 @@ export default function Apps() {
           <Select value={sort} onValueChange={setSort}>
             <SelectTrigger className='w-16'>
               <SelectValue>
-                <IconAdjustmentsHorizontal size={18} />
+                <SlidersHorizontal size={18} />
               </SelectValue>
             </SelectTrigger>
             <SelectContent align='end'>
               <SelectItem value='ascending'>
                 <div className='flex items-center gap-4'>
-                  <IconSortAscendingLetters size={16} />
+                  <ArrowUpAZ size={16} />
                   <span>Ascending</span>
                 </div>
               </SelectItem>
               <SelectItem value='descending'>
                 <div className='flex items-center gap-4'>
-                  <IconSortDescendingLetters size={16} />
+                  <ArrowDownAZ size={16} />
                   <span>Descending</span>
                 </div>
               </SelectItem>

+ 3 - 3
src/features/auth/sign-in/components/user-auth-form.tsx

@@ -3,7 +3,7 @@ import { z } from 'zod'
 import { useForm } from 'react-hook-form'
 import { zodResolver } from '@hookform/resolvers/zod'
 import { Link } from '@tanstack/react-router'
-import { IconBrandFacebook, IconBrandGithub } from '@tabler/icons-react'
+import { IconFacebook, IconGithub } from '@/assets/brand-icons'
 import { cn } from '@/lib/utils'
 import { Button } from '@/components/ui/button'
 import {
@@ -106,10 +106,10 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
 
         <div className='grid grid-cols-2 gap-2'>
           <Button variant='outline' type='button' disabled={isLoading}>
-            <IconBrandGithub className='h-4 w-4' /> GitHub
+            <IconGithub className='h-4 w-4' /> GitHub
           </Button>
           <Button variant='outline' type='button' disabled={isLoading}>
-            <IconBrandFacebook className='h-4 w-4' /> Facebook
+            <IconFacebook className='h-4 w-4' /> Facebook
           </Button>
         </div>
       </form>

+ 3 - 3
src/features/auth/sign-up/components/sign-up-form.tsx

@@ -2,7 +2,7 @@ import { HTMLAttributes, useState } from 'react'
 import { z } from 'zod'
 import { useForm } from 'react-hook-form'
 import { zodResolver } from '@hookform/resolvers/zod'
-import { IconBrandFacebook, IconBrandGithub } from '@tabler/icons-react'
+import { IconFacebook, IconGithub } from '@/assets/brand-icons'
 import { cn } from '@/lib/utils'
 import { Button } from '@/components/ui/button'
 import {
@@ -125,7 +125,7 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
             type='button'
             disabled={isLoading}
           >
-            <IconBrandGithub className='h-4 w-4' /> GitHub
+            <IconGithub className='h-4 w-4' /> GitHub
           </Button>
           <Button
             variant='outline'
@@ -133,7 +133,7 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
             type='button'
             disabled={isLoading}
           >
-            <IconBrandFacebook className='h-4 w-4' /> Facebook
+            <IconFacebook className='h-4 w-4' /> Facebook
           </Button>
         </div>
       </form>

+ 3 - 3
src/features/chats/components/new-chat.tsx

@@ -1,5 +1,5 @@
 import { useEffect, useState } from 'react'
-import { IconCheck, IconX } from '@tabler/icons-react'
+import { Check, X } from 'lucide-react'
 import { showSubmittedData } from '@/utils/show-submitted-data'
 import { Badge } from '@/components/ui/badge'
 import { Button } from '@/components/ui/button'
@@ -68,7 +68,7 @@ export function NewChat({ users, onOpenChange, open }: Props) {
                   }}
                   onClick={() => handleRemoveUser(user.id)}
                 >
-                  <IconX className='text-muted-foreground hover:text-foreground h-3 w-3' />
+                  <X className='text-muted-foreground hover:text-foreground h-3 w-3' />
                 </button>
               </Badge>
             ))}
@@ -104,7 +104,7 @@ export function NewChat({ users, onOpenChange, open }: Props) {
                     </div>
 
                     {selectedUsers.find((u) => u.id === user.id) && (
-                      <IconCheck className='h-4 w-4' />
+                      <Check className='h-4 w-4' />
                     )}
                   </CommandItem>
                 ))}

+ 25 - 28
src/features/chats/index.tsx

@@ -2,18 +2,18 @@ import { useState } from 'react'
 import { Fragment } from 'react/jsx-runtime'
 import { format } from 'date-fns'
 import {
-  IconArrowLeft,
-  IconDotsVertical,
-  IconEdit,
-  IconMessages,
-  IconPaperclip,
-  IconPhone,
-  IconPhotoPlus,
-  IconPlus,
-  IconSearch,
-  IconSend,
-  IconVideo,
-} from '@tabler/icons-react'
+  ArrowLeft,
+  MoreVertical,
+  Edit,
+  Paperclip,
+  Phone,
+  ImagePlus,
+  Plus,
+  Search as SearchIcon,
+  Send,
+  Video,
+  MessagesSquare,
+} from 'lucide-react'
 import { cn } from '@/lib/utils'
 import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
 import { Button } from '@/components/ui/button'
@@ -81,7 +81,7 @@ export default function Chats() {
               <div className='flex items-center justify-between py-2'>
                 <div className='flex gap-2'>
                   <h1 className='text-2xl font-bold'>Inbox</h1>
-                  <IconMessages size={20} />
+                  <MessagesSquare size={20} />
                 </div>
 
                 <Button
@@ -90,12 +90,12 @@ export default function Chats() {
                   onClick={() => setCreateConversationDialog(true)}
                   className='rounded-lg'
                 >
-                  <IconEdit size={24} className='stroke-muted-foreground' />
+                  <Edit size={24} className='stroke-muted-foreground' />
                 </Button>
               </div>
 
               <label className='border-input focus-within:ring-ring flex h-12 w-full items-center space-x-0 rounded-md border ps-2 focus-within:ring-1 focus-within:outline-hidden'>
-                <IconSearch size={15} className='me-2 stroke-slate-500' />
+                <SearchIcon size={15} className='me-2 stroke-slate-500' />
                 <span className='sr-only'>Search</span>
                 <input
                   type='text'
@@ -168,7 +168,7 @@ export default function Chats() {
                     className='-ms-2 h-full sm:hidden'
                     onClick={() => setMobileSelectedUser(null)}
                   >
-                    <IconArrowLeft className='rtl:rotate-180' />
+                    <ArrowLeft className='rtl:rotate-180' />
                   </Button>
                   <div className='flex items-center gap-2 lg:gap-4'>
                     <Avatar className='size-9 lg:size-11'>
@@ -196,21 +196,21 @@ export default function Chats() {
                     variant='ghost'
                     className='hidden size-8 rounded-full sm:inline-flex lg:size-10'
                   >
-                    <IconVideo size={22} className='stroke-muted-foreground' />
+                    <Video size={22} className='stroke-muted-foreground' />
                   </Button>
                   <Button
                     size='icon'
                     variant='ghost'
                     className='hidden size-8 rounded-full sm:inline-flex lg:size-10'
                   >
-                    <IconPhone size={22} className='stroke-muted-foreground' />
+                    <Phone size={22} className='stroke-muted-foreground' />
                   </Button>
                   <Button
                     size='icon'
                     variant='ghost'
                     className='h-10 rounded-md sm:h-8 sm:w-4 lg:h-10 lg:w-6'
                   >
-                    <IconDotsVertical className='stroke-muted-foreground sm:size-5' />
+                    <MoreVertical className='stroke-muted-foreground sm:size-5' />
                   </Button>
                 </div>
               </div>
@@ -259,10 +259,7 @@ export default function Chats() {
                         variant='ghost'
                         className='h-8 rounded-md'
                       >
-                        <IconPlus
-                          size={20}
-                          className='stroke-muted-foreground'
-                        />
+                        <Plus size={20} className='stroke-muted-foreground' />
                       </Button>
                       <Button
                         size='icon'
@@ -270,7 +267,7 @@ export default function Chats() {
                         variant='ghost'
                         className='hidden h-8 rounded-md lg:inline-flex'
                       >
-                        <IconPhotoPlus
+                        <ImagePlus
                           size={20}
                           className='stroke-muted-foreground'
                         />
@@ -281,7 +278,7 @@ export default function Chats() {
                         variant='ghost'
                         className='hidden h-8 rounded-md lg:inline-flex'
                       >
-                        <IconPaperclip
+                        <Paperclip
                           size={20}
                           className='stroke-muted-foreground'
                         />
@@ -300,11 +297,11 @@ export default function Chats() {
                       size='icon'
                       className='hidden sm:inline-flex'
                     >
-                      <IconSend size={20} />
+                      <Send size={20} />
                     </Button>
                   </div>
                   <Button className='h-full sm:hidden'>
-                    <IconSend size={18} /> Send
+                    <Send size={18} /> Send
                   </Button>
                 </form>
               </div>
@@ -317,7 +314,7 @@ export default function Chats() {
             >
               <div className='flex flex-col items-center space-y-6'>
                 <div className='border-border flex size-16 items-center justify-center rounded-full border-2'>
-                  <IconMessages className='size-8' />
+                  <MessagesSquare className='size-8' />
                 </div>
                 <div className='space-y-2 text-center'>
                   <h1 className='text-xl font-semibold'>Your messages</h1>

+ 6 - 12
src/features/settings/index.tsx

@@ -1,11 +1,5 @@
 import { Outlet } from '@tanstack/react-router'
-import {
-  IconBrowserCheck,
-  IconNotification,
-  IconPalette,
-  IconTool,
-  IconUser,
-} from '@tabler/icons-react'
+import { Monitor, Bell, Palette, Wrench, UserCog } from 'lucide-react'
 import { Separator } from '@/components/ui/separator'
 import { Header } from '@/components/layout/header'
 import { Main } from '@/components/layout/main'
@@ -52,27 +46,27 @@ export default function Settings() {
 const sidebarNavItems = [
   {
     title: 'Profile',
-    icon: <IconUser size={18} />,
     href: '/settings',
+    icon: <UserCog size={18} />,
   },
   {
     title: 'Account',
-    icon: <IconTool size={18} />,
     href: '/settings/account',
+    icon: <Wrench size={18} />,
   },
   {
     title: 'Appearance',
-    icon: <IconPalette size={18} />,
     href: '/settings/appearance',
+    icon: <Palette size={18} />,
   },
   {
     title: 'Notifications',
-    icon: <IconNotification size={18} />,
     href: '/settings/notifications',
+    icon: <Bell size={18} />,
   },
   {
     title: 'Display',
-    icon: <IconBrowserCheck size={18} />,
     href: '/settings/display',
+    icon: <Monitor size={18} />,
   },
 ]

+ 2 - 2
src/features/tasks/components/data-table-row-actions.tsx

@@ -1,6 +1,6 @@
 import { DotsHorizontalIcon } from '@radix-ui/react-icons'
 import { Row } from '@tanstack/react-table'
-import { IconTrash } from '@tabler/icons-react'
+import { Trash2 } from 'lucide-react'
 import { Button } from '@/components/ui/button'
 import {
   DropdownMenu,
@@ -74,7 +74,7 @@ export function DataTableRowActions<TData>({
         >
           Delete
           <DropdownMenuShortcut>
-            <IconTrash size={16} />
+            <Trash2 size={16} />
           </DropdownMenuShortcut>
         </DropdownMenuItem>
       </DropdownMenuContent>

+ 3 - 3
src/features/tasks/components/tasks-primary-buttons.tsx

@@ -1,4 +1,4 @@
-import { IconDownload, IconPlus } from '@tabler/icons-react'
+import { Download, Plus } from 'lucide-react'
 import { Button } from '@/components/ui/button'
 import { useTasks } from '../context/tasks-context'
 
@@ -11,10 +11,10 @@ export function TasksPrimaryButtons() {
         className='space-x-1'
         onClick={() => setOpen('import')}
       >
-        <span>Import</span> <IconDownload size={18} />
+        <span>Import</span> <Download size={18} />
       </Button>
       <Button className='space-x-1' onClick={() => setOpen('create')}>
-        <span>Create</span> <IconPlus size={18} />
+        <span>Create</span> <Plus size={18} />
       </Button>
     </div>
   )

+ 23 - 17
src/features/tasks/data/data.tsx

@@ -1,13 +1,14 @@
 import {
-  IconArrowDown,
-  IconArrowRight,
-  IconArrowUp,
-  IconCircle,
-  IconCircleCheck,
-  IconCircleX,
-  IconExclamationCircle,
-  IconStopwatch,
-} from '@tabler/icons-react'
+  ArrowDown,
+  ArrowRight,
+  ArrowUp,
+  Circle,
+  CheckCircle,
+  AlertCircle,
+  Timer,
+  HelpCircle,
+  CircleOff,
+} from 'lucide-react'
 
 export const labels = [
   {
@@ -28,27 +29,27 @@ export const statuses = [
   {
     value: 'backlog',
     label: 'Backlog',
-    icon: IconExclamationCircle,
+    icon: HelpCircle,
   },
   {
     value: 'todo',
     label: 'Todo',
-    icon: IconCircle,
+    icon: Circle,
   },
   {
     value: 'in progress',
     label: 'In Progress',
-    icon: IconStopwatch,
+    icon: Timer,
   },
   {
     value: 'done',
     label: 'Done',
-    icon: IconCircleCheck,
+    icon: CheckCircle,
   },
   {
     value: 'canceled',
     label: 'Canceled',
-    icon: IconCircleX,
+    icon: CircleOff,
   },
 ]
 
@@ -56,16 +57,21 @@ export const priorities = [
   {
     label: 'Low',
     value: 'low',
-    icon: IconArrowDown,
+    icon: ArrowDown,
   },
   {
     label: 'Medium',
     value: 'medium',
-    icon: IconArrowRight,
+    icon: ArrowRight,
   },
   {
     label: 'High',
     value: 'high',
-    icon: IconArrowUp,
+    icon: ArrowUp,
+  },
+  {
+    label: 'Critical',
+    value: 'critical',
+    icon: AlertCircle,
   },
 ]

+ 3 - 3
src/features/users/components/data-table-row-actions.tsx

@@ -1,6 +1,6 @@
 import { DotsHorizontalIcon } from '@radix-ui/react-icons'
 import { Row } from '@tanstack/react-table'
-import { IconEdit, IconTrash } from '@tabler/icons-react'
+import { Trash2, UserPen } from 'lucide-react'
 import { Button } from '@/components/ui/button'
 import {
   DropdownMenu,
@@ -40,7 +40,7 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
           >
             Edit
             <DropdownMenuShortcut>
-              <IconEdit size={16} />
+              <UserPen size={16} />
             </DropdownMenuShortcut>
           </DropdownMenuItem>
           <DropdownMenuSeparator />
@@ -53,7 +53,7 @@ export function DataTableRowActions({ row }: DataTableRowActionsProps) {
           >
             Delete
             <DropdownMenuShortcut>
-              <IconTrash size={16} />
+              <Trash2 size={16} />
             </DropdownMenuShortcut>
           </DropdownMenuItem>
         </DropdownMenuContent>

+ 2 - 2
src/features/users/components/data-table-toolbar.tsx

@@ -2,7 +2,7 @@ import { Cross2Icon } from '@radix-ui/react-icons'
 import { Table } from '@tanstack/react-table'
 import { Button } from '@/components/ui/button'
 import { Input } from '@/components/ui/input'
-import { userTypes } from '../data/data'
+import { roles } from '../data/data'
 import { DataTableFacetedFilter } from './data-table-faceted-filter'
 import { DataTableViewOptions } from './data-table-view-options'
 
@@ -45,7 +45,7 @@ export function DataTableToolbar<TData>({
             <DataTableFacetedFilter
               column={table.getColumn('role')}
               title='Role'
-              options={userTypes.map((t) => ({ ...t }))}
+              options={roles.map((t) => ({ ...t }))}
             />
           )}
         </div>

+ 2 - 2
src/features/users/components/users-action-dialog.tsx

@@ -24,7 +24,7 @@ import {
 import { Input } from '@/components/ui/input'
 import { PasswordInput } from '@/components/password-input'
 import { SelectDropdown } from '@/components/select-dropdown'
-import { userTypes } from '../data/data'
+import { roles } from '../data/data'
 import { User } from '../data/schema'
 
 const formSchema = z
@@ -260,7 +260,7 @@ export function UsersActionDialog({ currentRow, open, onOpenChange }: Props) {
                       onValueChange={field.onChange}
                       placeholder='Select a role'
                       className='col-span-4'
-                      items={userTypes.map(({ label, value }) => ({
+                      items={roles.map(({ label, value }) => ({
                         label,
                         value,
                       }))}

+ 2 - 2
src/features/users/components/users-columns.tsx

@@ -3,7 +3,7 @@ import { cn } from '@/lib/utils'
 import { Badge } from '@/components/ui/badge'
 import { Checkbox } from '@/components/ui/checkbox'
 import LongText from '@/components/long-text'
-import { callTypes, userTypes } from '../data/data'
+import { callTypes, roles } from '../data/data'
 import { User } from '../data/schema'
 import { DataTableColumnHeader } from './data-table-column-header'
 import { DataTableRowActions } from './data-table-row-actions'
@@ -114,7 +114,7 @@ export const columns: ColumnDef<User>[] = [
     ),
     cell: ({ row }) => {
       const { role } = row.original
-      const userType = userTypes.find(({ value }) => value === role)
+      const userType = roles.find(({ value }) => value === role)
 
       if (!userType) {
         return null

+ 2 - 2
src/features/users/components/users-delete-dialog.tsx

@@ -1,7 +1,7 @@
 'use client'
 
 import { useState } from 'react'
-import { IconAlertTriangle } from '@tabler/icons-react'
+import { AlertTriangle } from 'lucide-react'
 import { showSubmittedData } from '@/utils/show-submitted-data'
 import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
 import { Input } from '@/components/ui/input'
@@ -33,7 +33,7 @@ export function UsersDeleteDialog({ open, onOpenChange, currentRow }: Props) {
       disabled={value.trim() !== currentRow.username}
       title={
         <span className='text-destructive'>
-          <IconAlertTriangle
+          <AlertTriangle
             className='stroke-destructive me-1 inline-block'
             size={18}
           />{' '}

+ 5 - 5
src/features/users/components/users-invite-dialog.tsx

@@ -1,7 +1,7 @@
 import { z } from 'zod'
 import { useForm } from 'react-hook-form'
 import { zodResolver } from '@hookform/resolvers/zod'
-import { IconMailPlus, IconSend } from '@tabler/icons-react'
+import { MailPlus, Send } from 'lucide-react'
 import { showSubmittedData } from '@/utils/show-submitted-data'
 import { Button } from '@/components/ui/button'
 import {
@@ -24,7 +24,7 @@ import {
 import { Input } from '@/components/ui/input'
 import { Textarea } from '@/components/ui/textarea'
 import { SelectDropdown } from '@/components/select-dropdown'
-import { userTypes } from '../data/data'
+import { roles } from '../data/data'
 
 const formSchema = z.object({
   email: z.email({
@@ -64,7 +64,7 @@ export function UsersInviteDialog({ open, onOpenChange }: Props) {
       <DialogContent className='sm:max-w-md'>
         <DialogHeader className='text-start'>
           <DialogTitle className='flex items-center gap-2'>
-            <IconMailPlus /> Invite User
+            <MailPlus /> Invite User
           </DialogTitle>
           <DialogDescription>
             Invite new user to join your team by sending them an email
@@ -104,7 +104,7 @@ export function UsersInviteDialog({ open, onOpenChange }: Props) {
                     defaultValue={field.value}
                     onValueChange={field.onChange}
                     placeholder='Select a role'
-                    items={userTypes.map(({ label, value }) => ({
+                    items={roles.map(({ label, value }) => ({
                       label,
                       value,
                     }))}
@@ -137,7 +137,7 @@ export function UsersInviteDialog({ open, onOpenChange }: Props) {
             <Button variant='outline'>Cancel</Button>
           </DialogClose>
           <Button type='submit' form='user-invite-form'>
-            Invite <IconSend />
+            Invite <Send />
           </Button>
         </DialogFooter>
       </DialogContent>

+ 3 - 3
src/features/users/components/users-primary-buttons.tsx

@@ -1,4 +1,4 @@
-import { IconMailPlus, IconUserPlus } from '@tabler/icons-react'
+import { MailPlus, UserPlus } from 'lucide-react'
 import { Button } from '@/components/ui/button'
 import { useUsers } from '../context/users-context'
 
@@ -11,10 +11,10 @@ export function UsersPrimaryButtons() {
         className='space-x-1'
         onClick={() => setOpen('invite')}
       >
-        <span>Invite User</span> <IconMailPlus size={18} />
+        <span>Invite User</span> <MailPlus size={18} />
       </Button>
       <Button className='space-x-1' onClick={() => setOpen('add')}>
-        <span>Add User</span> <IconUserPlus size={18} />
+        <span>Add User</span> <UserPlus size={18} />
       </Button>
     </div>
   )

+ 6 - 11
src/features/users/data/data.ts

@@ -1,9 +1,4 @@
-import {
-  IconCash,
-  IconShield,
-  IconUsersGroup,
-  IconUserShield,
-} from '@tabler/icons-react'
+import { Shield, UserCheck, Users, CreditCard } from 'lucide-react'
 import { UserStatus } from './schema'
 
 export const callTypes = new Map<UserStatus, string>([
@@ -16,25 +11,25 @@ export const callTypes = new Map<UserStatus, string>([
   ],
 ])
 
-export const userTypes = [
+export const roles = [
   {
     label: 'Superadmin',
     value: 'superadmin',
-    icon: IconShield,
+    icon: Shield,
   },
   {
     label: 'Admin',
     value: 'admin',
-    icon: IconUserShield,
+    icon: UserCheck,
   },
   {
     label: 'Manager',
     value: 'manager',
-    icon: IconUsersGroup,
+    icon: Users,
   },
   {
     label: 'Cashier',
     value: 'cashier',
-    icon: IconCash,
+    icon: CreditCard,
   },
 ] as const

+ 3 - 3
src/routes/clerk/_authenticated/user-management.tsx

@@ -5,8 +5,8 @@ import {
   useNavigate,
   useRouter,
 } from '@tanstack/react-router'
-import { IconArrowUpRight, IconLoader2 } from '@tabler/icons-react'
 import { SignedIn, useAuth, UserButton } from '@clerk/clerk-react'
+import { ExternalLink, Loader2 } from 'lucide-react'
 import { ClerkLogo } from '@/assets/clerk-logo'
 import { Button } from '@/components/ui/button'
 import { Header } from '@/components/layout/header'
@@ -33,7 +33,7 @@ function UserManagement() {
   if (!isLoaded) {
     return (
       <div className='flex h-svh items-center justify-center'>
-        <IconLoader2 className='size-8 animate-spin' />
+        <Loader2 className='size-8 animate-spin' />
       </div>
     )
   }
@@ -82,7 +82,7 @@ function UserManagement() {
                     <p className='mt-4'>
                       You can sign out or manage/delete your account via the
                       User Profile menu in the top-right corner of the page.
-                      <IconArrowUpRight className='inline-block size-4' />
+                      <ExternalLink className='inline-block size-4' />
                     </p>
                   </LearnMore>
                 </div>

+ 3 - 3
src/routes/clerk/route.tsx

@@ -1,6 +1,6 @@
 import { createFileRoute, Outlet } from '@tanstack/react-router'
-import { IconExternalLink, IconKeyOff } from '@tabler/icons-react'
 import { ClerkProvider } from '@clerk/clerk-react'
+import { ExternalLink, Key } from 'lucide-react'
 import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
 import { Separator } from '@/components/ui/separator'
 import { SidebarTrigger } from '@/components/ui/sidebar'
@@ -46,7 +46,7 @@ function MissingClerkPubKey() {
       <Main className='flex flex-col items-center justify-start'>
         <div className='max-w-2xl'>
           <Alert>
-            <IconKeyOff className='size-4' />
+            <Key className='size-4' />
             <AlertTitle>No Publishable Key Found!</AlertTitle>
             <AlertDescription>
               <p className='text-balance'>
@@ -68,7 +68,7 @@ function MissingClerkPubKey() {
                 >
                   Clerk
                   <sup>
-                    <IconExternalLink className='inline-block size-4' />
+                    <ExternalLink className='inline-block size-4' />
                   </sup>
                 </a>{' '}
                 Dashboard, navigate to the API keys page.

+ 0 - 4
vite.config.ts

@@ -17,10 +17,6 @@ export default defineConfig({
   resolve: {
     alias: {
       '@': path.resolve(__dirname, './src'),
-
-      // fix loading all icon chunks in dev mode
-      // https://github.com/tabler/tabler-icons/issues/1233
-      '@tabler/icons-react': '@tabler/icons-react/dist/esm/icons/index.mjs',
     },
   },
 })