@djangocfg/layouts 2.1.254 → 2.1.255

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/layouts",
3
- "version": "2.1.254",
3
+ "version": "2.1.255",
4
4
  "description": "Simple, straightforward layout components for Next.js - import and use with props",
5
5
  "keywords": [
6
6
  "layouts",
@@ -74,14 +74,14 @@
74
74
  "check": "tsc --noEmit"
75
75
  },
76
76
  "peerDependencies": {
77
- "@djangocfg/api": "^2.1.254",
78
- "@djangocfg/centrifugo": "^2.1.254",
79
- "@djangocfg/i18n": "^2.1.254",
80
- "@djangocfg/monitor": "^2.1.254",
81
- "@djangocfg/debuger": "^2.1.254",
82
- "@djangocfg/ui-core": "^2.1.254",
83
- "@djangocfg/ui-nextjs": "^2.1.254",
84
- "@djangocfg/ui-tools": "^2.1.254",
77
+ "@djangocfg/api": "^2.1.255",
78
+ "@djangocfg/centrifugo": "^2.1.255",
79
+ "@djangocfg/i18n": "^2.1.255",
80
+ "@djangocfg/monitor": "^2.1.255",
81
+ "@djangocfg/debuger": "^2.1.255",
82
+ "@djangocfg/ui-core": "^2.1.255",
83
+ "@djangocfg/ui-nextjs": "^2.1.255",
84
+ "@djangocfg/ui-tools": "^2.1.255",
85
85
  "@hookform/resolvers": "^5.2.2",
86
86
  "consola": "^3.4.2",
87
87
  "lucide-react": "^0.545.0",
@@ -109,15 +109,15 @@
109
109
  "uuid": "^11.1.0"
110
110
  },
111
111
  "devDependencies": {
112
- "@djangocfg/api": "^2.1.254",
113
- "@djangocfg/i18n": "^2.1.254",
114
- "@djangocfg/centrifugo": "^2.1.254",
115
- "@djangocfg/monitor": "^2.1.254",
116
- "@djangocfg/debuger": "^2.1.254",
117
- "@djangocfg/typescript-config": "^2.1.254",
118
- "@djangocfg/ui-core": "^2.1.254",
119
- "@djangocfg/ui-nextjs": "^2.1.254",
120
- "@djangocfg/ui-tools": "^2.1.254",
112
+ "@djangocfg/api": "^2.1.255",
113
+ "@djangocfg/i18n": "^2.1.255",
114
+ "@djangocfg/centrifugo": "^2.1.255",
115
+ "@djangocfg/monitor": "^2.1.255",
116
+ "@djangocfg/debuger": "^2.1.255",
117
+ "@djangocfg/typescript-config": "^2.1.255",
118
+ "@djangocfg/ui-core": "^2.1.255",
119
+ "@djangocfg/ui-nextjs": "^2.1.255",
120
+ "@djangocfg/ui-tools": "^2.1.255",
121
121
  "@types/node": "^24.7.2",
122
122
  "@types/react": "^19.1.0",
123
123
  "@types/react-dom": "^19.1.0",
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Private sidebar: header (brand only when expanded; icon mode shows expand trigger only),
3
- * nav groups, account footer. Nav: muted inactive rows, pill active; density scales with item count.
3
+ * nav groups, account footer. Item-count density when **expanded**; collapsed rail always uses `default` metrics so icons match.
4
4
  */
5
5
 
6
6
  'use client';
@@ -32,11 +32,15 @@ import { LucideIcon } from '../../../components';
32
32
  import type { I18nLayoutConfig } from '../../AppLayout/AppLayout';
33
33
  import type { HeaderConfig, SidebarItem, SidebarConfig } from '../PrivateLayout';
34
34
 
35
+ /** Few items → roomier rows; many items → tighter. Same breakpoints for demo, CarAPIS, etc. */
36
+ const DENSITY_COMFORTABLE_MAX = 6;
37
+ const DENSITY_DEFAULT_MAX = 14;
38
+
35
39
  type NavDensity = 'comfortable' | 'default' | 'compact';
36
40
 
37
41
  function navDensityFromCount(n: number): NavDensity {
38
- if (n <= 6) return 'comfortable';
39
- if (n <= 14) return 'default';
42
+ if (n <= DENSITY_COMFORTABLE_MAX) return 'comfortable';
43
+ if (n <= DENSITY_DEFAULT_MAX) return 'default';
40
44
  return 'compact';
41
45
  }
42
46
 
@@ -57,15 +61,13 @@ const DENSITY = {
57
61
  comfortable: {
58
62
  menu: 'gap-1.5',
59
63
  group: 'gap-2',
60
- /** Tighter than default SidebarGroup `p-2` (doubles Y between groups). */
61
64
  groupPad: 'px-2 py-1',
62
65
  label:
63
66
  'h-7 uppercase text-[10px] font-light leading-none tracking-[0.14em] text-sidebar-foreground/40',
64
67
  buttonSize: 'lg' as const,
65
68
  iconClass: 'h-5 w-5',
66
69
  extraButton: 'rounded-lg !px-3',
67
- /** Extra left inset so brand aligns with nav icons (group p-2 + button px). */
68
- headerRowInset: 'pl-3',
70
+ headerRowInset: 'pl-2',
69
71
  },
70
72
  default: {
71
73
  menu: 'gap-1',
@@ -76,7 +78,7 @@ const DENSITY = {
76
78
  buttonSize: 'default' as const,
77
79
  iconClass: 'h-4 w-4',
78
80
  extraButton: 'rounded-lg',
79
- headerRowInset: 'pl-2',
81
+ headerRowInset: 'pl-1.5',
80
82
  },
81
83
  compact: {
82
84
  menu: 'gap-0.5',
@@ -87,10 +89,13 @@ const DENSITY = {
87
89
  buttonSize: 'sm' as const,
88
90
  iconClass: 'h-3.5 w-3.5',
89
91
  extraButton: 'rounded-md !px-2',
90
- headerRowInset: 'pl-2',
92
+ headerRowInset: 'pl-1.5',
91
93
  },
92
94
  } as const;
93
95
 
96
+ /** Icon rail: always the same geometry — ignore comfortable/compact (larger/smaller rows only when expanded). */
97
+ const RAIL_NAV = DENSITY.default;
98
+
94
99
  interface PrivateSidebarProps {
95
100
  sidebar: SidebarConfig;
96
101
  header?: HeaderConfig;
@@ -116,7 +121,9 @@ export function PrivateSidebar({ sidebar, header, i18n, pathname: pathnameProp }
116
121
  );
117
122
 
118
123
  const density = React.useMemo(() => navDensityFromCount(allItems.length), [allItems.length]);
119
- const d = DENSITY[density];
124
+ const tierNav = DENSITY[density];
125
+ /** Expanded: follow item-count tier; collapsed rail: fixed `default` sizing so icons stay uniform. */
126
+ const menuNav = state === 'collapsed' ? RAIL_NAV : tierNav;
120
127
 
121
128
  const isActive = React.useCallback(
122
129
  (href: string) => {
@@ -134,7 +141,7 @@ export function PrivateSidebar({ sidebar, header, i18n, pathname: pathnameProp }
134
141
 
135
142
  const expanded = state === 'expanded';
136
143
 
137
- const headerRowClass = cn('flex items-center gap-2', d.headerRowInset);
144
+ const headerRowClass = cn('flex items-center gap-2', tierNav.headerRowInset);
138
145
  const brandMark = header?.brandIcon ? (
139
146
  <LucideIcon icon={header.brandIcon} className="h-4 w-4 text-sidebar-primary-foreground" />
140
147
  ) : (
@@ -152,12 +159,12 @@ export function PrivateSidebar({ sidebar, header, i18n, pathname: pathnameProp }
152
159
  <div className="w-full min-w-0 shrink-0 px-2">{sidebar.menuEnd}</div>
153
160
  ) : null;
154
161
 
155
- const sidebarContentClass = cn('gap-2', d.group);
162
+ const sidebarContentClass = cn('gap-2', menuNav.group);
156
163
 
157
164
  const renderedGroups = React.useMemo(() => {
158
- const navButtonClass = cn(navItemClass, d.extraButton);
159
- const groupLabelClass = cn('px-2', d.label);
160
- const sidebarGroupClass = cn('gap-0', d.groupPad);
165
+ const navButtonClass = cn(navItemClass, menuNav.extraButton);
166
+ const groupLabelClass = cn('px-2', menuNav.label);
167
+ const sidebarGroupClass = cn('gap-0', menuNav.groupPad);
161
168
 
162
169
  return sidebar.groups.map((group) => {
163
170
  if (group.dynamic && group.items.length === 0) return null;
@@ -169,12 +176,12 @@ export function PrivateSidebar({ sidebar, header, i18n, pathname: pathnameProp }
169
176
  <SidebarMenuButton
170
177
  asChild
171
178
  isActive={isActive(item.href)}
172
- size={d.buttonSize}
179
+ size={menuNav.buttonSize}
173
180
  tooltip={tooltipText}
174
181
  className={navButtonClass}
175
182
  >
176
183
  <Link href={item.href}>
177
- {item.icon ? <LucideIcon icon={iconProp} className={d.iconClass} /> : null}
184
+ {item.icon ? <LucideIcon icon={iconProp} className={menuNav.iconClass} /> : null}
178
185
  <span>{item.label}</span>
179
186
  {item.badge ? <SidebarMenuBadge>{item.badge}</SidebarMenuBadge> : null}
180
187
  </Link>
@@ -187,12 +194,12 @@ export function PrivateSidebar({ sidebar, header, i18n, pathname: pathnameProp }
187
194
  <SidebarGroup key={group.label} className={sidebarGroupClass}>
188
195
  <SidebarGroupLabel className={groupLabelClass}>{group.label}</SidebarGroupLabel>
189
196
  <SidebarGroupContent>
190
- <SidebarMenu className={d.menu}>{items}</SidebarMenu>
197
+ <SidebarMenu className={menuNav.menu}>{items}</SidebarMenu>
191
198
  </SidebarGroupContent>
192
199
  </SidebarGroup>
193
200
  );
194
201
  });
195
- }, [sidebar.groups, isActive, d]);
202
+ }, [sidebar.groups, isActive, menuNav]);
196
203
 
197
204
  const expandedHeader = (
198
205
  <div className={headerRowClass}>
@@ -218,7 +225,7 @@ export function PrivateSidebar({ sidebar, header, i18n, pathname: pathnameProp }
218
225
 
219
226
  return (
220
227
  <Sidebar collapsible="icon">
221
- <SidebarHeader className="px-2 pt-2.5 pb-2">{sidebarHeaderContent}</SidebarHeader>
228
+ <SidebarHeader className="px-2 pt-3.5 pb-2">{sidebarHeaderContent}</SidebarHeader>
222
229
 
223
230
  <SidebarContent className={sidebarContentClass}>
224
231
  {menuStartSlot}