Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Admin UI - Sidebar #4536

Open
wants to merge 80 commits into
base: feat/new-admin-ui
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
5ae0ade
wip
adrians5j Feb 6, 2025
9f0910b
Merge remote-tracking branch 'refs/remotes/origin/feat/new-admin-ui' …
adrians5j Feb 10, 2025
e379a80
wip
adrians5j Feb 10, 2025
f0e4a58
wip
adrians5j Feb 10, 2025
8cff522
wip
adrians5j Feb 10, 2025
8dae741
wip
adrians5j Feb 11, 2025
ca7992d
wip
adrians5j Feb 11, 2025
890e321
wip
adrians5j Feb 14, 2025
6cd47ca
wip
adrians5j Feb 18, 2025
c622384
wip
adrians5j Feb 19, 2025
7ad8c8b
wip
adrians5j Feb 20, 2025
f586df0
wip
adrians5j Feb 20, 2025
ae71301
wip
adrians5j Feb 20, 2025
b4946d3
wip
adrians5j Feb 20, 2025
1012c76
wip
adrians5j Feb 24, 2025
1c6a8ae
wip
adrians5j Feb 24, 2025
511d587
wip
adrians5j Feb 25, 2025
b02112e
wip
adrians5j Feb 25, 2025
bb676c6
wip
adrians5j Feb 25, 2025
845a754
wip
adrians5j Feb 25, 2025
c2a6e5a
wip
adrians5j Feb 26, 2025
24f37ff
wip
adrians5j Feb 26, 2025
e386d4e
wip
adrians5j Feb 26, 2025
aacb514
wip
adrians5j Feb 26, 2025
70e7a73
wip
adrians5j Feb 26, 2025
44dd9e3
wip
adrians5j Feb 26, 2025
6121198
wip
adrians5j Feb 27, 2025
3ba36cb
wip
adrians5j Feb 27, 2025
db52f75
wip
adrians5j Feb 27, 2025
d80300a
wip
adrians5j Feb 27, 2025
0c1dbc2
wip
adrians5j Feb 27, 2025
2315d5f
wip
adrians5j Feb 27, 2025
674d0bb
wip
adrians5j Feb 28, 2025
bc465ca
wip
adrians5j Feb 28, 2025
7ed2218
wip
adrians5j Feb 28, 2025
99a2900
wip
adrians5j Feb 28, 2025
7ae076a
wip
adrians5j Mar 3, 2025
3fe320d
wip
adrians5j Mar 3, 2025
374a8eb
wip
adrians5j Mar 3, 2025
90132c5
wip
adrians5j Mar 3, 2025
b1c877f
wip
adrians5j Mar 3, 2025
c347b1a
update IconButton styles to include img support in class names
adrians5j Mar 3, 2025
83d928a
update IconButton styles to include img support in class names
adrians5j Mar 3, 2025
5830cc5
update IconButton styles to include img support in class names
adrians5j Mar 3, 2025
7f88a48
wip
adrians5j Mar 3, 2025
6b586f6
wip
adrians5j Mar 3, 2025
584b8fb
wip
adrians5j Mar 4, 2025
14bb6a5
wip
adrians5j Mar 4, 2025
62b7c8c
wip
adrians5j Mar 4, 2025
6995a64
wip
adrians5j Mar 4, 2025
618d4f3
wip
adrians5j Mar 4, 2025
c3be861
wip
adrians5j Mar 4, 2025
4d8ca13
wip
adrians5j Mar 4, 2025
9f94a7b
wip
adrians5j Mar 4, 2025
a13c6b4
wip
adrians5j Mar 4, 2025
d3a152e
wip
adrians5j Mar 4, 2025
4ac129a
wip
adrians5j Mar 4, 2025
afc25df
wip
adrians5j Mar 4, 2025
1a9a70a
wip
adrians5j Mar 4, 2025
5d5920c
wip
adrians5j Mar 4, 2025
7f64384
wip
adrians5j Mar 4, 2025
46433ba
wip
adrians5j Mar 4, 2025
87cddb9
wip
adrians5j Mar 4, 2025
b75ce6e
wip
adrians5j Mar 4, 2025
45201a0
wip
adrians5j Mar 4, 2025
3d53573
wip
adrians5j Mar 4, 2025
06d8040
wip
adrians5j Mar 4, 2025
49a62d7
wip
adrians5j Mar 5, 2025
00a1d14
wip
adrians5j Mar 5, 2025
d32b001
wip
adrians5j Mar 5, 2025
26a2f2a
wip
adrians5j Mar 5, 2025
ea1d5c1
wip: undo recent BC-related changes
adrians5j Mar 5, 2025
2d51810
Merge remote-tracking branch 'refs/remotes/origin/feat/new-admin-ui' …
adrians5j Mar 5, 2025
6990f76
wip: undo recent BC-related changes
adrians5j Mar 5, 2025
5c1f2b2
wip
adrians5j Mar 5, 2025
9c0a788
wip
adrians5j Mar 5, 2025
fd5b56e
wip
adrians5j Mar 5, 2025
56e37cd
wip
adrians5j Mar 5, 2025
ac5ed75
wip
adrians5j Mar 5, 2025
8ebdca3
wip
adrians5j Mar 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/admin-ui/.storybook/overrides.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* storybook-overrides.css */
/* Sidebar component is fixed-positioned, so we had to apply these
in order for it to look good in a Storybook environment. */
.sb-show-main.sb-main-centered #storybook-root.component-sidebar {
margin: 0;
padding: 0;
}
1 change: 1 addition & 0 deletions packages/admin-ui/.storybook/preview.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Preview } from "@storybook/react";

import "../src/theme.scss";
import "./overrides.css";

const preview: Preview = {
parameters: {
Expand Down
1 change: 1 addition & 0 deletions packages/admin-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@radix-ui/react-accordion": "^1.2.2",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-checkbox": "^1.1.2",
"@radix-ui/react-collapsible": "^1.1.3",
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.4",
"@radix-ui/react-label": "^2.1.0",
Expand Down
20 changes: 10 additions & 10 deletions packages/admin-ui/src/Button/IconButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { cn, cva, type VariantProps, makeDecoratable } from "~/utils";

const iconButtonVariants = cva(
[
"wby-border-transparent wby-rounded wby-flex wby-items-center wby-justify-center wby-ring-offset-background wby-cursor-pointer wby-transition-colors [&_svg]:wby-pointer-events-none [&_svg]:wby-shrink-0",
"wby-border-transparent wby-rounded wby-flex wby-flex-shrink-0 wby-items-center wby-justify-center wby-ring-offset-background wby-cursor-pointer wby-transition-colors [&_svg]:wby-pointer-events-none [&_svg]:wby-shrink-0 [&_img]:wby-pointer-events-none [&_img]:wby-shrink-0",
"aria-disabled:wby-pointer-events-none",
"focus-visible:wby-outline-none focus-visible:wby-border-accent-default"
],
Expand Down Expand Up @@ -47,12 +47,12 @@ const iconButtonVariants = cva(
]
},
size: {
xxs: "wby-border-sm wby-rounded-xs wby-size-sm-extra [&_svg]:wby-size-md",
xs: "wby-border-sm wby-rounded-xs wby-size-md [&_svg]:wby-size-md",
xxs: "wby-border-sm wby-rounded-xs wby-size-sm-extra [&_svg]:wby-size-md [&_img]:wby-size-md",
xs: "wby-border-sm wby-rounded-xs wby-size-md [&_svg]:wby-size-md [&_img]:wby-size-md",
sm: "wby-border-sm wby-rounded-sm",
md: "wby-border-sm wby-rounded-md",
lg: "wby-border-sm wby-rounded-md",
xl: "wby-border-md wby-rounded-lg wby-p-[calc(theme(padding.md)-theme(borderWidth.md))] [&_svg]:wby-size-lg"
xl: "wby-border-md wby-rounded-lg wby-p-[calc(theme(padding.md)-theme(borderWidth.md))] [&_svg]:wby-size-lg [&_img]:wby-size-lg"
},
iconSize: {
default: "",
Expand All @@ -69,37 +69,37 @@ const iconButtonVariants = cva(
size: "sm",
iconSize: "default",
className:
"wby-p-[calc(theme(padding.xs)-theme(borderWidth.sm))] [&_svg]:wby-size-md"
"wby-p-[calc(theme(padding.xs)-theme(borderWidth.sm))] [&_svg]:wby-size-md [&_img]:wby-size-md"
},
{
size: "sm",
iconSize: "lg",
className:
"wby-p-[calc(theme(padding.xxs)-theme(borderWidth.sm))] [&_svg]:wby-size-md-plus"
"wby-p-[calc(theme(padding.xxs)-theme(borderWidth.sm))] [&_svg]:wby-size-md-plus [&_img]:wby-size-md-plus"
},
{
size: "md",
iconSize: "default",
className:
"wby-p-[calc(theme(padding.sm)-theme(borderWidth.sm))] [&_svg]:wby-size-md"
"wby-p-[calc(theme(padding.sm)-theme(borderWidth.sm))] [&_svg]:wby-size-md [&_img]:wby-size-md"
},
{
size: "md",
iconSize: "lg",
className:
"wby-p-[calc(theme(padding.xs)-theme(borderWidth.sm))] [&_svg]:wby-size-lg"
"wby-p-[calc(theme(padding.xs)-theme(borderWidth.sm))] [&_svg]:wby-size-lg [&_img]:wby-size-lg"
},
{
size: "lg",
iconSize: "default",
className:
"wby-p-[calc(theme(padding.sm-plus)-theme(borderWidth.sm))] [&_svg]:wby-size-md-plus"
"wby-p-[calc(theme(padding.sm-plus)-theme(borderWidth.sm))] [&_svg]:wby-size-md-plus [&_img]:wby-size-md-plus"
},
{
size: "lg",
iconSize: "lg",
className:
"wby-p-[calc(theme(padding.sm)-theme(borderWidth.sm))] [&_svg]:wby-size-lg"
"wby-p-[calc(theme(padding.sm)-theme(borderWidth.sm))] [&_svg]:wby-size-lg [&_img]:wby-size-lg"
}
],
defaultVariants: {
Expand Down
2 changes: 1 addition & 1 deletion packages/admin-ui/src/Icon/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from "react";
import * as AccessibleIcon from "@radix-ui/react-accessible-icon";
import { cn, cva, makeDecoratable, type VariantProps } from "~/utils";

const iconVariants = cva("", {
const iconVariants = cva("wby-shrink-0", {
variants: {
size: {
xs: "wby-size-sm-extra",
Expand Down
193 changes: 193 additions & 0 deletions packages/admin-ui/src/Sidebar/Sidebar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import React, { useEffect } from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { BrowserRouter, Route, Routes, useLocation } from "@webiny/react-router";
import { ReactComponent as AuditLogsIcon } from "@material-design-icons/svg/outlined/assignment.svg";
import { ReactComponent as FormBuilderIcon } from "@material-design-icons/svg/outlined/check_box.svg";
import { ReactComponent as CmsIcon } from "@material-design-icons/svg/outlined/web.svg";
import { ReactComponent as PageBuilderIcon } from "@material-design-icons/svg/outlined/table_chart.svg";
import { ReactComponent as InfoIcon } from "@material-design-icons/svg/outlined/info.svg";
import { ReactComponent as ChatIcon } from "@material-design-icons/svg/outlined/chat.svg";
import { ReactComponent as GithubIcon } from "@material-design-icons/svg/outlined/gite.svg";
import { ReactComponent as DocsIcon } from "@material-design-icons/svg/outlined/summarize.svg";
import { ReactComponent as ApiPlaygroundIcon } from "@material-design-icons/svg/outlined/swap_horiz.svg";
import { ReactComponent as MoreVertIcon } from "@material-design-icons/svg/outlined/more_vert.svg";
import { ReactComponent as FileManagerIcon } from "@material-design-icons/svg/outlined/insert_drive_file.svg";

import wbyLogo from "./stories/wby-logo.png";
import { Sidebar } from "./Sidebar";
import { SidebarProvider } from "~/Sidebar/components/SidebarProvider";
import { DropdownMenu } from "~/DropdownMenu";
import { Tag } from "~/Tag";

const meta: Meta<typeof Sidebar> = {
title: "Components/Sidebar",
component: Sidebar,

// We removed this because in the "all stories" view, the menu gets visually
// broken because of the fixed positioning of the sidebar. This is not a problem
// when the story is viewed in isolation.
// tags: ["autodocs"],

argTypes: {}
};

export default meta;

type Story = StoryObj<typeof Sidebar>;

export const MainMenu: Story = {
render: () => (
<BrowserRouter>
<Routes>
<Route path={"*"} element={<SidebarComponent />} />
</Routes>
</BrowserRouter>
)
};

const SidebarComponent = () => {
const { hash } = useLocation();

// Sidebar is fixed-positioned, so we had to apply these in order
// for it to look good in a Storybook environment.
useEffect(() => {
const sbRoot = document.getElementById("storybook-root");
if (sbRoot) {
sbRoot.classList.add("component-sidebar");
}

return () => {
if (sbRoot) {
sbRoot.classList.remove("component-sidebar");
}
};
}, []);

return (
<SidebarProvider>
<Sidebar
title={"Webiny"}
icon={
<Sidebar.Icon element={<img src={wbyLogo} alt={"Webiny"} />} label={"Webiny"} />
}
footer={
<DropdownMenu
trigger={
<Sidebar.Item
icon={<Sidebar.Item.Icon label="Settings" element={<InfoIcon />} />}
text={"Support"}
action={<Sidebar.Item.Action element={<MoreVertIcon />} />}
/>
}
className={"wby-w-[225px]"}
>
<DropdownMenu.Item
content={"API Playground"}
icon={<ApiPlaygroundIcon />}
/>
<DropdownMenu.Item content={"Documentation"} icon={<DocsIcon />} />
<DropdownMenu.Item content={"GitHub"} icon={<GithubIcon />} />
<DropdownMenu.Item content={"Slack"} icon={<ChatIcon />} />
<DropdownMenu.Separator />
<DropdownMenu.Item
content={
<div className={"flex wby-items-center"}>
Webiny 5.43.0
<Tag
variant={"accent"}
content={"WCP "}
className={"wby-ml-sm-extra"}
/>
</div>
}
/>
</DropdownMenu>
}
>
<Sidebar.Link
text={"Audit Logs"}
to={"#audit-logs"}
active={hash === "#audit-logs"}
icon={<Sidebar.Item.Icon label="Audit Logs" element={<AuditLogsIcon />} />}
/>
<Sidebar.Link
text={"Form Builder"}
to={"#form-builder"}
active={hash === "#form-builder"}
icon={<Sidebar.Item.Icon label="Form Builder" element={<FormBuilderIcon />} />}
/>
<Sidebar.Item
text={"File Manager"}
onClick={() => {
alert("File Manager clicked");
}}
icon={<Sidebar.Item.Icon label="File Manager" element={<FileManagerIcon />} />}
/>
<Sidebar.Link
text={"Headless CMS"}
to={"#cms"}
active={hash === "#cms"}
icon={<Sidebar.Item.Icon label="Headless CMS" element={<CmsIcon />} />}
>
<Sidebar.Item text={"Content Models"} variant={"group-label"} />
<Sidebar.Link
text={"Groups"}
to={"#cms-groups"}
active={hash === "#cms-groups"}
/>
<Sidebar.Link
text={"Models"}
to={"#cms-models"}
active={hash === "#cms-models"}
/>
</Sidebar.Link>
<Sidebar.Link
text={"Page Builder"}
to={"#page-builder"}
active={hash === "#page-builder"}
icon={<Sidebar.Item.Icon label="Page Builder" element={<PageBuilderIcon />} />}
>
<Sidebar.Item text={"Blocks"} variant={"group-label"} />
<Sidebar.Link
text={"Blocks"}
to={"#pb-blocks"}
active={hash === "#pb-blocks"}
/>
<Sidebar.Link
text={"Categories"}
to={"#pb-blocks-categories"}
active={hash === "#pb-blocks-categories"}
/>

<Sidebar.Link
to={"#pb-pages"}
text={"Pages"}
variant={"group-label"}
active={hash === `#pb-pages`}
/>
<Sidebar.Link
to={"#pb-pages-categories"}
text={"Categories"}
active={hash === `#pb-pages-categories`}
/>
<Sidebar.Link
to={"#pb-pages-menus"}
text={"Menus"}
active={hash === `#pb-pages-menus`}
/>
<Sidebar.Link
to={"#pb-pages-pages"}
text={"Pages"}
active={hash === `#pb-pages-pages`}
/>
<Sidebar.Link
to={"#pb-pages-templates"}
text={"Templates"}
disabled={true}
active={hash === `#pb-pages-templates`}
/>
</Sidebar.Link>
</Sidebar>
</SidebarProvider>
);
};
74 changes: 74 additions & 0 deletions packages/admin-ui/src/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as React from "react";
import { makeDecoratable, withStaticProps } from "~/utils";
import { SidebarRoot } from "./components/SidebarRoot";
import { SidebarContent } from "./components/SidebarContent";
import { SidebarMenuItem } from "./components/SidebarMenuItem";
import { SidebarMenuLink } from "./components/SidebarMenuLink";
import { SidebarMenu } from "./components/SidebarMenu";
import { SidebarHeader } from "./components/SidebarHeader";
import { SidebarIcon } from "./components/SidebarIcon";
import { SidebarFooter } from "./components/SidebarFooter";

interface SidebarProps
extends Omit<React.ComponentPropsWithoutRef<typeof SidebarRoot>, "title">,
Omit<React.ComponentPropsWithoutRef<typeof SidebarContent>, "title"> {
title?: React.ReactNode;
icon?: React.ReactNode;
children: React.ReactNode;
footer?: React.ReactNode;
}

const SidebarBase = (props: SidebarProps) => {
const { headerProps, rootProps, footerProps, contentProps } = React.useMemo(() => {
const {
// Header props.
title,
icon,

// Root props.
side,

// Footer props.
footer,

// Content props.
...rest
} = props;

return {
headerProps: {
title,
icon
},
rootProps: {
side
},
footerProps: {
footer
},
contentProps: rest
};
}, [props]);

return (
<SidebarRoot {...rootProps}>
<SidebarHeader {...headerProps} />
<SidebarContent {...contentProps}>
<SidebarMenu>{props.children}</SidebarMenu>
</SidebarContent>
<SidebarFooter>
<SidebarMenu>{footerProps.footer}</SidebarMenu>
</SidebarFooter>
</SidebarRoot>
);
};

const DecoratableSidebar = makeDecoratable("Sidebar", SidebarBase);

const Sidebar = withStaticProps(DecoratableSidebar, {
Item: SidebarMenuItem,
Link: SidebarMenuLink,
Icon: SidebarIcon
});

export { Sidebar };
Loading