switch to nx monorepo

This commit is contained in:
Philipinho
2024-01-09 18:58:26 +01:00
parent e1bb2632b8
commit 093e634c0b
273 changed files with 11419 additions and 31 deletions

View File

@ -0,0 +1,6 @@
.breadcrumb {
a {
color: var(--mantine-color-default-color);
text-overflow: ellipsis;
}
}

View File

@ -0,0 +1,104 @@
import { useAtomValue } from 'jotai';
import { treeDataAtom } from '@/features/page/tree/atoms/tree-data-atom';
import React, { useEffect, useState } from 'react';
import { TreeNode } from '@/features/page/tree/types';
import { findBreadcrumbPath } from '@/features/page/tree/utils';
import {
Button,
Anchor,
Popover,
Breadcrumbs,
ActionIcon,
Text,
} from '@mantine/core';
import {
IconDots,
} from '@tabler/icons-react';
import { Link, useParams } from 'react-router-dom';
import classes from './breadcrumb.module.css';
export default function Breadcrumb() {
const treeData = useAtomValue(treeDataAtom);
const [breadcrumbNodes, setBreadcrumbNodes] = useState<TreeNode[] | null>(
null,
);
const { pageId } = useParams();
useEffect(() => {
if (treeData.length) {
const breadcrumb = findBreadcrumbPath(treeData, pageId);
if (breadcrumb) {
setBreadcrumbNodes(breadcrumb);
}
}
}, [pageId, treeData]);
useEffect(() => {
if (treeData.length) {
const breadcrumb = findBreadcrumbPath(treeData, pageId);
if (breadcrumb) setBreadcrumbNodes(breadcrumb);
}
}, [pageId, treeData]);
const HiddenNodesTooltipContent = () => (
breadcrumbNodes?.slice(1, -2).map(node => (
<Button.Group orientation="vertical" key={node.id}>
<Button
justify="start"
component={Link}
to={`/p/${node.id}`}
variant="default"
style={{ border: 'none' }}
>
<Text truncate="end">{node.name}</Text>
</Button>
</Button.Group>
))
);
const getLastNthNode = (n: number) => breadcrumbNodes && breadcrumbNodes[breadcrumbNodes.length - n];
const getBreadcrumbItems = () => {
if (breadcrumbNodes?.length > 3) {
return [
<Anchor component={Link} to={`/p/${breadcrumbNodes[0].id}`} underline="never" key={breadcrumbNodes[0].id}>
{breadcrumbNodes[0].name}
</Anchor>,
<Popover width={250} position="bottom" withArrow shadow="xl" key="hidden-nodes">
<Popover.Target>
<ActionIcon color="gray" variant="transparent">
<IconDots size={20} stroke={2} />
</ActionIcon>
</Popover.Target>
<Popover.Dropdown>
<HiddenNodesTooltipContent />
</Popover.Dropdown>
</Popover>,
<Anchor component={Link} to={`/p/${getLastNthNode(2)?.id}`} underline="never" key={getLastNthNode(2)?.id}>
{getLastNthNode(2)?.name}
</Anchor>,
<Anchor component={Link} to={`/p/${getLastNthNode(1)?.id}`} underline="never" key={getLastNthNode(1)?.id}>
{getLastNthNode(1)?.name}
</Anchor>,
];
}
if (breadcrumbNodes) {
return breadcrumbNodes.map(node => (
<Anchor component={Link} to={`/p/${node.id}`} underline="never" key={node.id}>
{node.name}
</Anchor>
));
}
return [];
};
return (
<div className={classes.breadcrumb}>
{breadcrumbNodes ? (
<Breadcrumbs>{getBreadcrumbItems()}</Breadcrumbs>
) : (<></>)}
</div>
);
}

View File

@ -0,0 +1,93 @@
import {
ActionIcon,
Menu,
Button,
} from '@mantine/core';
import {
IconDots,
IconFileInfo,
IconHistory,
IconLink,
IconLock,
IconShare,
IconTrash,
IconMessage,
} from '@tabler/icons-react';
import React from 'react';
import useToggleAside from '@/hooks/use-toggle-aside';
import { useAtom } from 'jotai';
import { historyAtoms } from '@/features/page-history/atoms/history-atoms';
export default function Header() {
const toggleAside = useToggleAside();
return (
<>
<Button variant="default" style={{ border: 'none' }} size="compact-sm">
Share
</Button>
<ActionIcon variant="default" style={{ border: 'none' }} onClick={() => toggleAside('comments')}>
<IconMessage size={20} stroke={2} />
</ActionIcon>
<PageActionMenu />
</>
);
}
function PageActionMenu() {
const [, setHistoryModalOpen] = useAtom(historyAtoms);
const openHistoryModal = () => {
setHistoryModalOpen(true);
};
return (
<Menu
shadow="xl"
position="bottom-end"
offset={20}
width={200}
withArrow
arrowPosition="center"
>
<Menu.Target>
<ActionIcon variant="default" style={{ border: 'none' }}>
<IconDots size={20} stroke={2} />
</ActionIcon>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item
leftSection={<IconFileInfo size={16} stroke={2} />}>
Page info
</Menu.Item>
<Menu.Item
leftSection={<IconLink size={16} stroke={2} />}
>
Copy link
</Menu.Item>
<Menu.Item
leftSection={<IconShare size={16} stroke={2} />}>
Share
</Menu.Item>
<Menu.Item
leftSection={<IconHistory size={16} stroke={2} />}
onClick={openHistoryModal}>
Page history
</Menu.Item>
<Menu.Divider />
<Menu.Item
leftSection={<IconLock size={16} stroke={2} />}>
Lock
</Menu.Item>
<Menu.Item
leftSection={<IconTrash size={16} stroke={2} />}>
Delete
</Menu.Item>
</Menu.Dropdown>
</Menu>
);
}

View File

@ -0,0 +1,14 @@
import { UserProvider } from '@/features/user/user-provider';
import Shell from './shell';
import { Outlet } from 'react-router-dom';
export default function DashboardLayout() {
return (
<UserProvider>
<Shell>
<Outlet />
</Shell>
</UserProvider>
);
}

View File

@ -0,0 +1,26 @@
.header,
.footer {
@media (max-width: 992px) {
[data-layout='alt'] & {
--_section-right: var(--app-shell-aside-offset, 0px);
}
}
}
.aside {
@media (min-width: 993px) {
background: var(--mantine-color-gray-light);
[data-layout='alt'] & {
--_section-top: var(--_section-top, var(--app-shell-header-offset, 0px));
--_section-height: var(
--_section-height,
calc(100dvh - var(--app-shell-header-offset, 0px) - var(--app-shell-footer-offset, 0px))
);
}
}
}

View File

@ -0,0 +1,88 @@
import { asideStateAtom, desktopSidebarAtom } from '@/components/navbar/atoms/sidebar-atom';
import { useToggleSidebar } from '@/components/navbar/hooks/use-toggle-sidebar';
import { Navbar } from '@/components/navbar/navbar';
import { AppShell, Burger, Group } from '@mantine/core';
import { useDisclosure } from '@mantine/hooks';
import { useAtom } from 'jotai';
import classes from './shell.module.css';
import Header from '@/components/layouts/header';
import Breadcrumb from '@/components/layouts/components/breadcrumb';
import Aside from '@/components/aside/aside';
import { useMatchPath } from '@/hooks/use-match-path';
import React from 'react';
export default function Shell({ children }: { children: React.ReactNode }) {
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure();
const [desktopOpened] = useAtom(desktopSidebarAtom);
const toggleDesktop = useToggleSidebar(desktopSidebarAtom);
const matchPath = useMatchPath();
const isPageRoute = matchPath('/p/:pageId');
const [{ isAsideOpen }] = useAtom(asideStateAtom);
return (
<AppShell
layout="alt"
header={{ height: 45 }}
navbar={{
width: 300,
breakpoint: 'sm',
collapsed: { mobile: !mobileOpened, desktop: !desktopOpened },
}}
aside={{
width: 300,
breakpoint: 'md',
collapsed: { mobile: (!isAsideOpen), desktop: (!isAsideOpen) },
}}
padding="md"
>
<AppShell.Header
className={classes.header}
>
<Group justify="space-between" h="100%" px="md" wrap="nowrap">
<Group h="100%" maw="60%" px="md" wrap="nowrap" style={{ overflow: 'hidden' }}>
<Burger
opened={mobileOpened}
onClick={toggleMobile}
hiddenFrom="sm"
size="sm"
/>
<Burger
opened={desktopOpened}
onClick={toggleDesktop}
visibleFrom="sm"
size="sm"
/>
{isPageRoute && <Breadcrumb />}
</Group>
{
isPageRoute &&
<Group justify="flex-end" h="100%" px="md" wrap="nowrap">
<Header />
</Group>
}
</Group>
</AppShell.Header>
<AppShell.Navbar>
<Navbar />
</AppShell.Navbar>
<AppShell.Main>
{children}
</AppShell.Main>
{
isPageRoute &&
<AppShell.Aside className={classes.aside}>
<Aside />
</AppShell.Aside>
}
</AppShell>
);
}