+
+
+ )}
+ {empty.length > 0 && (
+
+ )}
);
}
diff --git a/web/src/components/navigation-bar.tsx b/web/src/components/navigation-bar.tsx
index c9657dbf4..3967919d6 100644
--- a/web/src/components/navigation-bar.tsx
+++ b/web/src/components/navigation-bar.tsx
@@ -59,8 +59,9 @@ const navigation = [
},
];
+// The current page gets the tint of the brand, not a solid block.
const activeItem =
- "relative h-9 rounded-xl font-medium data-active:bg-sidebar-primary data-active:text-sidebar-primary-foreground data-active:hover:bg-sidebar-primary data-active:hover:text-sidebar-primary-foreground";
+ "relative h-10 rounded-xl font-medium data-active:bg-accent data-active:font-semibold data-active:text-accent-foreground data-active:hover:bg-accent data-active:hover:text-accent-foreground";
function CollapseButton() {
const { open, isMobile, toggleSidebar } = useSidebar();
@@ -71,13 +72,13 @@ function CollapseButton() {
{open ? : }
- Close
+ Collapse menu
@@ -107,40 +108,47 @@ export function AppSidebar() {
ref={navRef}
className="no-scrollbar scroll-fade gap-0 pb-6 group-data-[collapsible=icon]:overflow-x-hidden group-data-[collapsible=icon]:overflow-y-auto"
>
- {navigation.map((group) => (
-
- {/* In the icon rail, the hidden heading is pulled over the row
- above it: it must not take its clicks. */}
-
- {group.group}
-
-
-
- {group.items.map((item) => (
-
- isMobile && setOpenMobile(false)}
- render={}
- >
-
-
- {item.name}
-
-
-
- ))}
-
-
-
- ))}
+
+
+
+
+
{config?.version && (
{config.version}
@@ -152,25 +160,28 @@ export function AppSidebar() {
);
}
-/** The bar above the pages. */
+/**
+ * The bar above the pages on a small screen, where the menu is closed by
+ * default. On a larger screen, all it would hold is in the menu.
+ */
export function TopBar() {
const { setOpenMobile, openMobile } = useSidebar();
return (
-
-
+
+
-
-
-
+
+
+
);
diff --git a/web/src/components/ui/sidebar.tsx b/web/src/components/ui/sidebar.tsx
index e79e97f6e..75dbe9f5e 100644
--- a/web/src/components/ui/sidebar.tsx
+++ b/web/src/components/ui/sidebar.tsx
@@ -304,9 +304,10 @@ function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
)
}
-function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
+// A plain block: the page provides the main landmark.
+function SidebarInset({ className, ...props }: React.ComponentProps<"div">) {
return (
-
{user && }
{name.slice(0, 1).toUpperCase()}
+
+
+ {name}
+
+ {user?.name && user?.email && (
+
+ {user.email}
+
+ )}
+
-
+
diff --git a/web/src/components/visualize/dimensions-input.tsx b/web/src/components/visualize/dimensions-input.tsx
index cccf10c31..7388391e7 100644
--- a/web/src/components/visualize/dimensions-input.tsx
+++ b/web/src/components/visualize/dimensions-input.tsx
@@ -60,7 +60,7 @@ function Chip({
event.stopPropagation()}
onClick={(event) => {
event.stopPropagation();
diff --git a/web/src/components/visualize/field.tsx b/web/src/components/visualize/field.tsx
index d653a84a0..7c8463e76 100644
--- a/web/src/components/visualize/field.tsx
+++ b/web/src/components/visualize/field.tsx
@@ -26,18 +26,25 @@ export function Field({
label,
error,
htmlFor,
+ labelId,
className,
children,
}: {
label: string;
error?: string;
htmlFor?: string;
+ /** For a field which is not an input: it names itself with this label. */
+ labelId?: string;
className?: string;
children: ReactNode;
}) {
return (