Skip to content

Commit

Permalink
refactor to Drawer
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabor Juhasz committed Jul 11, 2022
1 parent a0c2f4b commit b65d15b
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 149 deletions.
149 changes: 52 additions & 97 deletions components/Box.tsx
Original file line number Diff line number Diff line change
@@ -1,128 +1,83 @@
import { Button, Group, Popover, Drawer } from "@mantine/core";
import { Favorites, FavoriteState } from "pages";
import { FC, useState } from "react";
import { useLongPress } from "react-use";
import { useMantineTheme } from "@mantine/core";
import { Gradient } from "components/Gradient";
import { Favorites } from "pages";
import { FC } from "react";
import { Item } from "types";

const getBackground = (itemState: FavoriteState) => {
switch (itemState) {
case "must": {
return "green";
}
case "maybe": {
return "yellow";
}
default: {
return "white";
}
}
};
export const SCALE_MINUTES_TO_PIXELS = 2.7;

interface BoxProps {
startOfDay: number;
item: Item;
favorites: Favorites;
setFavorites: React.Dispatch<React.SetStateAction<Favorites | undefined>>;
setDetailId: React.Dispatch<React.SetStateAction<string | null>>;
}
export const Box: FC<BoxProps> = ({ item, startOfDay, favorites, setFavorites }) => {
const [popoverOpen, setPopoverOpen] = useState(false);
const setOverlayState = (state: boolean) => setPopoverOpen(state);
const longPressEvent = useLongPress(() => setOverlayState(true));
export const Box: FC<BoxProps> = ({ item, startOfDay, favorites, setDetailId }) => {
const theme = useMantineTheme();

const itemState = favorites[item.id];
if (itemState === "nope") {
return null;
}

const setFavoriteState = (state?: FavoriteState) => {
setFavorites((favs) => {
if (!favs) {
favs = {};
const getBackground = () => {
switch (itemState) {
case "must": {
return theme.colors.green[4];
}
if (state) {
favs[item.id] = state;
} else {
delete favs[item.id];
case "maybe": {
return theme.colors.yellow[4];
}
return favs;
});
setOverlayState(false);
default: {
return "white";
}
}
};

return (
<li
{...longPressEvent}
onClick={() => setDetailId(item.id)}
style={{
listStyle: "none",
position: "absolute",
left: 0,
top: (item.relativeDateInMinutes - startOfDay) * 2,
top: (item.relativeDateInMinutes - startOfDay) * SCALE_MINUTES_TO_PIXELS,
padding: 4,
}}
>
<Popover
opened={popoverOpen}
onClose={() => setOverlayState(false)}
position="bottom"
target={
<div
style={{
position: "relative",
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
background: getBackground(itemState),
border: "1px solid gray",
height: popoverOpen ? "auto" : item.duration * 2,
minHeight: popoverOpen ? item.duration * 2 : "",
transform: popoverOpen ? "scale(1.05)" : "",
transition: "transform 400ms",
overflow: "hidden",
zIndex: popoverOpen ? 2 : "",
width: 272,
}}
>
<div style={{ padding: 8, flex: 1, minHeight: 0 }}>
<p
style={{
marginBottom: 16,
}}
>
{item.title}
</p>
<p dangerouslySetInnerHTML={{ __html: item.description }} />
</div>
<div
style={{
padding: 8,
background: getBackground(itemState),
display: "flex",
justifyContent: "space-between",
}}
>
<p>{item.time?.name}</p>
<p>{item.duration} perc</p>
</div>
</div>
}
<div
style={{
position: "relative",
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
background: getBackground(),
border: "1px solid rgba(0, 0, 0, .08)",
height: item.duration * SCALE_MINUTES_TO_PIXELS,
overflow: "hidden",
width: 272,
borderRadius: 8,
filter: "drop-shadow(0 4px 16px rgba(0, 0, 0, .16))",
}}
>
<Group direction="column">
{itemState && <Button onClick={() => setFavoriteState()}>Alapállapot</Button>}
{itemState !== "must" && (
<Button color="green" onClick={() => setFavoriteState("must")}>
Kötelező
</Button>
)}
{itemState !== "maybe" && (
<Button color="yellow" onClick={() => setFavoriteState("maybe")}>
Jó lenne
</Button>
)}
<Button color="red" onClick={() => setFavoriteState("nope")}>
Rejtsd el
</Button>
</Group>
</Popover>
<div style={{ padding: 6, flex: 1, minHeight: 0 }}>
<p style={{ lineHeight: 1.4 }}>{item.title}</p>
</div>

<Gradient height={20} color={getBackground()} />

<div
style={{
padding: 6,
background: getBackground(),
display: "flex",
justifyContent: "space-between",
}}
>
<p>{item.time?.name}</p>
<p>{item.duration} perc</p>
</div>
</div>
</li>
);
};
139 changes: 87 additions & 52 deletions components/Calendar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Box } from "components/Box";
import { Favorites } from "pages";
import { FC } from "react";
import { Drawer } from "@mantine/core";
import { Box, SCALE_MINUTES_TO_PIXELS } from "components/Box";
import { Detail } from "components/Detail";
import { Favorites, FavoriteState } from "pages";
import { FC, useState } from "react";
import { Item, Stage, Village } from "types";

const PADDING = 30;
Expand Down Expand Up @@ -34,12 +36,15 @@ interface CalendarProps {
setFavorites: React.Dispatch<React.SetStateAction<Favorites | undefined>>;
}
export const Calendar: FC<CalendarProps> = ({ list, favorites, setFavorites }) => {
const [detailId, setDetailId] = useState<string | null>(null);

// find the first program of the day
// show an extra 30 minutes of padding before
const startOfDay =
list.reduce((smallest, current) => {
return Math.min(smallest, current.relativeDateInMinutes);
}, Infinity) - PADDING;
}, Infinity) -
PADDING / 2;
const endOfDay =
list.reduce((biggest, current) => {
return Math.max(biggest, current.relativeDateInMinutes + current.duration);
Expand All @@ -49,58 +54,88 @@ export const Calendar: FC<CalendarProps> = ({ list, favorites, setFavorites }) =

const groups = groupByVillageAndStage(list);

const detail = list.find((item) => item.id === detailId);

const setFavoriteState = (item: Item, state?: FavoriteState) => {
setFavorites((favs) => {
if (!favs) {
favs = {};
}
if (state) {
favs[item.id] = state;
} else {
delete favs[item.id];
}
return favs;
});
setDetailId(null);
};

return (
<ul
style={{
display: "flex",
overflowX: "auto",
scrollSnapType: "x mandatory",
height: "100vh",
background: "lightgray",
}}
>
{groups.map((group) => {
return (
<li
key={group.stage}
style={{
position: "relative",
scrollSnapAlign: "start",
}}
>
<div
style={{
position: "sticky",
top: 0,
zIndex: 1,
background: "white",
}}
>
<p>{group.village}</p>
<p>{group.stage}</p>
</div>
<ul
<>
<Drawer
opened={detailId !== null}
onClose={() => setDetailId(null)}
position="right"
padding="md"
size="80%"
zIndex={301}
>
{detail && <Detail item={detail} favorites={favorites} setFavoriteState={setFavoriteState} />}
</Drawer>

<ul
style={{
display: "flex",
overflowX: "auto",
scrollSnapType: "x mandatory",
height: "100vh",
background: "lightgray",
}}
>
{groups.map((group) => {
return (
<li
key={group.stage}
style={{
width: 280,
position: "relative",
height: endOfDay * 2,
scrollSnapAlign: "start",
}}
>
{group.list.map((item) => {
return (
<Box
key={item.id}
item={item}
startOfDay={startOfDay}
favorites={favorites as Favorites}
setFavorites={setFavorites}
/>
);
})}
</ul>
</li>
);
})}
</ul>
<div
style={{
position: "sticky",
top: 0,
zIndex: 1,
background: "white",
}}
>
<p>{group.village}</p>
<p>{group.stage}</p>
</div>
<ul
style={{
width: 280,
position: "relative",
height: endOfDay * SCALE_MINUTES_TO_PIXELS,
}}
>
{group.list.map((item) => {
return (
<Box
key={item.id}
item={item}
startOfDay={startOfDay}
favorites={favorites as Favorites}
setDetailId={setDetailId}
/>
);
})}
</ul>
</li>
);
})}
</ul>
</>
);
};
45 changes: 45 additions & 0 deletions components/Detail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Button, Group, Space, Title } from "@mantine/core";
import { Gradient } from "components/Gradient";
import { Favorites, FavoriteState } from "pages";
import { FC } from "react";
import { Item } from "types";

interface DetailProps {
item: Item;
favorites: Favorites;
setFavoriteState: (item: Item, state?: FavoriteState) => void;
}
export const Detail: FC<DetailProps> = ({ item, favorites, setFavoriteState }) => {
const itemState = favorites[item.id];
if (itemState === "nope") {
return null;
}

return (
<Group direction="column" style={{ height: "100%", paddingBottom: 50 }}>
<div style={{ flex: 100, overflowY: "auto", paddingBottom: 50 }}>
<Title order={3}>{item.title}</Title>
<p dangerouslySetInnerHTML={{ __html: item.description }} />
</div>

<Gradient />

<Group direction="column" align="center" style={{ width: "100%", flexGrow: 1, justifyContent: "flex-end" }}>
{itemState && <Button onClick={() => setFavoriteState(item)}>Alapállapot</Button>}
{itemState !== "must" && (
<Button color="green" onClick={() => setFavoriteState(item, "must")}>
Kötelező
</Button>
)}
{itemState !== "maybe" && (
<Button color="yellow" onClick={() => setFavoriteState(item, "maybe")}>
Jó lenne
</Button>
)}
<Button color="red" onClick={() => setFavoriteState(item, "nope")}>
Rejtsd el
</Button>
</Group>
</Group>
);
};
Loading

1 comment on commit b65d15b

@vercel
Copy link

@vercel vercel bot commented on b65d15b Jul 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

katlan – ./

katlan-git-main-juhg24.vercel.app
katlan.vercel.app
katlan-juhg24.vercel.app

Please sign in to comment.