@goplusvn/core 0.1.12 → 0.1.13
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/CHANGELOG.md +61 -0
- package/package.json +1 -1
- package/src/providers/index.tsx +19 -0
- package/src/styles/base.css +41 -0
- package/src/ui/layout/customizer.tsx +12 -42
- package/src/ui/layout/sidebar.tsx +7 -5
- package/src/ui/primitives/sidebar.tsx +25 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.13 — Customizer: make radius, density & inset/floating actually apply
|
|
4
|
+
|
|
5
|
+
The Customizer exposed controls that stored a value but changed nothing on
|
|
6
|
+
screen. Wired them up at the source so every app using core gets them working:
|
|
7
|
+
|
|
8
|
+
- **Radius ("Bo góc") now applies.** `SettingsProvider` drives the real
|
|
9
|
+
`--radius` token from `settings.radius`; Tailwind's `@theme inline` derives
|
|
10
|
+
`rounded-sm/md/lg/xl` from it, so the whole UI re-rounds live (0 → square,
|
|
11
|
+
1rem → fully rounded). Previously nothing read `settings.radius`.
|
|
12
|
+
- **Density ("Mật độ") now applies.** `SettingsProvider` sets
|
|
13
|
+
`data-density="compact"` on `<html>`; `base.css` tightens the global
|
|
14
|
+
`--spacing` scale (0.25rem → 0.215rem) so every spacing utility packs in
|
|
15
|
+
compact mode. Previously `useDensity()` was read nowhere.
|
|
16
|
+
- **Inset / floating sidebar no longer renders a harsh frame.** Core's default
|
|
17
|
+
sidebar is deep navy, and shadcn's inset/floating paints the page frame with
|
|
18
|
+
that sidebar colour — reading as a broken-looking block. The frame is now the
|
|
19
|
+
soft `--muted` neutral, so the content floats as a card on a calm page
|
|
20
|
+
(adapts to dark mode; the rounded-xl + shadow core already applies stay).
|
|
21
|
+
- **Inset / floating collapsed rail no longer looks squeezed.** In icon mode the
|
|
22
|
+
floating/inset content box is `--sidebar-width-icon + 8px` (56px) but had
|
|
23
|
+
`px-2.5` padding, leaving the pill only 36px — narrower than the default 48px
|
|
24
|
+
rail. Reduced to `px-1` so the pill is a comfortable 48px with a 4px floating
|
|
25
|
+
gutter.
|
|
26
|
+
- **Inset / floating sidebar corners are softened.** The floating panel was
|
|
27
|
+
`rounded-lg` and the inset panel had NO radius (a sharp navy block whose
|
|
28
|
+
top-right corner met the header as a hard 90°). Both now use `rounded-xl`
|
|
29
|
+
(matching the inset content card) so the sidebar reads as a soft floating
|
|
30
|
+
panel — the header/sidebar junction is a gentle curve, not a rough corner.
|
|
31
|
+
The floating content area also rounds both left corners
|
|
32
|
+
(`rounded-l-xl`, clipping the sticky header + footer via overflow-hidden) so
|
|
33
|
+
its whole left edge hugs the floating sidebar with soft curves; the right
|
|
34
|
+
edge stays flush to the viewport (inset already rounds via its `rounded-xl`
|
|
35
|
+
card). Finally, the header's own BOTTOM-left corner is rounded in both
|
|
36
|
+
variants (base.css: `[data-variant=floating|inset] ~ main > header`), so its
|
|
37
|
+
divider curves into the left edge instead of ending in a hard inner corner.
|
|
38
|
+
And the content no longer touches the sidebar: inset drops its `ml-0` (so the
|
|
39
|
+
uniform `m-2` leaves a left gap) and floating gains `ml-2`, giving a small
|
|
40
|
+
gap between the sidebar and the content/header.
|
|
41
|
+
- **"Ẩn ngoài" (`collapsible="offcanvas"`) can finally hide the sidebar.**
|
|
42
|
+
`AppSidebar` force-remapped `offcanvas → icon`, so the option collapsed to an
|
|
43
|
+
icon rail instead of hiding — identical to "Biểu tượng" and impossible to fully
|
|
44
|
+
hide the sidebar. The choice is now honoured as-is: offcanvas slides the
|
|
45
|
+
sidebar off-screen (reopen via the header toggle), icon → rail.
|
|
46
|
+
- **Dropped the "none" (Tắt) collapsible option from the Customizer.** Locking
|
|
47
|
+
the sidebar expanded made the header collapse-toggle a no-op — a
|
|
48
|
+
conflicting/dead control. The picker now offers only offcanvas + icon, both of
|
|
49
|
+
which the toggle actually drives. (`none` remains a valid type for any code
|
|
50
|
+
that sets it directly; it's just no longer offered in the UI.)
|
|
51
|
+
- **Dropped the "Bố cục" (layout: horizontal/vertical) control from the
|
|
52
|
+
Customizer.** The horizontal layout swaps the whole nav for a top menubar,
|
|
53
|
+
which turns every sidebar option ("Kiểu thanh bên", "Thu gọn thanh bên") into
|
|
54
|
+
a no-op — the same dead-control problem. The customizer now locks to the
|
|
55
|
+
vertical sidebar the apps are designed around (`defaultSettings.layout` stays
|
|
56
|
+
`vertical`; `HorizontalLayout` is untouched for code that sets it directly).
|
|
57
|
+
- **Non-collapsing sidebar (`collapsible="none"`) is now readable.** It rendered
|
|
58
|
+
`bg-sidebar text-sidebar-foreground` (the deep navy), but the group labels +
|
|
59
|
+
active item are `text-primary`, giving ~1.9:1 contrast (unreadable) on that
|
|
60
|
+
navy. A non-collapsing sidebar is permanently *expanded*, so it now uses the
|
|
61
|
+
expanded surface (`bg-background` / `text-foreground`), matching the rest of
|
|
62
|
+
the design (labels-on-light) — contrast jumps to ~9:1.
|
|
63
|
+
|
|
3
64
|
## 0.1.11 — print: force light colours on the print surface
|
|
4
65
|
|
|
5
66
|
- **Fix faded print output in dark mode.** Print pages render under the app's
|
package/package.json
CHANGED
package/src/providers/index.tsx
CHANGED
|
@@ -76,6 +76,25 @@ export function SettingsProvider({
|
|
|
76
76
|
setSettings(defaultSettings);
|
|
77
77
|
}, [deleteStoredSettings]);
|
|
78
78
|
|
|
79
|
+
// Apply the appearance choices the Customizer exposes but that nothing else
|
|
80
|
+
// wires up. Without this, the "Radius" and "Density" controls store a value
|
|
81
|
+
// yet change nothing on screen (dead controls in every app using core).
|
|
82
|
+
// - radius → drive the real `--radius` token. Tailwind's @theme inline
|
|
83
|
+
// derives rounded-sm/md/lg/xl from it (see styles/base.css), so the whole
|
|
84
|
+
// UI re-rounds live. The Customizer stores rem (0, 0.3, 0.5, 0.75, 1).
|
|
85
|
+
// - density → expose as a `data-density` attribute; base.css tightens the
|
|
86
|
+
// global `--spacing` scale in compact mode ([data-density="compact"]).
|
|
87
|
+
// Client-only (useEffect) so there's no SSR/hydration mismatch.
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
const root = document.documentElement;
|
|
90
|
+
root.style.setProperty("--radius", `${settings.radius ?? 0.5}rem`);
|
|
91
|
+
if (settings.density === "compact") {
|
|
92
|
+
root.setAttribute("data-density", "compact");
|
|
93
|
+
} else {
|
|
94
|
+
root.removeAttribute("data-density");
|
|
95
|
+
}
|
|
96
|
+
}, [settings.radius, settings.density]);
|
|
97
|
+
|
|
79
98
|
return (
|
|
80
99
|
<SettingsContext.Provider
|
|
81
100
|
value={{ settings, updateSettings, resetSettings }}
|
package/src/styles/base.css
CHANGED
|
@@ -582,4 +582,45 @@ aside.EmojiPickerReact {
|
|
|
582
582
|
.dark .custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
|
583
583
|
background: #64748b;
|
|
584
584
|
/* slate-500 */
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/* ============================================================================
|
|
588
|
+
* Customizer: Density ("Comfortable" vs "Compact")
|
|
589
|
+
* SettingsProvider sets data-density="compact" on <html> from settings.density.
|
|
590
|
+
* Tailwind v4 derives EVERY spacing utility (p-/px-/gap-/space-/h-/w-/size-…)
|
|
591
|
+
* from the single `--spacing` token (default 0.25rem). Tightening it here packs
|
|
592
|
+
* the whole UI from one lever — tables, forms, cards, the sidebar — instead of
|
|
593
|
+
* per-component edits. 0.215rem ≈ 14% tighter: denser, still comfortably hit.
|
|
594
|
+
* ========================================================================== */
|
|
595
|
+
[data-density="compact"] {
|
|
596
|
+
--spacing: 0.215rem;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/* ============================================================================
|
|
600
|
+
* Customizer: Sidebar variant "inset" / "floating" — frame colour.
|
|
601
|
+
* Core's default sidebar is a deep navy (--sidebar-background), and the shadcn
|
|
602
|
+
* inset/floating treatment paints the page frame with that same sidebar colour
|
|
603
|
+
* (has-[[data-variant=inset]]:bg-sidebar). On the navy default that reads as a
|
|
604
|
+
* harsh, broken-looking block. Repaint the frame with the soft neutral so the
|
|
605
|
+
* content reads as a CARD FLOATING ON A CALM PAGE (the rounded-xl + shadow core
|
|
606
|
+
* already applies do the floating). Token-based → adapts to dark mode.
|
|
607
|
+
* Un-layered → wins over the Tailwind `bg-sidebar` utility (in @layer utilities)
|
|
608
|
+
* regardless of specificity.
|
|
609
|
+
* ========================================================================== */
|
|
610
|
+
.group\/sidebar-wrapper:has([data-variant="inset"]),
|
|
611
|
+
.group\/sidebar-wrapper:has([data-variant="floating"]) {
|
|
612
|
+
background-color: hsl(var(--muted));
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/* ============================================================================
|
|
616
|
+
* Customizer: floating / inset — round the header's BOTTOM-left corner.
|
|
617
|
+
* The content panel already rounds its left corners (rounded-l-xl clips the
|
|
618
|
+
* sticky header's top-left) and the sidebar rounds its corners, but the
|
|
619
|
+
* header's divider still met the left edge as a hard inner corner. The layout
|
|
620
|
+
* header is the first child of the SidebarInset <main>, a sibling after the
|
|
621
|
+
* sidebar peer (which carries data-variant). 0.75rem = rounded-xl, matching.
|
|
622
|
+
* ========================================================================== */
|
|
623
|
+
[data-variant="floating"] ~ main > header,
|
|
624
|
+
[data-variant="inset"] ~ main > header {
|
|
625
|
+
border-bottom-left-radius: 0.75rem;
|
|
585
626
|
}
|
|
@@ -5,8 +5,6 @@ import { useParams, usePathname, useRouter } from "next/navigation";
|
|
|
5
5
|
import {
|
|
6
6
|
AlignLeft,
|
|
7
7
|
AlignRight,
|
|
8
|
-
AlignStartHorizontal,
|
|
9
|
-
AlignStartVertical,
|
|
10
8
|
MoonStar,
|
|
11
9
|
RotateCcw,
|
|
12
10
|
Sun,
|
|
@@ -48,11 +46,10 @@ interface CustomizerProps {
|
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
const sidebarVariants: SidebarVariantType[] = ["sidebar", "floating", "inset"];
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
];
|
|
49
|
+
// "none" (lock the sidebar expanded) is intentionally NOT offered: it makes the
|
|
50
|
+
// header collapse-toggle a no-op, which reads as a broken/conflicting control.
|
|
51
|
+
// Both remaining options work with that toggle — offcanvas hides, icon → rail.
|
|
52
|
+
const sidebarCollapsibleOptions: SidebarCollapsibleType[] = ["offcanvas", "icon"];
|
|
56
53
|
const densityOptions: DensityType[] = ["comfortable", "compact"];
|
|
57
54
|
|
|
58
55
|
// Localized labels — the customizer follows the active URL locale (params.lang)
|
|
@@ -246,41 +243,14 @@ export function Customizer({ trigger, triggerClassName }: CustomizerProps) {
|
|
|
246
243
|
<SunMoon className="shrink-0 h-4 w-4" />
|
|
247
244
|
</Button>
|
|
248
245
|
</div>
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
onClick={() =>
|
|
259
|
-
updateSettings({
|
|
260
|
-
...settings,
|
|
261
|
-
layout: "horizontal",
|
|
262
|
-
})
|
|
263
|
-
}
|
|
264
|
-
>
|
|
265
|
-
<AlignStartHorizontal className="shrink-0 h-4 w-4 me-2" />
|
|
266
|
-
{t("horizontal")}
|
|
267
|
-
</Button>
|
|
268
|
-
<Button
|
|
269
|
-
variant={
|
|
270
|
-
settings.layout === "vertical" ? "secondary" : "outline"
|
|
271
|
-
}
|
|
272
|
-
onClick={() =>
|
|
273
|
-
updateSettings({
|
|
274
|
-
...settings,
|
|
275
|
-
layout: "vertical",
|
|
276
|
-
})
|
|
277
|
-
}
|
|
278
|
-
>
|
|
279
|
-
<AlignStartVertical className="shrink-0 h-4 w-4 me-2" />
|
|
280
|
-
{t("vertical")}
|
|
281
|
-
</Button>
|
|
282
|
-
</div>
|
|
283
|
-
</div>
|
|
246
|
+
{/* "Bố cục" (layout: horizontal/vertical) removed from the
|
|
247
|
+
picker. The horizontal layout swaps the whole nav for a top
|
|
248
|
+
menubar, which makes every sidebar option below ("Kiểu thanh
|
|
249
|
+
bên", "Thu gọn thanh bên") a no-op — dead/conflicting
|
|
250
|
+
controls. The apps here are designed around the vertical
|
|
251
|
+
sidebar, so the customizer locks to it (defaultSettings.layout
|
|
252
|
+
stays "vertical"; the HorizontalLayout code is untouched for
|
|
253
|
+
anything that sets layout directly). */}
|
|
284
254
|
|
|
285
255
|
<div className="space-y-1.5">
|
|
286
256
|
<span className="text-sm">{t("sidebarVariant")}</span>
|
|
@@ -185,11 +185,13 @@ export function AppSidebar({
|
|
|
185
185
|
}
|
|
186
186
|
};
|
|
187
187
|
|
|
188
|
-
//
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
188
|
+
// Honour the Customizer's "Thu gọn thanh bên" choice as-is:
|
|
189
|
+
// offcanvas → collapses fully off-screen (hidden), reopened via header toggle
|
|
190
|
+
// icon → collapses to an icon rail
|
|
191
|
+
// none → never collapses (always expanded)
|
|
192
|
+
// Previously offcanvas was force-remapped to icon, so "Ẩn ngoài" could never
|
|
193
|
+
// actually hide the sidebar (it behaved identically to "Biểu tượng").
|
|
194
|
+
const collapsibleMode = settings.sidebarCollapsible || "icon";
|
|
193
195
|
|
|
194
196
|
return (
|
|
195
197
|
<SidebarWrapper
|
|
@@ -218,10 +218,16 @@ const Sidebar = React.forwardRef<
|
|
|
218
218
|
}, [hoverExpandEnabled, setHoverOpen]);
|
|
219
219
|
|
|
220
220
|
if (collapsible === "none") {
|
|
221
|
+
// A non-collapsing sidebar is permanently EXPANDED, so it must use the
|
|
222
|
+
// expanded surface (bg-background / text-foreground), NOT the deep
|
|
223
|
+
// `bg-sidebar` colour. On a coloured sidebar (e.g. the navy default) the
|
|
224
|
+
// old `bg-sidebar text-sidebar-foreground` left the group labels + active
|
|
225
|
+
// item — which are `text-primary` — at ~1.9:1 contrast (unreadable). This
|
|
226
|
+
// matches the expanded state of the collapsible sidebar (labels-on-light).
|
|
221
227
|
return (
|
|
222
228
|
<div
|
|
223
229
|
className={cn(
|
|
224
|
-
"flex h-full w-(--sidebar-width) flex-col bg-
|
|
230
|
+
"flex h-full w-(--sidebar-width) flex-col border-r bg-background text-foreground",
|
|
225
231
|
className,
|
|
226
232
|
)}
|
|
227
233
|
ref={ref}
|
|
@@ -294,7 +300,7 @@ const Sidebar = React.forwardRef<
|
|
|
294
300
|
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
295
301
|
// Adjustments for collapsible=icon
|
|
296
302
|
variant === "floating" || variant === "inset"
|
|
297
|
-
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_8px)] group-data-[collapsible=icon]:px-
|
|
303
|
+
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_8px)] group-data-[collapsible=icon]:px-1"
|
|
298
304
|
: "group-data-[collapsible=icon]:w-(--sidebar-width-icon) group-data-[collapsible=icon]:border-r group-data-[collapsible=icon]:px-0",
|
|
299
305
|
// Hover expand - override icon width to full width on hover
|
|
300
306
|
"group-data-[hover-expanded=true]:!w-(--sidebar-width) group-data-[hover-expanded=true]:shadow-xl group-data-[hover-expanded=true]:z-[100]",
|
|
@@ -310,7 +316,12 @@ const Sidebar = React.forwardRef<
|
|
|
310
316
|
"group-data-[state=collapsed]:bg-sidebar group-data-[state=collapsed]:border-border/50",
|
|
311
317
|
"group-data-[state=expanded]:bg-background group-data-[state=expanded]:border-border/50",
|
|
312
318
|
"group-data-[hover-expanded=true]:!bg-background group-data-[hover-expanded=true]:!border-border/50",
|
|
313
|
-
|
|
319
|
+
// Floating & inset: the sidebar is a soft floating panel. Round
|
|
320
|
+
// ALL corners (rounded-xl) so the top-right corner where it meets
|
|
321
|
+
// the header reads as a soft curve, not a hard 90° junction. Inset
|
|
322
|
+
// previously had no radius (sharp navy block) — now matches.
|
|
323
|
+
"group-data-[variant=floating]:rounded-xl group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow",
|
|
324
|
+
"group-data-[variant=inset]:rounded-xl group-data-[variant=inset]:border group-data-[variant=inset]:border-sidebar-border group-data-[variant=inset]:shadow",
|
|
314
325
|
)}
|
|
315
326
|
>
|
|
316
327
|
{children}
|
|
@@ -386,7 +397,17 @@ const SidebarInset = React.forwardRef<
|
|
|
386
397
|
ref={ref}
|
|
387
398
|
className={cn(
|
|
388
399
|
"relative flex min-h-svh flex-1 flex-col bg-muted/40 transition-[margin] duration-200 ease-linear",
|
|
389
|
-
|
|
400
|
+
// Inset: content is a card floating with a uniform m-2 gap on ALL sides
|
|
401
|
+
// (no ml-0 override) so there's a small gap between the sidebar and the
|
|
402
|
+
// content/header instead of them touching.
|
|
403
|
+
"peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
|
|
404
|
+
// Floating: the content is full-bleed (no card), and its LEFT edge is
|
|
405
|
+
// the side that meets the floating sidebar. Give it a small left gap
|
|
406
|
+
// (ml-2) so it doesn't touch the sidebar, and round both left corners
|
|
407
|
+
// (top-left clips the sticky header, bottom-left clips the footer via
|
|
408
|
+
// overflow-hidden) so the content hugs the floating sidebar with soft
|
|
409
|
+
// curves instead of hard 90° corners. Right edge stays flush.
|
|
410
|
+
"md:peer-data-[variant=floating]:ml-2 md:peer-data-[variant=floating]:rounded-l-xl",
|
|
390
411
|
className,
|
|
391
412
|
)}
|
|
392
413
|
{...props}
|