-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
// SPDX-FileCopyrightText: 2024 Shota FUJI <pockawoooh@gmail.com>
// SPDX-License-Identifier: AGPL-3.0-only
import { HamburgerMenuIcon } from "@radix-ui/react-icons";
import {
Box,
type BoxProps,
Container,
Flex,
Grid,
Heading,
IconButton,
} from "@radix-ui/themes";
import { type FC, type ReactNode, useCallback, useState } from "react";
import { useViewTransition } from "../hooks/useViewTransition.ts";
import css from "./WorkspacePagesLayout.module.css";
export interface WorkspacePagesLayoutProps
extends Pick<BoxProps, "className" | "children" | "style"> {
menu: ReactNode;
title: ReactNode;
/**
* この画面 (シーン) にグローバルな操作・アクション。
* Flex コンテナ内となるため、 Fragment で渡すとレイアウトされる。
*/
actions?: ReactNode;
defaultMenuOpened?: boolean;
}
export const WorkspacePagesLayout: FC<WorkspacePagesLayoutProps> = ({
menu,
children,
title,
actions,
defaultMenuOpened = false,
...rest
}) => {
const viewTransition = useViewTransition();
const [isMenuOpened, setIsMenuOpened] = useState(defaultMenuOpened);
const toggleMenu = useCallback(() => {
viewTransition(() => {
setIsMenuOpened((prev) => !prev);
});
}, [viewTransition]);
return (
<Grid
{...rest}
inset="0"
height="100%"
columns={{ initial: "1", md: "minmax(15rem, max-content) minmax(0, 1fr)" }}
rows="max-content minmax(0, 1fr)"
gapY="2"
>
<Box className={css.appbar} display={{ initial: "none", md: "block" }} />
<Flex className={css.appbar} p="2" align="center" gapX="3">
<Box display={{ md: "none" }}>
<IconButton variant="soft" onClick={toggleMenu}>
<HamburgerMenuIcon />
</IconButton>
</Box>
<Container size={{ initial: "4", md: "2", lg: "3" }}>
<Flex align="center" minHeight="var(--space-6)">
<Box flexGrow="1" flexShrink="1">
<Heading size="3">{title}</Heading>
</Box>
{actions && (
<Flex justify="end" gapX="1">
{actions}
</Flex>
)}
</Flex>
</Container>
</Flex>
<Box
className={css.menu}
p="2"
gridRowStart="2"
gridColumnStart="1"
display={{ initial: isMenuOpened ? "block" : "none", md: "block" }}
>
{menu}
</Box>
<Container
size={{ initial: "2", lg: "3" }}
p="2"
gridRowStart="2"
gridColumnStart={{ initial: "1", md: "2" }}
>
{children}
</Container>
</Grid>
);
};