feat: select view buttons
This commit is contained in:
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { Group } from "@mantine/core";
|
||||
import ViewSelector from "@/app/deals/components/desktop/ViewSelector/ViewSelector";
|
||||
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
||||
import ProjectSelect from "@/components/selects/ProjectSelect/ProjectSelect";
|
||||
import useIsMobile from "@/hooks/utils/useIsMobile";
|
||||
|
||||
const TopToolPanel = () => {
|
||||
const { projects, setSelectedProjectId, selectedProject } =
|
||||
useProjectsContext();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
if (isMobile) return;
|
||||
|
||||
return (
|
||||
<Group justify={"space-between"}>
|
||||
<ViewSelector />
|
||||
<ProjectSelect
|
||||
data={projects}
|
||||
value={selectedProject}
|
||||
onChange={value => value && setSelectedProjectId(value.id)}
|
||||
/>
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default TopToolPanel;
|
||||
@ -0,0 +1,9 @@
|
||||
.container {
|
||||
width: 100%;
|
||||
border-radius: var(--mantine-radius-xl);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
padding: var(--mantine-spacing-xs);
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { FC, PropsWithChildren } from "react";
|
||||
import { Button } from "@mantine/core";
|
||||
import { useViewContext, View } from "@/app/deals/contexts/ViewContext";
|
||||
import SmallPageBlock from "@/components/layout/SmallPageBlock/SmallPageBlock";
|
||||
import style from "./ViewSelectButton.module.css";
|
||||
|
||||
type Props = {
|
||||
viewName: View;
|
||||
};
|
||||
|
||||
const ViewSelectButton: FC<PropsWithChildren<Props>> = ({
|
||||
viewName,
|
||||
children,
|
||||
}) => {
|
||||
const { view, setView } = useViewContext();
|
||||
|
||||
return (
|
||||
<SmallPageBlock
|
||||
active={view === viewName}
|
||||
style={{ borderRadius: "var(--mantine-radius-xl)" }}>
|
||||
<Button
|
||||
unstyled
|
||||
onClick={() => setView(viewName)}
|
||||
radius="xl"
|
||||
className={style.container}>
|
||||
{children}
|
||||
</Button>
|
||||
</SmallPageBlock>
|
||||
);
|
||||
};
|
||||
|
||||
export default ViewSelectButton;
|
||||
@ -0,0 +1,25 @@
|
||||
import {
|
||||
IconCalendarWeekFilled,
|
||||
IconLayoutDashboard,
|
||||
IconMenu2,
|
||||
} from "@tabler/icons-react";
|
||||
import { Group } from "@mantine/core";
|
||||
import ViewSelectButton from "@/app/deals/components/desktop/ViewSelectButton/ViewSelectButton";
|
||||
|
||||
const ViewSelector = () => {
|
||||
return (
|
||||
<Group>
|
||||
<ViewSelectButton viewName={"board"}>
|
||||
<IconLayoutDashboard />
|
||||
</ViewSelectButton>
|
||||
<ViewSelectButton viewName={"table"}>
|
||||
<IconMenu2 />
|
||||
</ViewSelectButton>
|
||||
<ViewSelectButton viewName={"schedule"}>
|
||||
<IconCalendarWeekFilled />
|
||||
</ViewSelectButton>
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
||||
export default ViewSelector;
|
||||
@ -1,6 +1,6 @@
|
||||
.container {
|
||||
@media (min-width: 48em) {
|
||||
max-width: calc(100vw - 450px);
|
||||
max-width: calc(100vw - 210px - var(--mantine-spacing-md));
|
||||
}
|
||||
@media (max-width: 48em) {
|
||||
max-width: 100vw;
|
||||
|
||||
28
src/app/deals/components/shared/PageBody/PageBody.tsx
Normal file
28
src/app/deals/components/shared/PageBody/PageBody.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { Space } from "@mantine/core";
|
||||
import MainBlockHeader from "@/app/deals/components/mobile/MainBlockHeader/MainBlockHeader";
|
||||
import Funnel from "@/app/deals/components/shared/Funnel/Funnel";
|
||||
import { DealsContextProvider } from "@/app/deals/contexts/DealsContext";
|
||||
import { useViewContext } from "@/app/deals/contexts/ViewContext";
|
||||
|
||||
const PageBody = () => {
|
||||
const { view } = useViewContext();
|
||||
|
||||
if (view === "board")
|
||||
return (
|
||||
<>
|
||||
<MainBlockHeader />
|
||||
<Space h={"md"} />
|
||||
<DealsContextProvider>
|
||||
<Funnel />
|
||||
</DealsContextProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
if (view === "table") return <>-</>;
|
||||
|
||||
return <>-</>;
|
||||
};
|
||||
|
||||
export default PageBody;
|
||||
@ -1,6 +1,6 @@
|
||||
|
||||
.container {
|
||||
height: calc(100vh - 150px);
|
||||
height: calc(100vh - 210px);
|
||||
@media (max-width: 48em) {
|
||||
width: 80vw;
|
||||
height: calc(100vh - 215px);
|
||||
|
||||
23
src/app/deals/contexts/ViewContext.tsx
Normal file
23
src/app/deals/contexts/ViewContext.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import makeContext from "@/lib/contextFactory/contextFactory";
|
||||
|
||||
export type View = "board" | "table" | "schedule";
|
||||
|
||||
type ViewContextState = {
|
||||
view: View;
|
||||
setView: (view: View) => void;
|
||||
};
|
||||
|
||||
const useViewContextState = (): ViewContextState => {
|
||||
const [view, setView] = useState<View>("board");
|
||||
|
||||
return {
|
||||
view,
|
||||
setView,
|
||||
};
|
||||
};
|
||||
|
||||
export const [ViewContextProvider, useViewContext] =
|
||||
makeContext<ViewContextState>(useViewContextState, "View");
|
||||
@ -3,12 +3,11 @@ import {
|
||||
HydrationBoundary,
|
||||
QueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
import { Space } from "@mantine/core";
|
||||
import Funnel from "@/app/deals/components/shared/Funnel/Funnel";
|
||||
import Header from "@/app/deals/components/shared/Header/Header";
|
||||
import PageBody from "@/app/deals/components/shared/PageBody/PageBody";
|
||||
import { BoardsContextProvider } from "@/app/deals/contexts/BoardsContext";
|
||||
import { ProjectsContextProvider } from "@/app/deals/contexts/ProjectsContext";
|
||||
import { StatusesContextProvider } from "@/app/deals/contexts/StatusesContext";
|
||||
import { ViewContextProvider } from "@/app/deals/contexts/ViewContext";
|
||||
import PageBlock from "@/components/layout/PageBlock/PageBlock";
|
||||
import PageContainer from "@/components/layout/PageContainer/PageContainer";
|
||||
import {
|
||||
@ -16,7 +15,7 @@ import {
|
||||
getProjectsOptions,
|
||||
} from "@/lib/client/@tanstack/react-query.gen";
|
||||
import { combineProviders } from "@/utils/combineProviders";
|
||||
import { DealsContextProvider } from "./contexts/DealsContext";
|
||||
import TopToolPanel from "./components/desktop/TopToolPanel/TopToolPanel";
|
||||
|
||||
async function prefetchData() {
|
||||
const queryClient = new QueryClient();
|
||||
@ -39,18 +38,16 @@ export default async function DealsPage() {
|
||||
[HydrationBoundary, { state: dehydrate(queryClient) }],
|
||||
[ProjectsContextProvider],
|
||||
[BoardsContextProvider],
|
||||
[StatusesContextProvider]
|
||||
[StatusesContextProvider],
|
||||
[ViewContextProvider]
|
||||
);
|
||||
|
||||
return (
|
||||
<Providers>
|
||||
<PageContainer>
|
||||
<PageBlock className={"mobile-margin-height"}>
|
||||
<Header />
|
||||
<Space h={"md"} />
|
||||
<DealsContextProvider>
|
||||
<Funnel />
|
||||
</DealsContextProvider>
|
||||
<TopToolPanel />
|
||||
<PageBlock>
|
||||
<PageBody />
|
||||
</PageBlock>
|
||||
</PageContainer>
|
||||
</Providers>
|
||||
|
||||
@ -18,13 +18,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-margin-height {
|
||||
height: var(--page-height);
|
||||
@media (min-width: 48em) {
|
||||
margin: var(--mantine-spacing-md);
|
||||
}
|
||||
}
|
||||
|
||||
.container-full-height {
|
||||
min-height: var(--page-height);
|
||||
height: var(--page-height);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
background-color: transparent;
|
||||
|
||||
@media (min-width: 48em) {
|
||||
gap: rem(10);
|
||||
gap: var(--mantine-spacing-md);
|
||||
padding: var(--mantine-spacing-md);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
|
||||
.container {
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
|
||||
@mixin dark {
|
||||
background-color: var(--mantine-color-dark-7-5);
|
||||
box-shadow: var(--dark-shadow);
|
||||
}
|
||||
@mixin light {
|
||||
background-color: var(--color-light-whitesmoke);
|
||||
box-shadow: var(--light-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
.container-active {
|
||||
@mixin dark {
|
||||
color: dodgerblue;
|
||||
}
|
||||
@mixin light {
|
||||
background-color: var(--color-light-aqua);
|
||||
box-shadow: var(--light-thick-shadow);
|
||||
}
|
||||
}
|
||||
|
||||
.container:hover {
|
||||
@mixin dark {
|
||||
box-shadow: var(--dark-thick-shadow);
|
||||
}
|
||||
@mixin light {
|
||||
background-color: var(--color-light-aqua);
|
||||
box-shadow: var(--light-thick-shadow);
|
||||
}
|
||||
}
|
||||
24
src/components/layout/SmallPageBlock/SmallPageBlock.tsx
Normal file
24
src/components/layout/SmallPageBlock/SmallPageBlock.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { CSSProperties, FC, ReactNode } from "react";
|
||||
import classNames from "classnames";
|
||||
import { Box } from "@mantine/core";
|
||||
import styles from "@/components/layout/SmallPageBlock/SmallPageBlock.module.css";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
style?: CSSProperties;
|
||||
active?: boolean;
|
||||
};
|
||||
|
||||
const SmallPageBlock: FC<Props> = ({ children, style, active = false }) => {
|
||||
return (
|
||||
<Box
|
||||
className={classNames(
|
||||
styles.container,
|
||||
active && styles["container-active"]
|
||||
)}
|
||||
style={style}>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
export default SmallPageBlock;
|
||||
@ -37,7 +37,10 @@ const EnterNameModal = ({
|
||||
<Flex
|
||||
gap={rem(10)}
|
||||
direction={"column"}>
|
||||
<TextInput {...form.getInputProps("name")} />
|
||||
<TextInput
|
||||
{...form.getInputProps("name")}
|
||||
data-autofocus
|
||||
/>
|
||||
<Button
|
||||
variant={"default"}
|
||||
type={"submit"}>
|
||||
|
||||
Reference in New Issue
Block a user