add GetStartedChecklist

This commit is contained in:
Sidney Alcantara
2022-07-07 19:16:59 +10:00
parent 711327e28d
commit 0ece76c3ef
15 changed files with 748 additions and 153 deletions

View File

@@ -94,6 +94,12 @@ export { Table };
import { Leaf } from "mdi-material-ui";
export { Leaf };
import { FormatListChecks } from "mdi-material-ui";
export { FormatListChecks as Checklist };
import { FileTableBoxOutline } from "mdi-material-ui";
export { FileTableBoxOutline as Project };
export * from "./AddRow";
export * from "./AddRowTop";
export * from "./ChevronDown";

View File

@@ -143,6 +143,9 @@ export const tableSettingsDialogSchemaAtom = atom(async (get) => {
return getTableSchema(tableId);
});
/** Open the Get Started checklist from anywhere */
export const getStartedChecklistAtom = atom(false);
/** Persist the state of the add row ID type */
export const tableAddRowIdTypeAtom = atomWithStorage<
"decrement" | "random" | "custom"

View File

@@ -0,0 +1,52 @@
import { Box, BoxProps, SvgIcon } from "@mui/material";
import { Discord as DiscordIcon } from "@src/assets/icons";
import GitHubIcon from "@mui/icons-material/GitHub";
import TwitterIcon from "@mui/icons-material/Twitter";
import { spreadSx } from "@src/utils/ui";
const SOCIAL_PLATFORMS = Object.freeze({
discord: { bg: "#5865F2", fg: "#fff", icon: <DiscordIcon /> },
gitHub: { bg: "#24292E", fg: "#fff", icon: <GitHubIcon /> },
twitter: { bg: "#1d9bf0", fg: "#fff", icon: <TwitterIcon /> },
productHunt: {
bg: "#fff",
fg: "#DA552F",
icon: (
<SvgIcon viewBox="0 0 240 240">
<path d="M240 120c0 66.274-53.726 120-120 120S0 186.274 0 120 53.726 0 120 0s120 53.726 120 120m-104 0h-34V84h34c9.941 0 18 8.059 18 18 0 9.94-8.059 18-18 18m0-60H78v120h24v-36h34c23.196 0 42-18.804 42-42s-18.804-42-42-42" />
</SvgIcon>
),
},
});
export interface ISocialLogoProps extends Partial<BoxProps> {
platform: keyof typeof SOCIAL_PLATFORMS;
}
export default function SocialLogo({ platform, ...props }: ISocialLogoProps) {
return (
<Box
{...props}
sx={[
{
borderRadius: 1.5,
p: 0.5,
bgcolor: SOCIAL_PLATFORMS[platform].bg,
color: SOCIAL_PLATFORMS[platform].fg,
boxShadow: (theme) => `0 0 0 1px ${
theme.palette.action.inputOutline
} inset,
0 ${theme.palette.mode === "dark" ? "" : "-"}1px 0 0 ${
theme.palette.action.inputOutline
} inset`,
"& svg": { display: "block" },
},
...spreadSx(props.sx),
]}
>
{SOCIAL_PLATFORMS[platform].icon}
</Box>
);
}

View File

@@ -94,18 +94,20 @@ export default function SteppedAccordion({
>
<StepLabel error={error} {...labelProps}>
{title}
<ExpandIcon sx={{ mr: -0.5 }} />
{content && <ExpandIcon sx={{ mr: -0.5 }} />}
</StepLabel>
</StepButton>
<StepContent
TransitionProps={
disableUnmount ? { unmountOnExit: false } : undefined
}
{...contentProps}
>
{content}
</StepContent>
{content && (
<StepContent
TransitionProps={
disableUnmount ? { unmountOnExit: false } : undefined
}
{...contentProps}
>
{content}
</StepContent>
)}
</Step>
)
)}

View File

@@ -10,6 +10,7 @@ export const EXTERNAL_LINKS = {
gitHub: meta.repository.url.replace(".git", ""),
discord: "https://discord.gg/B8yAD5PDX4",
twitter: "https://twitter.com/rowyio",
productHunt: "https://www.producthunt.com/products/rowy-2",
rowyRun: meta.repository.url.replace(".git", "Run"),
rowyRunGitHub: meta.repository.url.replace(".git", "Run"),

View File

@@ -0,0 +1,116 @@
import { useEffect } from "react";
import {
Menu,
MenuProps,
ListSubheader,
MenuItem,
ListItemIcon,
ListItemSecondaryAction,
} from "@mui/material";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import SocialLogo from "@src/components/SocialLogo";
import { EXTERNAL_LINKS } from "@src/constants/externalLinks";
import { logEvent, analytics } from "analytics";
export default function HelpMenu({
anchorEl,
onClose,
}: Pick<MenuProps, "anchorEl" | "onClose">) {
const open = Boolean(anchorEl);
useEffect(() => {
if (open) logEvent(analytics, "open_community_menu");
}, [open]);
const externalLinkIcon = (
<ListItemSecondaryAction sx={{ right: 10, color: "text.disabled" }}>
<InlineOpenInNewIcon />
</ListItemSecondaryAction>
);
return (
<Menu
anchorEl={anchorEl}
open={open}
onClose={onClose}
id="community-menu"
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
transformOrigin={{ vertical: "bottom", horizontal: "left" }}
sx={{ "& .MuiPaper-root": { mt: 0.5, py: 1 } }}
PaperProps={{ elevation: 10 }}
>
<ListSubheader
sx={{
pb: 0.5,
typography: "subtitle1",
}}
>
Join our community
</ListSubheader>
<ListSubheader
sx={{
pb: 1.5,
maxWidth: 260,
typography: "body2",
color: "text.secondary",
}}
>
Reach out for help, engage with our community, or shout us out!
</ListSubheader>
<MenuItem
component="a"
href={EXTERNAL_LINKS.discord}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon sx={{ mr: 1 }}>
<SocialLogo platform="discord" />
</ListItemIcon>
Discord
{externalLinkIcon}
</MenuItem>
<MenuItem
component="a"
href={EXTERNAL_LINKS.gitHub}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon sx={{ mr: 1 }}>
<SocialLogo platform="gitHub" />
</ListItemIcon>
GitHub
{externalLinkIcon}
</MenuItem>
<MenuItem
component="a"
href={EXTERNAL_LINKS.twitter}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon sx={{ mr: 1 }}>
<SocialLogo platform="twitter" />
</ListItemIcon>
Twitter
{externalLinkIcon}
</MenuItem>
<MenuItem
component="a"
href={EXTERNAL_LINKS.productHunt}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon sx={{ mr: 1 }}>
<SocialLogo platform="productHunt" />
</ListItemIcon>
Product Hunt
{externalLinkIcon}
</MenuItem>
</Menu>
);
}

View File

@@ -0,0 +1,174 @@
import { useAtom, useSetAtom } from "jotai";
import { Typography, Button } from "@mui/material";
import UncheckedIcon from "@mui/icons-material/RadioButtonUnchecked";
import CheckedIcon from "@mui/icons-material/CheckCircleOutline";
import AddIcon from "@mui/icons-material/Add";
import MembersIcon from "@mui/icons-material/AccountCircleOutlined";
import { Project as ProjectIcon } from "@src/assets/icons";
import Modal, { IModalProps } from "@src/components/Modal";
import SteppedAccordion from "@src/components/SteppedAccordion";
import Progress from "./Progress";
import {
globalScope,
getStartedChecklistAtom,
tableSettingsDialogAtom,
} from "@src/atoms/globalScope";
import {
NAV_DRAWER_WIDTH,
NAV_DRAWER_COLLAPSED_WIDTH,
} from "@src/layouts/Navigation/NavDrawer";
export interface IGetStartedChecklistProps extends Partial<IModalProps> {
navOpen: boolean;
navPermanent: boolean;
}
export default function GetStartedChecklist({
navOpen,
navPermanent,
...props
}: IGetStartedChecklistProps) {
const [open, setOpen] = useAtom(getStartedChecklistAtom, globalScope);
const openTableSettingsDialog = useSetAtom(
tableSettingsDialogAtom,
globalScope
);
if (!open) return null;
return (
<Modal
{...props}
onClose={() => setOpen(false)}
title="Get started"
hideBackdrop
maxWidth="xs"
PaperProps={{ elevation: 8 }}
fullScreen={false}
sx={[
{
"& .MuiDialog-container": {
justifyContent: "flex-start",
alignItems: "flex-end",
},
"& .MuiDialog-paper": {
marginLeft: {
xs: `max(env(safe-area-inset-left), 8px)`,
sm: `max(env(safe-area-inset-left), ${
(navPermanent
? navOpen
? NAV_DRAWER_WIDTH
: NAV_DRAWER_COLLAPSED_WIDTH
: 0) + 8
}px)`,
},
marginBottom: `max(env(safe-area-inset-bottom), 8px)`,
marginRight: `max(env(safe-area-inset-right), 8px)`,
width: 360,
},
},
]}
>
<Progress sx={{ mb: 2 }} />
<SteppedAccordion
steps={[
{
id: "workspace",
title: "Create a workspace",
labelButtonProps: { icon: <CheckedIcon color="success" /> },
content: null,
},
{
id: "tutorial",
title: "Complete the table tutorial",
labelButtonProps: { icon: <UncheckedIcon color="action" /> },
content: (
<>
<Typography>This is why you should</Typography>
<Button variant="contained" color="primary">
Begin tutorial
</Button>
</>
),
},
{
id: "project",
title: "Create a project",
labelButtonProps: { icon: <UncheckedIcon color="action" /> },
content: (
<>
<Typography>
Youre ready to create a project and connect to a data source
</Typography>
<Button
variant="contained"
color="primary"
startIcon={<ProjectIcon />}
>
Create project
</Button>
</>
),
},
{
id: "table",
title: "Create a table",
labelButtonProps: { icon: <UncheckedIcon color="action" /> },
content: (
<>
<Typography>This is why you should</Typography>
<Button
variant="contained"
color="primary"
startIcon={<AddIcon />}
onClick={() => openTableSettingsDialog({ open: true })}
>
Create table
</Button>
</>
),
},
{
id: "members",
title: "Invite team members",
labelButtonProps: { icon: <UncheckedIcon color="action" /> },
content: (
<>
<Typography>
Go to the members page to invite someone
</Typography>
<Button
variant="contained"
color="primary"
startIcon={<MembersIcon />}
>
Members
</Button>
</>
),
},
]}
sx={{
"& .MuiStepConnector-root": {
my: -10 / 8,
},
"& .Mui-active + .MuiStep-root:not(:last-of-type) .MuiStepContent-root":
{
mt: -10 / 8,
pt: 10 / 8,
mb: 10 / 8,
pb: 2,
},
"& .MuiStepContent-root .MuiCollapse-wrapperInner > * + *": {
mt: 1,
},
}}
/>
</Modal>
);
}

View File

@@ -0,0 +1,23 @@
import { Box, BoxProps, Typography } from "@mui/material";
import { spreadSx } from "@src/utils/ui";
export default function Progress({ sx }: Partial<BoxProps>) {
return (
<Box
sx={[
{ display: "flex", alignItems: "center", gap: 0.5 },
...spreadSx(sx),
]}
>
<Typography style={{ flex: 3 }}>1/5</Typography>
<Box
sx={{ flex: 1, borderRadius: 1, height: 8, bgcolor: "success.light" }}
/>
<Box sx={{ flex: 1, borderRadius: 1, height: 8, bgcolor: "divider" }} />
<Box sx={{ flex: 1, borderRadius: 1, height: 8, bgcolor: "divider" }} />
<Box sx={{ flex: 1, borderRadius: 1, height: 8, bgcolor: "divider" }} />
<Box sx={{ flex: 1, borderRadius: 1, height: 8, bgcolor: "divider" }} />
</Box>
);
}

View File

@@ -0,0 +1,2 @@
export * from "./GetStartedChecklist";
export { default } from "./GetStartedChecklist";

View File

@@ -1,30 +1,39 @@
import { useEffect } from "react";
import {
Menu,
MenuProps,
ListSubheader,
MenuItem,
ListItemIcon,
ListItemSecondaryAction,
Divider,
} from "@mui/material";
import DocsIcon from "@mui/icons-material/LibraryBooksOutlined";
import { Discord as DiscordIcon } from "@src/assets/icons";
import GitHubIcon from "@mui/icons-material/GitHub";
import TwitterIcon from "@mui/icons-material/Twitter";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import SocialLogo from "@src/components/SocialLogo";
import { EXTERNAL_LINKS } from "@src/constants/externalLinks";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import { analytics } from "analytics";
import { logEvent, analytics } from "analytics";
export default function HelpMenu({
anchorEl,
onClose,
}: Pick<MenuProps, "anchorEl" | "onClose">) {
// useEffect(() => {
// analytics.logEvent("open_help_menu");
// }, []);
const open = Boolean(anchorEl);
useEffect(() => {
if (open) logEvent(analytics, "open_help_menu");
}, [open]);
const externalLinkIcon = (
<ListItemSecondaryAction sx={{ right: 10, color: "text.disabled" }}>
<ListItemSecondaryAction
sx={{
position: "static",
transform: "none",
ml: "auto",
pl: 2,
color: "text.disabled",
}}
>
<InlineOpenInNewIcon />
</ListItemSecondaryAction>
);
@@ -32,50 +41,60 @@ export default function HelpMenu({
return (
<Menu
anchorEl={anchorEl}
open={Boolean(anchorEl)}
open={open}
onClose={onClose}
id="help-menu"
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
transformOrigin={{ vertical: "bottom", horizontal: "left" }}
sx={{ "& .MuiPaper-root": { mt: 0.5, minWidth: 160 } }}
sx={{ "& .MuiPaper-root": { mt: 0.5, py: 1 } }}
PaperProps={{ elevation: 10 }}
>
<ListSubheader
sx={{
mb: 0.5,
typography: "subtitle1",
}}
>
Get support
</ListSubheader>
<ListSubheader
sx={{
mb: 1.5,
maxWidth: 260,
typography: "body2",
color: "text.secondary",
}}
>
Reach out for help and find FAQs on GitHub Discussions
</ListSubheader>
<MenuItem
component="a"
href={EXTERNAL_LINKS.discord}
href={EXTERNAL_LINKS.gitHub + "/discussions"}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon>
<DiscordIcon />
<ListItemIcon sx={{ mr: 1 }}>
<SocialLogo platform="gitHub" />
</ListItemIcon>
Discord
GitHub Discussions
{externalLinkIcon}
</MenuItem>
<Divider variant="middle" />
<MenuItem
component="a"
href={EXTERNAL_LINKS.gitHub}
href={EXTERNAL_LINKS.gitHub + "/issues/new/choose"}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon>
<GitHubIcon />
<ListItemIcon sx={{ mr: 1 }}>
<SocialLogo platform="gitHub" />
</ListItemIcon>
GitHub
{externalLinkIcon}
</MenuItem>
<MenuItem
component="a"
href={EXTERNAL_LINKS.twitter}
target="_blank"
rel="noopener noreferrer"
onClick={onClose as any}
>
<ListItemIcon>
<TwitterIcon />
</ListItemIcon>
Twitter
Feature request
{externalLinkIcon}
</MenuItem>
</Menu>

View File

@@ -4,6 +4,7 @@ import { find, groupBy } from "lodash-es";
import { colord } from "colord";
import {
alpha,
Drawer,
DrawerProps,
Stack,
@@ -17,28 +18,31 @@ import {
} from "@mui/material";
import CloseIcon from "@mui/icons-material/MenuOpen";
import HomeIcon from "@mui/icons-material/HomeOutlined";
import SettingsIcon from "@mui/icons-material/SettingsOutlined";
import UserManagementIcon from "@mui/icons-material/AccountCircleOutlined";
import AddIcon from "@mui/icons-material/Add";
import DocsIcon from "@mui/icons-material/LibraryBooksOutlined";
import LearningIcon from "@mui/icons-material/LocalLibraryOutlined";
import HelpIcon from "@mui/icons-material/HelpOutline";
import CommunityIcon from "@mui/icons-material/SentimentSatisfiedAltOutlined";
import InlineOpenInNewIcon from "@src/components/InlineOpenInNewIcon";
import { ChevronRight as ChevronRightIcon } from "@src/assets/icons";
import {
ChevronRight as ChevronRightIcon,
Checklist as ChecklistIcon,
} from "@src/assets/icons";
import Logo from "@src/assets/Logo";
import NavItem from "./NavItem";
import SettingsNav from "./SettingsNav";
import NavTableSection from "./NavTableSection";
import UpdateCheckBadge from "./UpdateCheckBadge";
import Progress from "./GetStartedChecklist/Progress";
import CommunityMenu from "./CommunityMenu";
import HelpMenu from "./HelpMenu";
import {
globalScope,
userRolesAtom,
userSettingsAtom,
tablesAtom,
tableSettingsDialogAtom,
getStartedChecklistAtom,
} from "@src/atoms/globalScope";
import { TableSettings } from "@src/types/table";
import { ROUTES } from "@src/constants/routes";
@@ -61,16 +65,23 @@ export default function NavDrawer({
}: INavDrawerProps) {
const [tables] = useAtom(tablesAtom, globalScope);
const [userSettings] = useAtom(userSettingsAtom, globalScope);
const [userRoles] = useAtom(userRolesAtom, globalScope);
const openTableSettingsDialog = useSetAtom(
tableSettingsDialogAtom,
globalScope
);
const openGetStartedChecklist = useSetAtom(
getStartedChecklistAtom,
globalScope
);
const [hover, setHover] = useState(false);
const [communityMenuAnchorEl, setCommunityMenuAnchorEl] =
useState<HTMLButtonElement | null>(null);
const [helpMenuAnchorEl, setHelpMenuAnchorEl] =
useState<HTMLButtonElement | null>(null);
const menuOpen = communityMenuAnchorEl || helpMenuAnchorEl;
const favorites = Array.isArray(userSettings.favoriteTables)
? userSettings.favoriteTables
: [];
@@ -82,7 +93,7 @@ export default function NavDrawer({
};
const collapsed = !open && isPermanent;
const tempExpanded = hover && collapsed;
const tempExpanded = (hover || menuOpen) && collapsed;
const width =
collapsed && !tempExpanded ? NAV_DRAWER_COLLAPSED_WIDTH : NAV_DRAWER_WIDTH;
const closeDrawer = isPermanent
@@ -111,8 +122,15 @@ export default function NavDrawer({
"& .MuiDrawer-paper": {
width,
pt: 0,
pb: 1,
scrollbarWidth: "thin",
"--nav-bg": (theme) =>
colord(theme.palette.background.paper)
.mix("#fff", 0.09) // elevation 8
.alpha(1)
.toHslString(),
bgcolor: "var(--nav-bg)",
backgroundImage: "none",
},
},
isPermanent && {
@@ -135,7 +153,7 @@ export default function NavDrawer({
overflowX: "hidden",
borderRight: "none",
bgcolor: "background.default",
"--nav-bg": (theme) => theme.palette.background.default,
},
"& .MuiListItemSecondaryAction-root": {
@@ -158,9 +176,9 @@ export default function NavDrawer({
tempExpanded && {
zIndex: "drawer",
"& .MuiDrawer-paper": {
bgcolor: (theme) =>
"--nav-bg": (theme) =>
colord(theme.palette.background.paper)
.mix("#fff", 0.09)
.mix("#fff", 0.09) // elevation 8
.alpha(1)
.toHslString(),
boxShadow: (theme) =>
@@ -168,14 +186,25 @@ export default function NavDrawer({
},
},
]}
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
PaperProps={{
elevation: isPermanent ? 0 : 8,
onMouseEnter: () => setHover(true),
onMouseLeave: () => setHover(false),
}}
>
{!isPermanent && (
<Stack
direction="row"
alignItems="center"
sx={{ height: TOP_BAR_HEIGHT, flexShrink: 0, px: 0.5 }}
sx={{
height: TOP_BAR_HEIGHT,
flexShrink: 0,
px: 0.5,
position: "sticky",
top: 0,
zIndex: 1,
backgroundColor: "var(--nav-bg)",
}}
>
<IconButton
aria-label="Close navigation drawer"
@@ -191,8 +220,15 @@ export default function NavDrawer({
<nav style={{ flexGrow: 1 }}>
<List
component="ol"
disablePadding
style={{ height: "100%", display: "flex", flexDirection: "column" }}
style={{
height: "100%",
display: "flex",
flexDirection: "column",
position: "static",
backgroundColor: "var(--nav-bg)",
}}
>
<li>
<NavItem to={ROUTES.tables} onClick={closeDrawer}>
@@ -203,47 +239,13 @@ export default function NavDrawer({
</NavItem>
</li>
<li>
<NavItem to={ROUTES.userSettings} onClick={closeDrawer}>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary="Settings" />
{userRoles.includes("ADMIN") && (
<UpdateCheckBadge sx={{ mr: 1.5 }} />
)}
</NavItem>
</li>
{userRoles.includes("ADMIN") && (
<li>
<NavItem to={ROUTES.members} onClick={closeDrawer}>
<ListItemIcon>
<UserManagementIcon />
</ListItemIcon>
<ListItemText primary="Members" />
</NavItem>
</li>
)}
<SettingsNav
closeDrawer={closeDrawer as any}
collapsed={isPermanent && !open && !tempExpanded}
/>
<Divider variant="middle" sx={{ my: 1 }} />
<li>
<NavItem
{...({ component: "button" } as any)}
style={{ textAlign: "left" }}
onClick={(e: any) => {
if (closeDrawer) closeDrawer(e);
openTableSettingsDialog({});
}}
>
<ListItemIcon>
<AddIcon />
</ListItemIcon>
<ListItemText primary="Create table…" />
</NavItem>
</li>
{sections &&
Object.entries(sections)
.filter(([, tables]) => tables.length > 0)
@@ -253,61 +255,142 @@ export default function NavDrawer({
section={section}
tables={tables}
closeDrawer={closeDrawer}
hidden={isPermanent && !open && !tempExpanded}
collapsed={isPermanent && !open && !tempExpanded}
/>
))}
<Divider variant="middle" sx={{ my: 1, mt: "auto" }} />
<li>
<NavItem href={EXTERNAL_LINKS.docs}>
<ListItemIcon>
<DocsIcon />
</ListItemIcon>
<ListItemText primary="Docs" />
{externalLinkIcon}
</NavItem>
</li>
<li>
<NavItem href={WIKI_LINKS.howTo}>
<ListItemIcon>
<LearningIcon />
</ListItemIcon>
<ListItemText primary="Learning" />
{externalLinkIcon}
</NavItem>
</li>
<li>
<NavItem
onClick={(e: any) => setHelpMenuAnchorEl(e.currentTarget)}
{...({ component: "button" } as any)}
onClick={(e: any) => {
if (closeDrawer) closeDrawer(e);
openTableSettingsDialog({});
}}
sx={{ mb: 1 }}
>
<ListItemIcon>
<CommunityIcon />
<AddIcon />
</ListItemIcon>
<ListItemText primary="Join our community" />
<ListItemSecondaryAction>
<ChevronRightIcon />
</ListItemSecondaryAction>
</NavItem>
</li>
<li>
<NavItem
onClick={(e: any) => setHelpMenuAnchorEl(e.currentTarget)}
>
<ListItemIcon>
<HelpIcon />
</ListItemIcon>
<ListItemText primary="Help" />
<ListItemSecondaryAction>
<ChevronRightIcon />
</ListItemSecondaryAction>
<ListItemText primary="Create table…" />
</NavItem>
</li>
<HelpMenu
anchorEl={helpMenuAnchorEl}
onClose={() => setHelpMenuAnchorEl(null)}
/>
<List
component="li"
disablePadding
sx={{
position: "sticky",
bottom: 0,
bgcolor: "var(--nav-bg)",
mt: "auto",
pb: 1,
}}
>
<ol style={{ listStyle: "none", margin: 0, padding: 0 }}>
<Divider variant="middle" sx={{ mb: 1 }} />
<li>
<NavItem
onClick={() => {
openGetStartedChecklist(true);
setHover(false);
}}
sx={{
mb: 1,
py: 0.5,
bgcolor: (theme) =>
alpha(
theme.palette.primary.main,
theme.palette.action.selectedOpacity
),
"&:hover": {
bgcolor: (theme) =>
alpha(
theme.palette.primary.main,
theme.palette.action.selectedOpacity +
theme.palette.action.hoverOpacity
),
},
"& *, &&:hover *": {
color: (theme) =>
theme.palette.primary[
theme.palette.mode === "dark" ? "light" : "dark"
],
},
}}
>
<ListItemIcon>
<ChecklistIcon />
</ListItemIcon>
<ListItemText
primary="Get started"
secondary={<Progress sx={{ mr: 3 }} />}
/>
<ListItemSecondaryAction>
<ChevronRightIcon />
</ListItemSecondaryAction>
</NavItem>
</li>
<li>
<NavItem href={EXTERNAL_LINKS.docs}>
<ListItemIcon>
<DocsIcon />
</ListItemIcon>
<ListItemText primary="Docs" />
{externalLinkIcon}
</NavItem>
</li>
<li>
<NavItem href={WIKI_LINKS.howTo}>
<ListItemIcon>
<LearningIcon />
</ListItemIcon>
<ListItemText primary="Learning" />
{externalLinkIcon}
</NavItem>
</li>
<li>
<NavItem
onClick={(e: any) =>
setCommunityMenuAnchorEl(e.currentTarget)
}
>
<ListItemIcon>
<CommunityIcon />
</ListItemIcon>
<ListItemText primary="Join our community" />
<ListItemSecondaryAction>
<ChevronRightIcon />
</ListItemSecondaryAction>
</NavItem>
<CommunityMenu
anchorEl={communityMenuAnchorEl}
onClose={() => setCommunityMenuAnchorEl(null)}
/>
</li>
<li>
<NavItem
onClick={(e: any) => setHelpMenuAnchorEl(e.currentTarget)}
>
<ListItemIcon>
<HelpIcon />
</ListItemIcon>
<ListItemText primary="Help" />
<ListItemSecondaryAction>
<ChevronRightIcon />
</ListItemSecondaryAction>
</NavItem>
<HelpMenu
anchorEl={helpMenuAnchorEl}
onClose={() => setHelpMenuAnchorEl(null)}
/>
</li>
</ol>
</List>
</List>
</nav>
</Drawer>

View File

@@ -23,14 +23,14 @@ export interface INavTableSectionProps {
section: string;
tables: TableSettings[];
closeDrawer?: (e: {}) => void;
hidden?: boolean;
collapsed?: boolean;
}
export default function NavTableSection({
section,
tables,
closeDrawer,
hidden,
collapsed,
}: INavTableSectionProps) {
const { pathname } = useLocation();
const hasMatch = tables.map(getTableRoute).includes(pathname);
@@ -39,16 +39,8 @@ export default function NavTableSection({
const isFavorites = section === "Favorites";
return (
<li
style={{
opacity: hidden ? 0.38 : 1,
transitionProperty: "opacity",
transitionTimingFunction: "var(--nav-transition-timing-function)",
transitionDuration: "var(--nav-transition-duration)",
}}
>
<li>
<NavItem
{...({ component: "button" } as any)}
selected={!isFavorites && hasMatch && !open}
onClick={() => setOpen((o) => !o)}
>
@@ -71,7 +63,7 @@ export default function NavTableSection({
</ListItemSecondaryAction>
</NavItem>
<Collapse in={open}>
<Collapse in={open && !collapsed}>
<List style={{ paddingTop: 0 }}>
{tables.map((table) => {
const route = getTableRoute(table);

View File

@@ -11,6 +11,7 @@ import ErrorFallback, {
IErrorFallbackProps,
} from "@src/components/ErrorFallback";
import Loading from "@src/components/Loading";
import GetStartedChecklist from "./GetStartedChecklist";
import {
globalScope,
@@ -51,6 +52,7 @@ export default function Navigation({ children }: React.PropsWithChildren<{}>) {
isPermanent={isPermanent}
onClose={() => setOpen(false)}
/>
<GetStartedChecklist navOpen={open} navPermanent={isPermanent} />
<ErrorBoundary FallbackComponent={StyledErrorFallback}>
<Suspense

View File

@@ -0,0 +1,115 @@
import { useState } from "react";
import { useAtom } from "jotai";
import { useLocation } from "react-router-dom";
import {
ListItemIcon,
ListItemText,
ListItemSecondaryAction,
Collapse,
List,
} from "@mui/material";
import MembersIcon from "@mui/icons-material/AccountCircleOutlined";
import SettingsIcon from "@mui/icons-material/SettingsOutlined";
import { ChevronDown } from "@src/assets/icons";
import NavItem from "./NavItem";
import UpdateCheckBadge from "./UpdateCheckBadge";
import { globalScope, userRolesAtom } from "@src/atoms/globalScope";
import { ROUTES } from "@src/constants/routes";
export interface ISettingsNavProps {
closeDrawer: () => void;
collapsed: boolean;
}
export default function SettingsNav({
closeDrawer,
collapsed,
}: ISettingsNavProps) {
const [userRoles] = useAtom(userRolesAtom, globalScope);
const { pathname } = useLocation();
const [open, setOpen] = useState(pathname.includes(ROUTES.settings));
if (!userRoles.includes("ADMIN"))
return (
<li>
<NavItem to={ROUTES.userSettings} onClick={closeDrawer}>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary="Settings" />
</NavItem>
</li>
);
return (
<>
<li>
<NavItem to={ROUTES.members} onClick={closeDrawer}>
<ListItemIcon>
<MembersIcon />
</ListItemIcon>
<ListItemText primary="Members" />
</NavItem>
</li>
<li>
<NavItem onClick={() => setOpen((o) => !o)}>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary="Settings" />
<ListItemSecondaryAction>
<ChevronDown
sx={{
color: "action.active",
m: 0.25,
display: "block",
transform: open ? "rotate(180deg)" : "rotate(0)",
transition: (theme) => theme.transitions.create("transform"),
}}
/>
</ListItemSecondaryAction>
{userRoles.includes("ADMIN") && <UpdateCheckBadge sx={{ mr: 1.5 }} />}
</NavItem>
<Collapse in={open && !collapsed}>
<List style={{ paddingTop: 0 }}>
<li>
<NavItem to={ROUTES.userSettings} onClick={closeDrawer}>
<ListItemIcon />
<ListItemText
primary="User"
sx={{
"&& .MuiListItemText-primary": {
fontWeight: "normal",
fontSize: ".8125rem",
},
}}
/>
</NavItem>
</li>
<li>
<NavItem to={ROUTES.projectSettings} onClick={closeDrawer}>
<ListItemIcon />
<ListItemText
primary="Project"
sx={{
"&& .MuiListItemText-primary": {
fontWeight: "normal",
fontSize: ".8125rem",
},
}}
/>
</NavItem>
</li>
</List>
</Collapse>
</li>
</>
);
}

View File

@@ -134,7 +134,7 @@ export default function TopBar({
ml: 1,
},
!(routeTitle as any)?.leftAligned && {
ml: { xs: 1, sm: 208 / 8 + 1 },
ml: { xs: 1, sm: 40 / 8 + 1, md: 208 / 8 + 1 },
},
isPermanent &&
(routeTitle as any)?.leftAligned && {
@@ -167,11 +167,16 @@ export default function TopBar({
to={ROUTES.members}
startIcon={<PersonAddIcon />}
sx={{
minWidth: 40,
"&&": { px: { xs: 1, md: 2 } },
mr: 1,
"&.active": { visibility: "hidden" },
"& .text": { display: { xs: "none", md: "inline" } },
"& .MuiButton-startIcon": { mr: { xs: 0, md: 1 } },
}}
>
Invite team members
<span className="text">Invite team members</span>
</Button>
<UserMenu />