uibee 3.2.0 → 3.3.0

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.
@@ -824,17 +824,21 @@ type SidebarItem = {
824
824
  };
825
825
  type SidebarProps = {
826
826
  items: SidebarItem[];
827
- header?: ReactNode;
827
+ header?: ReactNode | ((expanded: boolean) => ReactNode);
828
828
  bottomAction?: (expanded: boolean) => ReactNode;
829
829
  mobile?: boolean;
830
830
  initialExpanded?: boolean;
831
+ onExpandedChange?: (expanded: boolean) => void;
832
+ className?: string;
831
833
  };
832
834
  declare function Sidebar({
833
835
  items,
834
836
  header,
835
837
  bottomAction,
836
838
  mobile,
837
- initialExpanded
839
+ initialExpanded,
840
+ onExpandedChange,
841
+ className
838
842
  }: SidebarProps): import("react").JSX.Element;
839
843
  //#endregion
840
844
  //#region src/components/badge/badge.d.ts
@@ -2054,11 +2054,18 @@ function Footer({ logo, sponsor, columns, socialLinks, copyright, version, lang
2054
2054
  children: [/* @__PURE__ */ jsx("h4", {
2055
2055
  className: "pb-2 text-sm font-medium tracking-widest text-login-100",
2056
2056
  children: t(col.heading, lang)
2057
- }), col.items.map((item, j) => item.href ? /* @__PURE__ */ jsx("a", {
2058
- className: "link--underscore-hover block",
2057
+ }), col.items.map((item, j) => item.href ? item.href.startsWith("/") ? /* @__PURE__ */ jsx(Link, {
2058
+ className: "link--underscore-hover block text-login-100",
2059
2059
  href: item.href,
2060
2060
  children: t(item.label, lang)
2061
- }, j) : /* @__PURE__ */ jsx("p", { children: t(item.label, lang) }, j))]
2061
+ }, j) : /* @__PURE__ */ jsx("a", {
2062
+ className: "link--underscore-hover block text-login-100",
2063
+ href: item.href,
2064
+ children: t(item.label, lang)
2065
+ }, j) : /* @__PURE__ */ jsx("p", {
2066
+ className: "text-login-100",
2067
+ children: t(item.label, lang)
2068
+ }, j))]
2062
2069
  }, i))
2063
2070
  }),
2064
2071
  socialLinks && socialLinks.length > 0 && /* @__PURE__ */ jsx("div", {
@@ -2081,7 +2088,8 @@ function Footer({ logo, sponsor, columns, socialLinks, copyright, version, lang
2081
2088
  children: [/* @__PURE__ */ jsxs("p", {
2082
2089
  className: "text-xs wrap-break-word text-login-100",
2083
2090
  children: [
2084
- "Copyright © ",
2091
+ lang === "no" ? "Opphavsrett" : "Copyright",
2092
+ " © ",
2085
2093
  year,
2086
2094
  " ",
2087
2095
  t(copyright, lang)
@@ -3948,11 +3956,21 @@ function Modal({ isOpen, onClose, title, children, footer, size = "md" }) {
3948
3956
  const ITEM_HEIGHT = 48;
3949
3957
  const GAP = 4;
3950
3958
  const SUB_STRIDE = 40;
3951
- function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded = true }) {
3959
+ function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded = true, onExpandedChange, className = "" }) {
3952
3960
  const [expanded, setExpanded] = useState(initialExpanded);
3953
3961
  const pathname = usePathname();
3962
+ const searchParams = useSearchParams();
3963
+ const fullPath = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : "");
3964
+ function toggleExpanded() {
3965
+ const next = !expanded;
3966
+ setExpanded(next);
3967
+ onExpandedChange?.(next);
3968
+ }
3969
+ function isSubActive(sub) {
3970
+ return sub.path.includes("?") ? fullPath.startsWith(sub.path) : pathname === sub.path;
3971
+ }
3954
3972
  function isItemActive(item) {
3955
- return pathname === item.path || !!item.items?.some((sub) => pathname === sub.path || pathname.startsWith(sub.path + "/"));
3973
+ return pathname === item.path || !!item.items?.some((sub) => sub.path.includes("?") ? fullPath.startsWith(sub.path) : pathname === sub.path || pathname.startsWith(sub.path + "/"));
3956
3974
  }
3957
3975
  const activeIndex = items.findIndex(isItemActive);
3958
3976
  const activeOffset = items.slice(0, Math.max(activeIndex, 0)).reduce((acc, item) => acc + ITEM_HEIGHT + (item.items ? GAP : 0) + GAP, 0);
@@ -3961,6 +3979,7 @@ function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded
3961
3979
  flex flex-col border-r border-login-100/10 bg-login-900
3962
3980
  transition-all duration-300 ease-in-out
3963
3981
  ${mobile ? "w-full" : `h-full ${expanded ? "w-64" : "w-20"}`}
3982
+ ${className}
3964
3983
  `,
3965
3984
  children: [
3966
3985
  !mobile && /* @__PURE__ */ jsxs("div", {
@@ -3970,9 +3989,9 @@ function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded
3970
3989
  absolute top-4 flex items-center transition-all duration-300
3971
3990
  ${expanded ? "left-4 gap-3" : "left-1/2 -translate-x-1/2 gap-0"}
3972
3991
  `,
3973
- children: header
3992
+ children: typeof header === "function" ? header(expanded) : header
3974
3993
  }), /* @__PURE__ */ jsx("button", {
3975
- onClick: () => setExpanded(!expanded),
3994
+ onClick: toggleExpanded,
3976
3995
  className: `
3977
3996
  absolute cursor-pointer rounded-lg p-1.5
3978
3997
  text-login-200 transition-all duration-300 hover:bg-login-800
@@ -3983,7 +4002,7 @@ function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded
3983
4002
  }),
3984
4003
  mobile && /* @__PURE__ */ jsx("div", { className: "h-4" }),
3985
4004
  /* @__PURE__ */ jsxs("div", {
3986
- className: "relative flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-3",
4005
+ className: "relative flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-3 [scrollbar-width:none]",
3987
4006
  children: [activeIndex >= 0 && /* @__PURE__ */ jsx("span", {
3988
4007
  "aria-hidden": true,
3989
4008
  className: "absolute left-3 right-3 top-0 h-12 rounded-lg bg-login-800 transition-transform duration-300 ease-in-out",
@@ -3991,7 +4010,7 @@ function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded
3991
4010
  }), items.map((item, index) => {
3992
4011
  const isActive = isItemActive(item);
3993
4012
  const Icon = item.icon;
3994
- const activeSubIndex = item.items ? item.items.findIndex((sub) => pathname === sub.path || pathname.startsWith(sub.path + "/")) : -1;
4013
+ const activeSubIndex = item.items ? item.items.findIndex(isSubActive) : -1;
3995
4014
  return /* @__PURE__ */ jsxs("div", {
3996
4015
  className: "flex flex-col gap-1",
3997
4016
  children: [/* @__PURE__ */ jsxs(Link, {
@@ -4038,13 +4057,13 @@ function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded
4038
4057
  className: "\n absolute left-2 right-0 top-0 h-9 rounded-lg\n bg-login-800/50 transition-transform duration-300 ease-in-out\n ",
4039
4058
  style: { transform: `translateY(${activeSubIndex * SUB_STRIDE}px)` }
4040
4059
  }), item.items.map((sub, subIndex) => {
4041
- const isSubActive = pathname === sub.path || pathname.startsWith(sub.path + "/");
4060
+ const subActive = isSubActive(sub);
4042
4061
  return /* @__PURE__ */ jsx(Link, {
4043
4062
  href: sub.path,
4044
4063
  className: `
4045
4064
  relative z-10 rounded-lg p-2 text-sm
4046
4065
  transition-all duration-200
4047
- ${isSubActive ? "text-login" : "text-login-300 hover:bg-login-800/30 hover:text-login-100"}
4066
+ ${subActive ? "text-login" : "text-login-300 hover:bg-login-800/30 hover:text-login-100"}
4048
4067
  `,
4049
4068
  children: sub.name
4050
4069
  }, `${index}-${subIndex}`);
package/dist/style.css CHANGED
@@ -1978,6 +1978,9 @@
1978
1978
  .resize-y {
1979
1979
  resize: vertical;
1980
1980
  }
1981
+ .\[scrollbar-width\:none\] {
1982
+ scrollbar-width: none;
1983
+ }
1981
1984
  .list-none {
1982
1985
  list-style-type: none;
1983
1986
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uibee",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
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": {
@@ -1,4 +1,5 @@
1
1
  import type { ReactNode } from 'react'
2
+ import Link from 'next/link'
2
3
  import VersionTag from '@components/version/version'
3
4
 
4
5
  export type Lang = 'no' | 'en'
@@ -56,7 +57,9 @@ export default function Footer({
56
57
  <div>
57
58
  <div className='block w-full'>{sponsor.node}</div>
58
59
  {sponsor.label && (
59
- <p className='pt-8 text-center text-login-100'>{t(sponsor.label, lang)}</p>
60
+ <p className='pt-8 text-center text-login-100'>
61
+ {t(sponsor.label, lang)}
62
+ </p>
60
63
  )}
61
64
  </div>
62
65
  )}
@@ -76,11 +79,27 @@ export default function Footer({
76
79
  </h4>
77
80
  {col.items.map((item, j) =>
78
81
  item.href ? (
79
- <a key={j} className='link--underscore-hover block' href={item.href}>
80
- {t(item.label, lang)}
81
- </a>
82
+ item.href.startsWith('/') ? (
83
+ <Link
84
+ key={j}
85
+ className='link--underscore-hover block text-login-100'
86
+ href={item.href}
87
+ >
88
+ {t(item.label, lang)}
89
+ </Link>
90
+ ) : (
91
+ <a
92
+ key={j}
93
+ className='link--underscore-hover block text-login-100'
94
+ href={item.href}
95
+ >
96
+ {t(item.label, lang)}
97
+ </a>
98
+ )
82
99
  ) : (
83
- <p key={j}>{t(item.label, lang)}</p>
100
+ <p key={j} className='text-login-100'>
101
+ {t(item.label, lang)}
102
+ </p>
84
103
  )
85
104
  )}
86
105
  </div>
@@ -112,7 +131,7 @@ export default function Footer({
112
131
  md:grid-cols-[auto_min-content] md:items-end md:gap-8'
113
132
  >
114
133
  <p className='text-xs wrap-break-word text-login-100'>
115
- Copyright © {year} {t(copyright, lang)}
134
+ {lang === 'no' ? 'Opphavsrett' : 'Copyright'} © {year} {t(copyright, lang)}
116
135
  </p>
117
136
  {version && (
118
137
  <VersionTag version={version.tag} url={version.href} />
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
 
3
3
  import { useState, type ElementType, type ReactNode } from 'react'
4
- import { usePathname } from 'next/navigation'
4
+ import { usePathname, useSearchParams } from 'next/navigation'
5
5
  import Link from 'next/link'
6
6
  import { ChevronLeft, ChevronRight } from 'lucide-react'
7
7
 
@@ -20,23 +20,49 @@ export type SidebarItem = {
20
20
 
21
21
  type SidebarProps = {
22
22
  items: SidebarItem[]
23
- header?: ReactNode
23
+ header?: ReactNode | ((expanded: boolean) => ReactNode)
24
24
  bottomAction?: (expanded: boolean) => ReactNode
25
25
  mobile?: boolean
26
26
  initialExpanded?: boolean
27
+ onExpandedChange?: (expanded: boolean) => void
28
+ className?: string
27
29
  }
28
30
 
29
31
  const ITEM_HEIGHT = 48
30
32
  const GAP = 4
31
33
  const SUB_STRIDE = 40
32
34
 
33
- export default function Sidebar({ items, header, bottomAction, mobile = false, initialExpanded = true }: SidebarProps) {
35
+ export default function Sidebar({
36
+ items,
37
+ header,
38
+ bottomAction,
39
+ mobile = false,
40
+ initialExpanded = true,
41
+ onExpandedChange,
42
+ className = '',
43
+ }: SidebarProps) {
34
44
  const [expanded, setExpanded] = useState(initialExpanded)
35
45
  const pathname = usePathname()
46
+ const searchParams = useSearchParams()
47
+ const fullPath = pathname + (searchParams.toString() ? `?${searchParams.toString()}` : '')
48
+
49
+ function toggleExpanded() {
50
+ const next = !expanded
51
+ setExpanded(next)
52
+ onExpandedChange?.(next)
53
+ }
54
+
55
+ function isSubActive(sub: SidebarSubItem) {
56
+ return sub.path.includes('?')
57
+ ? fullPath.startsWith(sub.path)
58
+ : pathname === sub.path
59
+ }
36
60
 
37
61
  function isItemActive(item: SidebarItem) {
38
62
  return pathname === item.path ||
39
- !!(item.items?.some(sub => pathname === sub.path || pathname.startsWith(sub.path + '/')))
63
+ !!(item.items?.some(sub => sub.path.includes('?')
64
+ ? fullPath.startsWith(sub.path)
65
+ : pathname === sub.path || pathname.startsWith(sub.path + '/')))
40
66
  }
41
67
 
42
68
  const activeIndex = items.findIndex(isItemActive)
@@ -49,6 +75,7 @@ export default function Sidebar({ items, header, bottomAction, mobile = false, i
49
75
  flex flex-col border-r border-login-100/10 bg-login-900
50
76
  transition-all duration-300 ease-in-out
51
77
  ${mobile ? 'w-full' : `h-full ${expanded ? 'w-64' : 'w-20'}`}
78
+ ${className}
52
79
  `}>
53
80
  {!mobile && (
54
81
  <div className={`relative mb-2 p-4 transition-all duration-300 ${expanded ? 'h-16' : 'h-20'}`}>
@@ -57,11 +84,11 @@ export default function Sidebar({ items, header, bottomAction, mobile = false, i
57
84
  absolute top-4 flex items-center transition-all duration-300
58
85
  ${expanded ? 'left-4 gap-3' : 'left-1/2 -translate-x-1/2 gap-0'}
59
86
  `}>
60
- {header}
87
+ {typeof header === 'function' ? header(expanded) : header}
61
88
  </div>
62
89
  )}
63
90
  <button
64
- onClick={() => setExpanded(!expanded)}
91
+ onClick={toggleExpanded}
65
92
  className={`
66
93
  absolute cursor-pointer rounded-lg p-1.5
67
94
  text-login-200 transition-all duration-300 hover:bg-login-800
@@ -75,7 +102,7 @@ export default function Sidebar({ items, header, bottomAction, mobile = false, i
75
102
 
76
103
  {mobile && <div className='h-4' />}
77
104
 
78
- <div className='relative flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-3'>
105
+ <div className='relative flex flex-1 flex-col gap-1 overflow-x-hidden overflow-y-auto px-3 [scrollbar-width:none]'>
79
106
  {activeIndex >= 0 && (
80
107
  <span
81
108
  aria-hidden
@@ -87,7 +114,7 @@ export default function Sidebar({ items, header, bottomAction, mobile = false, i
87
114
  const isActive = isItemActive(item)
88
115
  const Icon = item.icon
89
116
  const activeSubIndex = item.items
90
- ? item.items.findIndex(sub => pathname === sub.path || pathname.startsWith(sub.path + '/'))
117
+ ? item.items.findIndex(isSubActive)
91
118
  : -1
92
119
 
93
120
  return (
@@ -142,7 +169,7 @@ export default function Sidebar({ items, header, bottomAction, mobile = false, i
142
169
  />
143
170
  )}
144
171
  {item.items.map((sub, subIndex) => {
145
- const isSubActive = pathname === sub.path || pathname.startsWith(sub.path + '/')
172
+ const subActive = isSubActive(sub)
146
173
  return (
147
174
  <Link
148
175
  key={`${index}-${subIndex}`}
@@ -150,7 +177,7 @@ export default function Sidebar({ items, header, bottomAction, mobile = false, i
150
177
  className={`
151
178
  relative z-10 rounded-lg p-2 text-sm
152
179
  transition-all duration-200
153
- ${isSubActive
180
+ ${subActive
154
181
  ? 'text-login'
155
182
  : 'text-login-300 hover:bg-login-800/30 hover:text-login-100'
156
183
  }
package/src/globals.css CHANGED
@@ -35,7 +35,7 @@
35
35
  --color-login-100: #b0b0b0;
36
36
  --color-login-75: #e4e4e4;
37
37
  --color-login-50: #ededed;
38
-
38
+
39
39
  --color-login-text: #ededed;
40
40
  }
41
41