uibee 2.8.7 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ type ConfirmPopupProps = {
2
+ isOpen: boolean;
3
+ header: string;
4
+ description?: string;
5
+ confirmText?: string;
6
+ cancelText?: string;
7
+ onConfirm: () => void;
8
+ onCancel: () => void;
9
+ variant?: 'danger' | 'warning' | 'default';
10
+ };
11
+ export default function ConfirmPopup({ isOpen, header, description, confirmText, cancelText, onConfirm, onCancel, variant, }: ConfirmPopupProps): import("react/jsx-runtime").JSX.Element | null;
12
+ export {};
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { TriangleAlert } from 'lucide-react';
4
+ export default function ConfirmPopup({ isOpen, header, description, confirmText = 'Confirm', cancelText = 'Cancel', onConfirm, onCancel, variant = 'default', }) {
5
+ if (!isOpen)
6
+ return null;
7
+ const confirmBg = variant === 'danger'
8
+ ? 'bg-red-700/80 outline-red-700 hover:bg-red-700'
9
+ : variant === 'warning'
10
+ ? 'bg-yellow-600/80 outline-yellow-600 hover:bg-yellow-600'
11
+ : 'bg-login/70 outline-login hover:bg-login/90';
12
+ return (_jsxs("div", { role: 'dialog', "aria-modal": 'true', "aria-labelledby": 'confirm-popup-header', className: 'fixed inset-0 z-50 flex items-center justify-center', onClick: onCancel, children: [_jsx("div", { className: 'absolute inset-0 bg-black/60 backdrop-blur-sm' }), _jsxs("div", { className: '\n relative z-10 w-full max-w-md mx-4\n bg-login-800 border border-login-500/50 rounded-xl\n shadow-2xl p-6 flex flex-col gap-4\n ', onClick: (e) => e.stopPropagation(), children: [_jsxs("div", { className: 'flex items-center gap-3', children: [variant !== 'default' && (_jsx(TriangleAlert, { className: `w-6 h-6 shrink-0 ${variant === 'danger' ? 'stroke-red-400' : 'stroke-yellow-400'}` })), _jsx("h2", { id: 'confirm-popup-header', className: 'text-login-50 text-lg font-bold leading-snug', children: header })] }), description && (_jsx("p", { className: 'text-login-100 text-sm leading-relaxed', children: description })), _jsxs("div", { className: 'flex justify-end gap-3 mt-1', children: [_jsx("button", { type: 'button', onClick: onCancel, className: '\n cursor-pointer px-4 py-1.5 rounded-md text-sm font-medium\n bg-login-500/60 text-login-50 outline outline-login-500/60\n hover:bg-login-500/90 focus:outline-none select-none\n transition-colors duration-150\n ', children: cancelText }), _jsx("button", { type: 'button', onClick: onConfirm, className: `
13
+ cursor-pointer px-4 py-1.5 rounded-md text-sm font-bold
14
+ text-white outline focus:outline-none select-none
15
+ transition-colors duration-150
16
+ ${confirmBg}
17
+ `, children: confirmText })] })] })] }));
18
+ }
@@ -20,3 +20,4 @@ export { default as LoginPage } from './login/loginPage';
20
20
  export { default as Toaster, toast } from './toast/toaster';
21
21
  export { default as Button } from './buttons/button';
22
22
  export { default as Alert } from './alert/alert';
23
+ export { default as ConfirmPopup } from './confirm/confirmPopup';
@@ -29,3 +29,5 @@ export { default as Toaster, toast } from './toast/toaster';
29
29
  export { default as Button } from './buttons/button';
30
30
  // Alert
31
31
  export { default as Alert } from './alert/alert';
32
+ // Confirm
33
+ export { default as ConfirmPopup } from './confirm/confirmPopup';
@@ -7,10 +7,11 @@ export type NavbarProps = {
7
7
  theme?: string;
8
8
  disableThemeToggle?: boolean;
9
9
  token?: string | null;
10
- disableAuthButton?: boolean;
11
- profileURL?: string;
10
+ profilePath?: string;
11
+ loginPath: string;
12
+ logoutPath: string;
12
13
  className?: string;
13
14
  innerClassName?: string;
14
15
  children: React.ReactNode;
15
16
  };
16
- export default function Navbar({ lang, onlyLogo, disableLanguageToggle, disableThemeToggle, token, disableAuthButton, profileURL, className, innerClassName, children, }: NavbarProps): import("react/jsx-runtime").JSX.Element;
17
+ export default function Navbar({ lang, onlyLogo, disableLanguageToggle, disableThemeToggle, token, profilePath, loginPath, logoutPath, className, innerClassName, children, }: NavbarProps): import("react/jsx-runtime").JSX.Element;
@@ -11,10 +11,13 @@ function hamburgerStyle(isOpen, isSecond) {
11
11
  ? `top-6 ${isSecond ? 'rotate-45' : '-rotate-45'}`
12
12
  : isSecond ? 'top-7' : 'top-4'}`;
13
13
  }
14
- export default function Navbar({ lang, onlyLogo, disableLanguageToggle, disableThemeToggle, token, disableAuthButton, profileURL, className, innerClassName, children, }) {
14
+ export default function Navbar({ lang, onlyLogo, disableLanguageToggle, disableThemeToggle, token, profilePath, loginPath, logoutPath, className, innerClassName, children, }) {
15
15
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
16
16
  return (_jsx("div", { className: `${isMobileMenuOpen ? 'bg-[#181818f0]' : 'bg-[#18181899]'} backdrop-blur-xl fixed top-0 z-900 w-full ${className}`, children: _jsxs("div", { className: `flex w-full max-w-6xl m-auto p-2 transition duration-500 800px:justify-between 800px:p-4 ${isMobileMenuOpen ? 'h-screen bg-login-900/20 800px:h-20' : ''} ${innerClassName}
17
- `, children: [_jsx("div", { className: 'block h-12 p-1 800px:p-0', children: _jsx(Link, { href: '/', onClick: () => setIsMobileMenuOpen(false), children: _jsx(LogoSmall, {}) }) }), onlyLogo ? null : (_jsxs(_Fragment, { children: [_jsx("nav", { className: 'hidden 800px:flex 800px:justify-between 800px:items-center 800px:w-fill max-w-200', children: children }), _jsxs("nav", { className: 'flex w-[calc(100vw-8rem)] justify-end h-12 800px:w-fit', children: [!disableThemeToggle && _jsx(ThemeToggle, {}), !disableLanguageToggle && _jsx(LanguageToggle, { language: lang }), !disableAuthButton && _jsx(AuthButton, { profileURL: profileURL, token: token })] }), _jsxs("button", { className: 'w-12 h-12 relative cursor-pointer bg-none border-none 800px:hidden', onClick: () => setIsMobileMenuOpen(!isMobileMenuOpen), children: [_jsx("div", { className: hamburgerStyle(isMobileMenuOpen) }), _jsx("div", { className: hamburgerStyle(isMobileMenuOpen, true) })] }), _jsx("nav", { className: `fixed top-16 w-[calc(100%-2rem)] max-w-140 mx-auto left-0 right-0 800px:hidden
17
+ `, children: [_jsx("div", { className: 'block h-12 p-1 800px:p-0', children: _jsx(Link, { href: '/', onClick: () => setIsMobileMenuOpen(false), children: _jsx(LogoSmall, {}) }) }), onlyLogo ? null : (_jsxs(_Fragment, { children: [_jsx("nav", { className: 'hidden 800px:flex 800px:justify-between 800px:items-center 800px:w-fill max-w-200', children: children }), _jsxs("nav", { className: 'flex w-[calc(100vw-8rem)] justify-end h-12 800px:w-fit', children: [!disableThemeToggle &&
18
+ _jsx(ThemeToggle, {}), !disableLanguageToggle &&
19
+ _jsx(LanguageToggle, { language: lang }), !loginPath && !logoutPath &&
20
+ _jsx(AuthButton, { profilePath: profilePath, token: token, loginPath: loginPath, logoutPath: logoutPath })] }), _jsxs("button", { className: 'w-12 h-12 relative cursor-pointer bg-none border-none 800px:hidden', onClick: () => setIsMobileMenuOpen(!isMobileMenuOpen), children: [_jsx("div", { className: hamburgerStyle(isMobileMenuOpen) }), _jsx("div", { className: hamburgerStyle(isMobileMenuOpen, true) })] }), _jsx("nav", { className: `fixed top-16 w-[calc(100%-2rem)] max-w-140 mx-auto left-0 right-0 800px:hidden
18
21
  transition-all duration-500 ease-in-out overflow-hidden
19
22
  ${isMobileMenuOpen ? 'max-h-[calc(100vh-4rem)] opacity-100' : 'max-h-0 opacity-0'}`, onClick: () => setIsMobileMenuOpen(false), children: React.Children.map(children, (child, index) => (_jsx("div", { className: `transition-all duration-500 ease-out ${isMobileMenuOpen
20
23
  ? 'opacity-100 transform translate-y-0'
@@ -22,10 +25,11 @@ export default function Navbar({ lang, onlyLogo, disableLanguageToggle, disableT
22
25
  transitionDelay: isMobileMenuOpen ? `${index * 80}ms` : '0ms'
23
26
  }, children: child }, index))) })] }))] }) }));
24
27
  }
25
- function AuthButton({ profileURL, token }) {
26
- return (_jsx("div", { className: 'rounded-[0.3rem] hover:bg-login-300/20 h-12 w-12', children: token ? (_jsxs(_Fragment, { children: [_jsx(Link, { href: '/api/logout', prefetch: false, onClick: (e) => {
27
- e.preventDefault();
28
- window.location.href = '/api/logout';
29
- }, className: 'grid items-center justify-center h-full w-full', children: _jsx(LogOut, { size: 24 }) }), profileURL &&
30
- _jsx(Link, { href: profileURL, className: 'grid items-center justify-center h-full w-full', children: _jsx(User, { size: 24 }) })] })) : (_jsx(Link, { href: '/api/login', className: 'grid items-center justify-center h-full w-full', children: _jsx(User, { size: 24 }) })) }));
28
+ function AuthButton({ profilePath, logoutPath, loginPath, token }) {
29
+ return (_jsx("div", { className: 'rounded-[0.3rem] hover:bg-login-300/20 h-12 w-12', children: token ? (_jsxs(_Fragment, { children: [logoutPath &&
30
+ _jsx(Link, { href: logoutPath, prefetch: false, onClick: (e) => {
31
+ e.preventDefault();
32
+ window.location.href = logoutPath;
33
+ }, className: 'grid items-center justify-center h-full w-full', children: _jsx(LogOut, { size: 24 }) }), profilePath &&
34
+ _jsx(Link, { href: profilePath, className: 'grid items-center justify-center h-full w-full', children: _jsx(User, { size: 24 }) })] })) : (_jsx(Link, { href: loginPath, className: 'grid items-center justify-center h-full w-full', children: _jsx(User, { size: 24 }) })) }));
31
35
  }
@@ -10,8 +10,11 @@
10
10
  --color-red-200: oklch(88.5% 0.062 18.334);
11
11
  --color-red-400: oklch(70.4% 0.191 22.216);
12
12
  --color-red-500: oklch(63.7% 0.237 25.331);
13
+ --color-red-700: oklch(50.5% 0.213 27.518);
13
14
  --color-red-900: oklch(39.6% 0.141 25.723);
15
+ --color-yellow-400: oklch(85.2% 0.199 91.936);
14
16
  --color-yellow-500: oklch(79.5% 0.184 86.047);
17
+ --color-yellow-600: oklch(68.1% 0.162 75.834);
15
18
  --color-green-500: oklch(72.3% 0.219 149.579);
16
19
  --color-blue-500: oklch(62.3% 0.214 259.815);
17
20
  --color-blue-600: oklch(54.6% 0.245 262.881);
@@ -46,6 +49,8 @@
46
49
  --font-weight-bold: 700;
47
50
  --font-weight-extrabold: 800;
48
51
  --tracking-tight: -0.025em;
52
+ --leading-snug: 1.375;
53
+ --leading-relaxed: 1.625;
49
54
  --radius-xs: 0.125rem;
50
55
  --radius-sm: 0.25rem;
51
56
  --radius-md: 0.375rem;
@@ -53,6 +58,7 @@
53
58
  --radius-xl: 0.75rem;
54
59
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
55
60
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
61
+ --blur-sm: 8px;
56
62
  --blur-xl: 24px;
57
63
  --default-transition-duration: 150ms;
58
64
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -377,6 +383,9 @@
377
383
  .m-auto {
378
384
  margin: auto;
379
385
  }
386
+ .mx-4 {
387
+ margin-inline: calc(var(--spacing) * 4);
388
+ }
380
389
  .mx-auto {
381
390
  margin-inline: auto;
382
391
  }
@@ -1442,6 +1451,12 @@
1442
1451
  .border-login-500 {
1443
1452
  border-color: var(--color-login-500);
1444
1453
  }
1454
+ .border-login-500\/50 {
1455
+ border-color: color-mix(in srgb, #323232 50%, transparent);
1456
+ @supports (color: color-mix(in lab, red, red)) {
1457
+ border-color: color-mix(in oklab, var(--color-login-500) 50%, transparent);
1458
+ }
1459
+ }
1445
1460
  .border-red-500 {
1446
1461
  border-color: var(--color-red-500);
1447
1462
  }
@@ -1454,6 +1469,12 @@
1454
1469
  .bg-\[\#18181899\] {
1455
1470
  background-color: #18181899;
1456
1471
  }
1472
+ .bg-black\/60 {
1473
+ background-color: color-mix(in srgb, #000 60%, transparent);
1474
+ @supports (color: color-mix(in lab, red, red)) {
1475
+ background-color: color-mix(in oklab, var(--color-black) 60%, transparent);
1476
+ }
1477
+ }
1457
1478
  .bg-blue-600 {
1458
1479
  background-color: var(--color-blue-600);
1459
1480
  }
@@ -1478,6 +1499,12 @@
1478
1499
  background-color: color-mix(in oklab, var(--color-login-500) 50%, transparent);
1479
1500
  }
1480
1501
  }
1502
+ .bg-login-500\/60 {
1503
+ background-color: color-mix(in srgb, #323232 60%, transparent);
1504
+ @supports (color: color-mix(in lab, red, red)) {
1505
+ background-color: color-mix(in oklab, var(--color-login-500) 60%, transparent);
1506
+ }
1507
+ }
1481
1508
  .bg-login-500\/70 {
1482
1509
  background-color: color-mix(in srgb, #323232 70%, transparent);
1483
1510
  @supports (color: color-mix(in lab, red, red)) {
@@ -1514,6 +1541,12 @@
1514
1541
  background-color: color-mix(in oklab, var(--color-login) 70%, transparent);
1515
1542
  }
1516
1543
  }
1544
+ .bg-red-700\/80 {
1545
+ background-color: color-mix(in srgb, oklch(50.5% 0.213 27.518) 80%, transparent);
1546
+ @supports (color: color-mix(in lab, red, red)) {
1547
+ background-color: color-mix(in oklab, var(--color-red-700) 80%, transparent);
1548
+ }
1549
+ }
1517
1550
  .bg-red-900 {
1518
1551
  background-color: var(--color-red-900);
1519
1552
  }
@@ -1523,6 +1556,12 @@
1523
1556
  .bg-white {
1524
1557
  background-color: var(--color-white);
1525
1558
  }
1559
+ .bg-yellow-600\/80 {
1560
+ background-color: color-mix(in srgb, oklch(68.1% 0.162 75.834) 80%, transparent);
1561
+ @supports (color: color-mix(in lab, red, red)) {
1562
+ background-color: color-mix(in oklab, var(--color-yellow-600) 80%, transparent);
1563
+ }
1564
+ }
1526
1565
  .bg-linear-to-r {
1527
1566
  --tw-gradient-position: to right;
1528
1567
  @supports (background-image: linear-gradient(in lab, red, red)) {
@@ -1576,6 +1615,12 @@
1576
1615
  .stroke-login-50 {
1577
1616
  stroke: var(--color-login-50);
1578
1617
  }
1618
+ .stroke-red-400 {
1619
+ stroke: var(--color-red-400);
1620
+ }
1621
+ .stroke-yellow-400 {
1622
+ stroke: var(--color-yellow-400);
1623
+ }
1579
1624
  .stroke-\[3\.5px\] {
1580
1625
  stroke-width: 3.5px;
1581
1626
  }
@@ -1597,6 +1642,9 @@
1597
1642
  .p-4 {
1598
1643
  padding: calc(var(--spacing) * 4);
1599
1644
  }
1645
+ .p-6 {
1646
+ padding: calc(var(--spacing) * 6);
1647
+ }
1600
1648
  .p-8 {
1601
1649
  padding: calc(var(--spacing) * 8);
1602
1650
  }
@@ -1718,6 +1766,14 @@
1718
1766
  --tw-leading: calc(var(--spacing) * 8);
1719
1767
  line-height: calc(var(--spacing) * 8);
1720
1768
  }
1769
+ .leading-relaxed {
1770
+ --tw-leading: var(--leading-relaxed);
1771
+ line-height: var(--leading-relaxed);
1772
+ }
1773
+ .leading-snug {
1774
+ --tw-leading: var(--leading-snug);
1775
+ line-height: var(--leading-snug);
1776
+ }
1721
1777
  .font-bold {
1722
1778
  --tw-font-weight: var(--font-weight-bold);
1723
1779
  font-weight: var(--font-weight-bold);
@@ -1757,6 +1813,12 @@
1757
1813
  .text-login\! {
1758
1814
  color: var(--color-login) !important;
1759
1815
  }
1816
+ .text-login-50 {
1817
+ color: var(--color-login-50);
1818
+ }
1819
+ .text-login-100 {
1820
+ color: var(--color-login-100);
1821
+ }
1760
1822
  .text-login-200 {
1761
1823
  color: var(--color-login-200);
1762
1824
  }
@@ -1807,6 +1869,10 @@
1807
1869
  .opacity-100 {
1808
1870
  opacity: 100%;
1809
1871
  }
1872
+ .shadow-2xl {
1873
+ --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));
1874
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
1875
+ }
1810
1876
  .shadow-\[0_0\.1rem_0\.5rem_rgba\(3\,3\,3\,0\.5\)\] {
1811
1877
  --tw-shadow: 0 0.1rem 0.5rem var(--tw-shadow-color, rgba(3,3,3,0.5));
1812
1878
  box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
@@ -1846,6 +1912,23 @@
1846
1912
  .outline-login-500 {
1847
1913
  outline-color: var(--color-login-500);
1848
1914
  }
1915
+ .outline-login-500\/60 {
1916
+ outline-color: color-mix(in srgb, #323232 60%, transparent);
1917
+ @supports (color: color-mix(in lab, red, red)) {
1918
+ outline-color: color-mix(in oklab, var(--color-login-500) 60%, transparent);
1919
+ }
1920
+ }
1921
+ .outline-red-700 {
1922
+ outline-color: var(--color-red-700);
1923
+ }
1924
+ .outline-yellow-600 {
1925
+ outline-color: var(--color-yellow-600);
1926
+ }
1927
+ .backdrop-blur-sm {
1928
+ --tw-backdrop-blur: blur(var(--blur-sm));
1929
+ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
1930
+ backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
1931
+ }
1849
1932
  .backdrop-blur-xl {
1850
1933
  --tw-backdrop-blur: blur(var(--blur-xl));
1851
1934
  -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
@@ -2215,6 +2298,20 @@
2215
2298
  }
2216
2299
  }
2217
2300
  }
2301
+ .hover\:bg-red-700 {
2302
+ &:hover {
2303
+ @media (hover: hover) {
2304
+ background-color: var(--color-red-700);
2305
+ }
2306
+ }
2307
+ }
2308
+ .hover\:bg-yellow-600 {
2309
+ &:hover {
2310
+ @media (hover: hover) {
2311
+ background-color: var(--color-yellow-600);
2312
+ }
2313
+ }
2314
+ }
2218
2315
  .hover\:text-login-200 {
2219
2316
  &:hover {
2220
2317
  @media (hover: hover) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uibee",
3
- "version": "2.8.7",
3
+ "version": "2.9.1",
4
4
  "description": "Shared components, functions and hooks for reuse across Login projects",
5
5
  "homepage": "https://github.com/Login-Linjeforening-for-IT/uibee#readme",
6
6
  "bugs": {
@@ -0,0 +1,103 @@
1
+ 'use client'
2
+
3
+ import { TriangleAlert } from 'lucide-react'
4
+
5
+ type ConfirmPopupProps = {
6
+ isOpen: boolean
7
+ header: string
8
+ description?: string
9
+ confirmText?: string
10
+ cancelText?: string
11
+ onConfirm: () => void
12
+ onCancel: () => void
13
+ variant?: 'danger' | 'warning' | 'default'
14
+ }
15
+
16
+ export default function ConfirmPopup({
17
+ isOpen,
18
+ header,
19
+ description,
20
+ confirmText = 'Confirm',
21
+ cancelText = 'Cancel',
22
+ onConfirm,
23
+ onCancel,
24
+ variant = 'default',
25
+ }: ConfirmPopupProps) {
26
+ if (!isOpen) return null
27
+
28
+ const confirmBg =
29
+ variant === 'danger'
30
+ ? 'bg-red-700/80 outline-red-700 hover:bg-red-700'
31
+ : variant === 'warning'
32
+ ? 'bg-yellow-600/80 outline-yellow-600 hover:bg-yellow-600'
33
+ : 'bg-login/70 outline-login hover:bg-login/90'
34
+
35
+ return (
36
+ <div
37
+ role='dialog'
38
+ aria-modal='true'
39
+ aria-labelledby='confirm-popup-header'
40
+ className='fixed inset-0 z-50 flex items-center justify-center'
41
+ onClick={onCancel}
42
+ >
43
+ <div className='absolute inset-0 bg-black/60 backdrop-blur-sm' />
44
+
45
+ <div
46
+ className='
47
+ relative z-10 w-full max-w-md mx-4
48
+ bg-login-800 border border-login-500/50 rounded-xl
49
+ shadow-2xl p-6 flex flex-col gap-4
50
+ '
51
+ onClick={(e) => e.stopPropagation()}
52
+ >
53
+ <div className='flex items-center gap-3'>
54
+ {variant !== 'default' && (
55
+ <TriangleAlert
56
+ className={`w-6 h-6 shrink-0 ${variant === 'danger' ? 'stroke-red-400' : 'stroke-yellow-400'}`}
57
+ />
58
+ )}
59
+ <h2
60
+ id='confirm-popup-header'
61
+ className='text-login-50 text-lg font-bold leading-snug'
62
+ >
63
+ {header}
64
+ </h2>
65
+ </div>
66
+
67
+ {description && (
68
+ <p className='text-login-100 text-sm leading-relaxed'>
69
+ {description}
70
+ </p>
71
+ )}
72
+
73
+ <div className='flex justify-end gap-3 mt-1'>
74
+ <button
75
+ type='button'
76
+ onClick={onCancel}
77
+ className='
78
+ cursor-pointer px-4 py-1.5 rounded-md text-sm font-medium
79
+ bg-login-500/60 text-login-50 outline outline-login-500/60
80
+ hover:bg-login-500/90 focus:outline-none select-none
81
+ transition-colors duration-150
82
+ '
83
+ >
84
+ {cancelText}
85
+ </button>
86
+
87
+ <button
88
+ type='button'
89
+ onClick={onConfirm}
90
+ className={`
91
+ cursor-pointer px-4 py-1.5 rounded-md text-sm font-bold
92
+ text-white outline focus:outline-none select-none
93
+ transition-colors duration-150
94
+ ${confirmBg}
95
+ `}
96
+ >
97
+ {confirmText}
98
+ </button>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ )
103
+ }
@@ -36,4 +36,7 @@ export { default as Toaster, toast } from './toast/toaster'
36
36
  export { default as Button } from './buttons/button'
37
37
 
38
38
  // Alert
39
- export { default as Alert } from './alert/alert'
39
+ export { default as Alert } from './alert/alert'
40
+
41
+ // Confirm
42
+ export { default as ConfirmPopup } from './confirm/confirmPopup'
@@ -24,8 +24,9 @@ export type NavbarProps = {
24
24
  theme?: string
25
25
  disableThemeToggle?: boolean
26
26
  token?: string | null
27
- disableAuthButton?: boolean
28
- profileURL?: string
27
+ profilePath?: string
28
+ loginPath: string
29
+ logoutPath: string
29
30
  className?: string
30
31
  innerClassName?: string
31
32
  children: React.ReactNode
@@ -37,8 +38,9 @@ export default function Navbar({
37
38
  disableLanguageToggle,
38
39
  disableThemeToggle,
39
40
  token,
40
- disableAuthButton,
41
- profileURL,
41
+ profilePath,
42
+ loginPath,
43
+ logoutPath,
42
44
  className,
43
45
  innerClassName,
44
46
  children,
@@ -69,9 +71,22 @@ export default function Navbar({
69
71
 
70
72
  {/* Controls */}
71
73
  <nav className='flex w-[calc(100vw-8rem)] justify-end h-12 800px:w-fit'>
72
- {!disableThemeToggle && <ThemeToggle />}
73
- {!disableLanguageToggle && <LanguageToggle language={lang} />}
74
- {!disableAuthButton && <AuthButton profileURL={profileURL} token={token} />}
74
+ {!disableThemeToggle &&
75
+ <ThemeToggle />
76
+ }
77
+ {!disableLanguageToggle &&
78
+ <LanguageToggle
79
+ language={lang}
80
+ />
81
+ }
82
+ {!loginPath && !logoutPath &&
83
+ <AuthButton
84
+ profilePath={profilePath}
85
+ token={token}
86
+ loginPath={loginPath}
87
+ logoutPath={logoutPath}
88
+ />
89
+ }
75
90
  </nav>
76
91
 
77
92
  {/* Mobile Menu Button */}
@@ -111,26 +126,35 @@ export default function Navbar({
111
126
  )
112
127
  }
113
128
 
114
- function AuthButton({ profileURL, token }: { profileURL?: string, token?: string | null }) {
129
+ type AuthButtonProps = {
130
+ profilePath?: string
131
+ logoutPath: string
132
+ loginPath: string
133
+ token?: string | null
134
+ }
135
+
136
+ function AuthButton({ profilePath, logoutPath, loginPath, token }: AuthButtonProps) {
115
137
 
116
138
  return (
117
139
  <div className='rounded-[0.3rem] hover:bg-login-300/20 h-12 w-12'>
118
140
  {token ? (
119
141
  <>
120
- <Link
121
- href='/api/logout'
122
- prefetch={false}
123
- onClick={(e) => {
124
- e.preventDefault()
125
- window.location.href = '/api/logout'
126
- }}
127
- className='grid items-center justify-center h-full w-full'
128
- >
129
- <LogOut size={24} />
130
- </Link>
131
- {profileURL &&
142
+ {logoutPath &&
143
+ <Link
144
+ href={logoutPath}
145
+ prefetch={false}
146
+ onClick={(e) => {
147
+ e.preventDefault()
148
+ window.location.href = logoutPath
149
+ }}
150
+ className='grid items-center justify-center h-full w-full'
151
+ >
152
+ <LogOut size={24} />
153
+ </Link>
154
+ }
155
+ {profilePath &&
132
156
  <Link
133
- href={profileURL}
157
+ href={profilePath}
134
158
  className='grid items-center justify-center h-full w-full'
135
159
  >
136
160
  <User size={24} />
@@ -139,7 +163,7 @@ function AuthButton({ profileURL, token }: { profileURL?: string, token?: string
139
163
  </>
140
164
  ) : (
141
165
  <Link
142
- href='/api/login'
166
+ href={loginPath}
143
167
  className='grid items-center justify-center h-full w-full'
144
168
  >
145
169
  <User size={24} />
@@ -45,4 +45,16 @@ declare module 'uibee/components' {
45
45
  }
46
46
  export default function LanguageToggle(props: { lang: Language }): JSX.Element;
47
47
  export default function ThemeSwitch(props: { className?: string }): JSX.Element;
48
+
49
+ export interface ConfirmPopupProps {
50
+ isOpen: boolean
51
+ header: string
52
+ description?: string
53
+ confirmText?: string
54
+ cancelText?: string
55
+ onConfirm: () => void
56
+ onCancel: () => void
57
+ variant?: 'danger' | 'warning' | 'default'
58
+ }
59
+ export function ConfirmPopup(props: ConfirmPopupProps): JSX.Element | null;
48
60
  }