this.gui 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -0
- package/package.json +27 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +38 -0
- package/public/manifest.json +15 -0
- package/src/App.tsx +22 -0
- package/src/components/AvatarWithStatus.tsx +26 -0
- package/src/components/ChatBubble.tsx +135 -0
- package/src/components/ChatListItem.tsx +87 -0
- package/src/components/ChatsPane.tsx +110 -0
- package/src/components/ColorSchemeToggle.tsx +61 -0
- package/src/components/Header.tsx +47 -0
- package/src/components/MessageInput.tsx +97 -0
- package/src/components/MessagesPane.tsx +87 -0
- package/src/components/MessagesPaneHeader.tsx +105 -0
- package/src/components/MuiLogo.tsx +34 -0
- package/src/components/MyMessages.tsx +49 -0
- package/src/components/Sidebar.tsx +320 -0
- package/src/createServiceWorker.js +52 -0
- package/src/data.tsx +272 -0
- package/src/index.tsx +12 -0
- package/src/package.json +22 -0
- package/src/public/index.html +22 -0
- package/src/tsconfig.json +25 -0
- package/src/types.tsx +25 -0
- package/src/useScript.ts +101 -0
- package/src/utils.ts +53 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Box from '@mui/joy/Box';
|
|
3
|
+
import Sheet from '@mui/joy/Sheet';
|
|
4
|
+
import Stack from '@mui/joy/Stack';
|
|
5
|
+
import AvatarWithStatus from './AvatarWithStatus';
|
|
6
|
+
import ChatBubble from './ChatBubble';
|
|
7
|
+
import MessageInput from './MessageInput';
|
|
8
|
+
import MessagesPaneHeader from './MessagesPaneHeader';
|
|
9
|
+
import { ChatProps, MessageProps } from '../types';
|
|
10
|
+
|
|
11
|
+
type MessagesPaneProps = {
|
|
12
|
+
chat: ChatProps;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default function MessagesPane({ chat }: MessagesPaneProps) {
|
|
16
|
+
const [chatMessages, setChatMessages] = React.useState(chat.messages);
|
|
17
|
+
const [textAreaValue, setTextAreaValue] = React.useState('');
|
|
18
|
+
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
setChatMessages(chat.messages);
|
|
21
|
+
}, [chat.messages]);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Sheet
|
|
25
|
+
sx={{
|
|
26
|
+
height: { xs: 'calc(100dvh - var(--Header-height))', lg: '100dvh' },
|
|
27
|
+
display: 'flex',
|
|
28
|
+
flexDirection: 'column',
|
|
29
|
+
backgroundColor: 'background.level1',
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<MessagesPaneHeader sender={chat.sender} />
|
|
33
|
+
|
|
34
|
+
<Box
|
|
35
|
+
sx={{
|
|
36
|
+
display: 'flex',
|
|
37
|
+
flex: 1,
|
|
38
|
+
minHeight: 0,
|
|
39
|
+
px: 2,
|
|
40
|
+
py: 3,
|
|
41
|
+
overflowY: 'scroll',
|
|
42
|
+
flexDirection: 'column-reverse',
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
<Stack spacing={2} justifyContent="flex-end">
|
|
46
|
+
{chatMessages.map((message: MessageProps, index: number) => {
|
|
47
|
+
const isYou = message.sender === 'You';
|
|
48
|
+
return (
|
|
49
|
+
<Stack
|
|
50
|
+
key={index}
|
|
51
|
+
direction="row"
|
|
52
|
+
spacing={2}
|
|
53
|
+
flexDirection={isYou ? 'row-reverse' : 'row'}
|
|
54
|
+
>
|
|
55
|
+
{message.sender !== 'You' && (
|
|
56
|
+
<AvatarWithStatus
|
|
57
|
+
online={message.sender.online}
|
|
58
|
+
src={message.sender.avatar}
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
61
|
+
<ChatBubble variant={isYou ? 'sent' : 'received'} {...message} />
|
|
62
|
+
</Stack>
|
|
63
|
+
);
|
|
64
|
+
})}
|
|
65
|
+
</Stack>
|
|
66
|
+
</Box>
|
|
67
|
+
|
|
68
|
+
<MessageInput
|
|
69
|
+
textAreaValue={textAreaValue}
|
|
70
|
+
setTextAreaValue={setTextAreaValue}
|
|
71
|
+
onSubmit={() => {
|
|
72
|
+
const newId = chatMessages.length + 1;
|
|
73
|
+
const newIdString = newId.toString();
|
|
74
|
+
setChatMessages([
|
|
75
|
+
...chatMessages,
|
|
76
|
+
{
|
|
77
|
+
id: newIdString,
|
|
78
|
+
sender: 'You',
|
|
79
|
+
content: textAreaValue,
|
|
80
|
+
timestamp: 'Just now',
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
}}
|
|
84
|
+
/>
|
|
85
|
+
</Sheet>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Avatar from '@mui/joy/Avatar';
|
|
3
|
+
import Button from '@mui/joy/Button';
|
|
4
|
+
import Chip from '@mui/joy/Chip';
|
|
5
|
+
import IconButton from '@mui/joy/IconButton';
|
|
6
|
+
import Stack from '@mui/joy/Stack';
|
|
7
|
+
import Typography from '@mui/joy/Typography';
|
|
8
|
+
import CircleIcon from '@mui/icons-material/Circle';
|
|
9
|
+
import ArrowBackIosNewRoundedIcon from '@mui/icons-material/ArrowBackIosNewRounded';
|
|
10
|
+
import PhoneInTalkRoundedIcon from '@mui/icons-material/PhoneInTalkRounded';
|
|
11
|
+
import MoreVertRoundedIcon from '@mui/icons-material/MoreVertRounded';
|
|
12
|
+
import { UserProps } from '../types';
|
|
13
|
+
import { toggleMessagesPane } from '../utils';
|
|
14
|
+
|
|
15
|
+
type MessagesPaneHeaderProps = {
|
|
16
|
+
sender: UserProps;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function MessagesPaneHeader({ sender }: MessagesPaneHeaderProps) {
|
|
20
|
+
return (
|
|
21
|
+
<Stack
|
|
22
|
+
direction="row"
|
|
23
|
+
justifyContent="space-between"
|
|
24
|
+
sx={{
|
|
25
|
+
borderBottom: '1px solid',
|
|
26
|
+
borderColor: 'divider',
|
|
27
|
+
backgroundColor: 'background.body',
|
|
28
|
+
}}
|
|
29
|
+
py={{ xs: 2, md: 2 }}
|
|
30
|
+
px={{ xs: 1, md: 2 }}
|
|
31
|
+
>
|
|
32
|
+
<Stack direction="row" spacing={{ xs: 1, md: 2 }} alignItems="center">
|
|
33
|
+
<IconButton
|
|
34
|
+
variant="plain"
|
|
35
|
+
color="neutral"
|
|
36
|
+
size="sm"
|
|
37
|
+
sx={{
|
|
38
|
+
display: { xs: 'inline-flex', sm: 'none' },
|
|
39
|
+
}}
|
|
40
|
+
onClick={() => toggleMessagesPane()}
|
|
41
|
+
>
|
|
42
|
+
<ArrowBackIosNewRoundedIcon />
|
|
43
|
+
</IconButton>
|
|
44
|
+
<Avatar size="lg" src={sender.avatar} />
|
|
45
|
+
<div>
|
|
46
|
+
<Typography
|
|
47
|
+
fontWeight="lg"
|
|
48
|
+
fontSize="lg"
|
|
49
|
+
component="h2"
|
|
50
|
+
noWrap
|
|
51
|
+
endDecorator={
|
|
52
|
+
sender.online ? (
|
|
53
|
+
<Chip
|
|
54
|
+
variant="outlined"
|
|
55
|
+
size="sm"
|
|
56
|
+
color="neutral"
|
|
57
|
+
sx={{
|
|
58
|
+
borderRadius: 'sm',
|
|
59
|
+
}}
|
|
60
|
+
startDecorator={
|
|
61
|
+
<CircleIcon sx={{ fontSize: 8 }} color="success" />
|
|
62
|
+
}
|
|
63
|
+
slotProps={{ root: { component: 'span' } }}
|
|
64
|
+
>
|
|
65
|
+
Online
|
|
66
|
+
</Chip>
|
|
67
|
+
) : undefined
|
|
68
|
+
}
|
|
69
|
+
>
|
|
70
|
+
{sender.name}
|
|
71
|
+
</Typography>
|
|
72
|
+
|
|
73
|
+
<Typography level="body-sm">{sender.username}</Typography>
|
|
74
|
+
</div>
|
|
75
|
+
</Stack>
|
|
76
|
+
<Stack spacing={1} direction="row" alignItems="center">
|
|
77
|
+
<Button
|
|
78
|
+
startDecorator={<PhoneInTalkRoundedIcon />}
|
|
79
|
+
color="neutral"
|
|
80
|
+
variant="outlined"
|
|
81
|
+
size="sm"
|
|
82
|
+
sx={{
|
|
83
|
+
display: { xs: 'none', md: 'inline-flex' },
|
|
84
|
+
}}
|
|
85
|
+
>
|
|
86
|
+
Call
|
|
87
|
+
</Button>
|
|
88
|
+
<Button
|
|
89
|
+
color="neutral"
|
|
90
|
+
variant="outlined"
|
|
91
|
+
size="sm"
|
|
92
|
+
sx={{
|
|
93
|
+
display: { xs: 'none', md: 'inline-flex' },
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
View profile
|
|
97
|
+
</Button>
|
|
98
|
+
|
|
99
|
+
<IconButton size="sm" variant="plain" color="neutral">
|
|
100
|
+
<MoreVertRoundedIcon />
|
|
101
|
+
</IconButton>
|
|
102
|
+
</Stack>
|
|
103
|
+
</Stack>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import AspectRatio, { AspectRatioProps } from '@mui/joy/AspectRatio';
|
|
3
|
+
|
|
4
|
+
export default function MuiLogo({ sx, ...props }: AspectRatioProps) {
|
|
5
|
+
return (
|
|
6
|
+
<AspectRatio
|
|
7
|
+
ratio="1"
|
|
8
|
+
variant="plain"
|
|
9
|
+
{...props}
|
|
10
|
+
sx={[
|
|
11
|
+
{
|
|
12
|
+
width: 36,
|
|
13
|
+
borderRadius: 'sm',
|
|
14
|
+
},
|
|
15
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
16
|
+
]}
|
|
17
|
+
>
|
|
18
|
+
<div>
|
|
19
|
+
<svg
|
|
20
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
21
|
+
width="24"
|
|
22
|
+
height="20"
|
|
23
|
+
viewBox="0 0 36 32"
|
|
24
|
+
fill="none"
|
|
25
|
+
>
|
|
26
|
+
<path
|
|
27
|
+
d="M30.343 21.976a1 1 0 00.502-.864l.018-5.787a1 1 0 01.502-.864l3.137-1.802a1 1 0 011.498.867v10.521a1 1 0 01-.502.867l-11.839 6.8a1 1 0 01-.994.001l-9.291-5.314a1 1 0 01-.504-.868v-5.305c0-.006.007-.01.013-.007.005.003.012 0 .012-.007v-.006c0-.004.002-.008.006-.01l7.652-4.396c.007-.004.004-.015-.004-.015a.008.008 0 01-.008-.008l.015-5.201a1 1 0 00-1.5-.87l-5.687 3.277a1 1 0 01-.998 0L6.666 9.7a1 1 0 00-1.499.866v9.4a1 1 0 01-1.496.869l-3.166-1.81a1 1 0 01-.504-.87l.028-16.43A1 1 0 011.527.86l10.845 6.229a1 1 0 00.996 0L24.21.86a1 1 0 011.498.868v16.434a1 1 0 01-.501.867l-5.678 3.27a1 1 0 00.004 1.735l3.132 1.783a1 1 0 00.993-.002l6.685-3.839zM31 7.234a1 1 0 001.514.857l3-1.8A1 1 0 0036 5.434V1.766A1 1 0 0034.486.91l-3 1.8a1 1 0 00-.486.857v3.668z"
|
|
28
|
+
fill="#007FFF"
|
|
29
|
+
/>
|
|
30
|
+
</svg>
|
|
31
|
+
</div>
|
|
32
|
+
</AspectRatio>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import Sheet from '@mui/joy/Sheet';
|
|
3
|
+
import MessagesPane from './MessagesPane';
|
|
4
|
+
import ChatsPane from './ChatsPane';
|
|
5
|
+
import { ChatProps } from '../types';
|
|
6
|
+
import { chats } from '../data';
|
|
7
|
+
|
|
8
|
+
export default function MyProfile() {
|
|
9
|
+
const [selectedChat, setSelectedChat] = React.useState<ChatProps>(chats[0]);
|
|
10
|
+
return (
|
|
11
|
+
<Sheet
|
|
12
|
+
sx={{
|
|
13
|
+
flex: 1,
|
|
14
|
+
width: '100%',
|
|
15
|
+
mx: 'auto',
|
|
16
|
+
pt: { xs: 'var(--Header-height)', sm: 0 },
|
|
17
|
+
display: 'grid',
|
|
18
|
+
gridTemplateColumns: {
|
|
19
|
+
xs: '1fr',
|
|
20
|
+
sm: 'minmax(min-content, min(30%, 400px)) 1fr',
|
|
21
|
+
},
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
<Sheet
|
|
25
|
+
sx={{
|
|
26
|
+
position: {
|
|
27
|
+
xs: 'fixed',
|
|
28
|
+
sm: 'sticky',
|
|
29
|
+
},
|
|
30
|
+
transform: {
|
|
31
|
+
xs: 'translateX(calc(100% * (var(--MessagesPane-slideIn, 0) - 1)))',
|
|
32
|
+
sm: 'none',
|
|
33
|
+
},
|
|
34
|
+
transition: 'transform 0.4s, width 0.4s',
|
|
35
|
+
zIndex: 100,
|
|
36
|
+
width: '100%',
|
|
37
|
+
top: 52,
|
|
38
|
+
}}
|
|
39
|
+
>
|
|
40
|
+
<ChatsPane
|
|
41
|
+
chats={chats}
|
|
42
|
+
selectedChatId={selectedChat.id}
|
|
43
|
+
setSelectedChat={setSelectedChat}
|
|
44
|
+
/>
|
|
45
|
+
</Sheet>
|
|
46
|
+
<MessagesPane chat={selectedChat} />
|
|
47
|
+
</Sheet>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import GlobalStyles from '@mui/joy/GlobalStyles';
|
|
3
|
+
import Avatar from '@mui/joy/Avatar';
|
|
4
|
+
import Box from '@mui/joy/Box';
|
|
5
|
+
import Button from '@mui/joy/Button';
|
|
6
|
+
import Card from '@mui/joy/Card';
|
|
7
|
+
import Chip from '@mui/joy/Chip';
|
|
8
|
+
import Divider from '@mui/joy/Divider';
|
|
9
|
+
import IconButton from '@mui/joy/IconButton';
|
|
10
|
+
import Input from '@mui/joy/Input';
|
|
11
|
+
import LinearProgress from '@mui/joy/LinearProgress';
|
|
12
|
+
import List from '@mui/joy/List';
|
|
13
|
+
import ListItem from '@mui/joy/ListItem';
|
|
14
|
+
import ListItemButton, { listItemButtonClasses } from '@mui/joy/ListItemButton';
|
|
15
|
+
import ListItemContent from '@mui/joy/ListItemContent';
|
|
16
|
+
import Typography from '@mui/joy/Typography';
|
|
17
|
+
import Sheet from '@mui/joy/Sheet';
|
|
18
|
+
import Stack from '@mui/joy/Stack';
|
|
19
|
+
import SearchRoundedIcon from '@mui/icons-material/SearchRounded';
|
|
20
|
+
import HomeRoundedIcon from '@mui/icons-material/HomeRounded';
|
|
21
|
+
import DashboardRoundedIcon from '@mui/icons-material/DashboardRounded';
|
|
22
|
+
import CollectionsBookmarkRoundedIcon from '@mui/icons-material/CollectionsBookmarkRounded';
|
|
23
|
+
import AssignmentRoundedIcon from '@mui/icons-material/AssignmentRounded';
|
|
24
|
+
import QuestionAnswerRoundedIcon from '@mui/icons-material/QuestionAnswerRounded';
|
|
25
|
+
import GroupRoundedIcon from '@mui/icons-material/GroupRounded';
|
|
26
|
+
import SupportRoundedIcon from '@mui/icons-material/SupportRounded';
|
|
27
|
+
import SettingsRoundedIcon from '@mui/icons-material/SettingsRounded';
|
|
28
|
+
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
|
|
29
|
+
import LogoutRoundedIcon from '@mui/icons-material/LogoutRounded';
|
|
30
|
+
import BadgeRoundedIcon from '@mui/icons-material/BadgeRounded';
|
|
31
|
+
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
|
|
32
|
+
|
|
33
|
+
import ColorSchemeToggle from './ColorSchemeToggle';
|
|
34
|
+
import { closeSidebar } from '../utils';
|
|
35
|
+
|
|
36
|
+
function Toggler({
|
|
37
|
+
defaultExpanded = false,
|
|
38
|
+
renderToggle,
|
|
39
|
+
children,
|
|
40
|
+
}: {
|
|
41
|
+
defaultExpanded?: boolean;
|
|
42
|
+
children: React.ReactNode;
|
|
43
|
+
renderToggle: (params: {
|
|
44
|
+
open: boolean;
|
|
45
|
+
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
|
46
|
+
}) => React.ReactNode;
|
|
47
|
+
}) {
|
|
48
|
+
const [open, setOpen] = React.useState(defaultExpanded);
|
|
49
|
+
return (
|
|
50
|
+
<React.Fragment>
|
|
51
|
+
{renderToggle({ open, setOpen })}
|
|
52
|
+
<Box
|
|
53
|
+
sx={{
|
|
54
|
+
display: 'grid',
|
|
55
|
+
gridTemplateRows: open ? '1fr' : '0fr',
|
|
56
|
+
transition: '0.2s ease',
|
|
57
|
+
'& > *': {
|
|
58
|
+
overflow: 'hidden',
|
|
59
|
+
},
|
|
60
|
+
}}
|
|
61
|
+
>
|
|
62
|
+
{children}
|
|
63
|
+
</Box>
|
|
64
|
+
</React.Fragment>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default function Sidebar() {
|
|
69
|
+
return (
|
|
70
|
+
<Sheet
|
|
71
|
+
className="Sidebar"
|
|
72
|
+
sx={{
|
|
73
|
+
position: {
|
|
74
|
+
xs: 'fixed',
|
|
75
|
+
md: 'sticky',
|
|
76
|
+
},
|
|
77
|
+
transform: {
|
|
78
|
+
xs: 'translateX(calc(100% * (var(--SideNavigation-slideIn, 0) - 1)))',
|
|
79
|
+
md: 'none',
|
|
80
|
+
},
|
|
81
|
+
transition: 'transform 0.4s, width 0.4s',
|
|
82
|
+
zIndex: 10000,
|
|
83
|
+
height: '100dvh',
|
|
84
|
+
width: 'var(--Sidebar-width)',
|
|
85
|
+
top: 0,
|
|
86
|
+
p: 1.5,
|
|
87
|
+
py: 2,
|
|
88
|
+
flexShrink: 0,
|
|
89
|
+
display: 'flex',
|
|
90
|
+
flexDirection: 'column',
|
|
91
|
+
gap: 2,
|
|
92
|
+
borderRight: '1px solid',
|
|
93
|
+
borderColor: 'divider',
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
<GlobalStyles
|
|
97
|
+
styles={(theme) => ({
|
|
98
|
+
':root': {
|
|
99
|
+
'--Sidebar-width': '220px',
|
|
100
|
+
[theme.breakpoints.up('lg')]: {
|
|
101
|
+
'--Sidebar-width': '240px',
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
})}
|
|
105
|
+
/>
|
|
106
|
+
<Box
|
|
107
|
+
className="Sidebar-overlay"
|
|
108
|
+
sx={{
|
|
109
|
+
position: 'fixed',
|
|
110
|
+
zIndex: 9998,
|
|
111
|
+
top: 0,
|
|
112
|
+
left: 0,
|
|
113
|
+
width: '100vw',
|
|
114
|
+
height: '100vh',
|
|
115
|
+
opacity: 'var(--SideNavigation-slideIn)',
|
|
116
|
+
backgroundColor: 'var(--joy-palette-background-backdrop)',
|
|
117
|
+
transition: 'opacity 0.4s',
|
|
118
|
+
transform: {
|
|
119
|
+
xs: 'translateX(calc(100% * (var(--SideNavigation-slideIn, 0) - 1) + var(--SideNavigation-slideIn, 0) * var(--Sidebar-width, 0px)))',
|
|
120
|
+
lg: 'translateX(-100%)',
|
|
121
|
+
},
|
|
122
|
+
}}
|
|
123
|
+
onClick={() => closeSidebar()}
|
|
124
|
+
/>
|
|
125
|
+
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
|
126
|
+
<IconButton variant="soft" color="primary" size="sm">
|
|
127
|
+
<BadgeRoundedIcon />
|
|
128
|
+
</IconButton>
|
|
129
|
+
<Typography level="title-lg">Profiles</Typography>
|
|
130
|
+
<ColorSchemeToggle sx={{ ml: 'auto' }} />
|
|
131
|
+
</Box>
|
|
132
|
+
<Input size="sm" startDecorator={<SearchRoundedIcon />} placeholder="Search" />
|
|
133
|
+
<Box
|
|
134
|
+
sx={{
|
|
135
|
+
minHeight: 0,
|
|
136
|
+
overflow: 'hidden auto',
|
|
137
|
+
flexGrow: 1,
|
|
138
|
+
display: 'flex',
|
|
139
|
+
flexDirection: 'column',
|
|
140
|
+
[`& .${listItemButtonClasses.root}`]: {
|
|
141
|
+
gap: 1.5,
|
|
142
|
+
},
|
|
143
|
+
}}
|
|
144
|
+
>
|
|
145
|
+
<List
|
|
146
|
+
size="sm"
|
|
147
|
+
sx={{
|
|
148
|
+
gap: 1,
|
|
149
|
+
'--List-nestedInsetStart': '30px',
|
|
150
|
+
'--ListItem-radius': (theme) => theme.vars.radius.sm,
|
|
151
|
+
}}
|
|
152
|
+
>
|
|
153
|
+
<ListItem>
|
|
154
|
+
<ListItemButton>
|
|
155
|
+
<HomeRoundedIcon />
|
|
156
|
+
<ListItemContent>
|
|
157
|
+
<Typography level="title-sm">Home</Typography>
|
|
158
|
+
</ListItemContent>
|
|
159
|
+
</ListItemButton>
|
|
160
|
+
</ListItem>
|
|
161
|
+
|
|
162
|
+
<ListItem>
|
|
163
|
+
<ListItemButton>
|
|
164
|
+
<DashboardRoundedIcon />
|
|
165
|
+
<ListItemContent>
|
|
166
|
+
<Typography level="title-sm">Dashboard</Typography>
|
|
167
|
+
</ListItemContent>
|
|
168
|
+
</ListItemButton>
|
|
169
|
+
</ListItem>
|
|
170
|
+
|
|
171
|
+
<ListItem>
|
|
172
|
+
<ListItemButton>
|
|
173
|
+
<CollectionsBookmarkRoundedIcon />
|
|
174
|
+
<ListItemContent>
|
|
175
|
+
<Typography level="title-sm">Projects</Typography>
|
|
176
|
+
</ListItemContent>
|
|
177
|
+
</ListItemButton>
|
|
178
|
+
</ListItem>
|
|
179
|
+
|
|
180
|
+
<ListItem nested>
|
|
181
|
+
<Toggler
|
|
182
|
+
renderToggle={({ open, setOpen }) => (
|
|
183
|
+
<ListItemButton onClick={() => setOpen(!open)}>
|
|
184
|
+
<AssignmentRoundedIcon />
|
|
185
|
+
<ListItemContent>
|
|
186
|
+
<Typography level="title-sm">Tasks</Typography>
|
|
187
|
+
</ListItemContent>
|
|
188
|
+
<KeyboardArrowDownIcon
|
|
189
|
+
sx={{ transform: open ? 'rotate(180deg)' : 'none' }}
|
|
190
|
+
/>
|
|
191
|
+
</ListItemButton>
|
|
192
|
+
)}
|
|
193
|
+
>
|
|
194
|
+
<List sx={{ gap: 0.5 }}>
|
|
195
|
+
<ListItem sx={{ mt: 0.5 }}>
|
|
196
|
+
<ListItemButton>All tasks</ListItemButton>
|
|
197
|
+
</ListItem>
|
|
198
|
+
<ListItem>
|
|
199
|
+
<ListItemButton>Backlog</ListItemButton>
|
|
200
|
+
</ListItem>
|
|
201
|
+
<ListItem>
|
|
202
|
+
<ListItemButton>In progress</ListItemButton>
|
|
203
|
+
</ListItem>
|
|
204
|
+
<ListItem>
|
|
205
|
+
<ListItemButton>Done</ListItemButton>
|
|
206
|
+
</ListItem>
|
|
207
|
+
</List>
|
|
208
|
+
</Toggler>
|
|
209
|
+
</ListItem>
|
|
210
|
+
|
|
211
|
+
<ListItem>
|
|
212
|
+
<ListItemButton selected>
|
|
213
|
+
<QuestionAnswerRoundedIcon />
|
|
214
|
+
<ListItemContent>
|
|
215
|
+
<Typography level="title-sm">Messages</Typography>
|
|
216
|
+
</ListItemContent>
|
|
217
|
+
<Chip size="sm" color="primary" variant="solid">
|
|
218
|
+
4
|
|
219
|
+
</Chip>
|
|
220
|
+
</ListItemButton>
|
|
221
|
+
</ListItem>
|
|
222
|
+
|
|
223
|
+
<ListItem nested>
|
|
224
|
+
<Toggler
|
|
225
|
+
renderToggle={({ open, setOpen }) => (
|
|
226
|
+
<ListItemButton onClick={() => setOpen(!open)}>
|
|
227
|
+
<GroupRoundedIcon />
|
|
228
|
+
<ListItemContent>
|
|
229
|
+
<Typography level="title-sm">Users</Typography>
|
|
230
|
+
</ListItemContent>
|
|
231
|
+
<KeyboardArrowDownIcon
|
|
232
|
+
sx={{ transform: open ? 'rotate(180deg)' : 'none' }}
|
|
233
|
+
/>
|
|
234
|
+
</ListItemButton>
|
|
235
|
+
)}
|
|
236
|
+
>
|
|
237
|
+
<List sx={{ gap: 0.5 }}>
|
|
238
|
+
<ListItem sx={{ mt: 0.5 }}>
|
|
239
|
+
<ListItemButton
|
|
240
|
+
role="menuitem"
|
|
241
|
+
component="a"
|
|
242
|
+
href="/joy-ui/getting-started/templates/profile-dashboard/"
|
|
243
|
+
>
|
|
244
|
+
My profile
|
|
245
|
+
</ListItemButton>
|
|
246
|
+
</ListItem>
|
|
247
|
+
<ListItem>
|
|
248
|
+
<ListItemButton>Create a new user</ListItemButton>
|
|
249
|
+
</ListItem>
|
|
250
|
+
<ListItem>
|
|
251
|
+
<ListItemButton>Roles & permission</ListItemButton>
|
|
252
|
+
</ListItem>
|
|
253
|
+
</List>
|
|
254
|
+
</Toggler>
|
|
255
|
+
</ListItem>
|
|
256
|
+
</List>
|
|
257
|
+
|
|
258
|
+
<List
|
|
259
|
+
size="sm"
|
|
260
|
+
sx={{
|
|
261
|
+
mt: 'auto',
|
|
262
|
+
flexGrow: 0,
|
|
263
|
+
'--ListItem-radius': (theme) => theme.vars.radius.sm,
|
|
264
|
+
'--List-gap': '8px',
|
|
265
|
+
mb: 2,
|
|
266
|
+
}}
|
|
267
|
+
>
|
|
268
|
+
<ListItem>
|
|
269
|
+
<ListItemButton>
|
|
270
|
+
<SupportRoundedIcon />
|
|
271
|
+
Support
|
|
272
|
+
</ListItemButton>
|
|
273
|
+
</ListItem>
|
|
274
|
+
<ListItem>
|
|
275
|
+
<ListItemButton>
|
|
276
|
+
<SettingsRoundedIcon />
|
|
277
|
+
Settings
|
|
278
|
+
</ListItemButton>
|
|
279
|
+
</ListItem>
|
|
280
|
+
</List>
|
|
281
|
+
<Card
|
|
282
|
+
invertedColors
|
|
283
|
+
variant="soft"
|
|
284
|
+
color="warning"
|
|
285
|
+
size="sm"
|
|
286
|
+
sx={{ boxShadow: 'none' }}
|
|
287
|
+
>
|
|
288
|
+
<Stack direction="row" justifyContent="space-between" alignItems="center">
|
|
289
|
+
<Typography level="title-sm">Used space</Typography>
|
|
290
|
+
<IconButton size="sm">
|
|
291
|
+
<CloseRoundedIcon />
|
|
292
|
+
</IconButton>
|
|
293
|
+
</Stack>
|
|
294
|
+
<Typography level="body-xs">
|
|
295
|
+
Your team has used 80% of your available space. Need more?
|
|
296
|
+
</Typography>
|
|
297
|
+
<LinearProgress variant="outlined" value={80} determinate sx={{ my: 1 }} />
|
|
298
|
+
<Button size="sm" variant="solid">
|
|
299
|
+
Upgrade plan
|
|
300
|
+
</Button>
|
|
301
|
+
</Card>
|
|
302
|
+
</Box>
|
|
303
|
+
<Divider />
|
|
304
|
+
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
|
|
305
|
+
<Avatar
|
|
306
|
+
variant="outlined"
|
|
307
|
+
size="sm"
|
|
308
|
+
src="https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?auto=format&fit=crop&w=286"
|
|
309
|
+
/>
|
|
310
|
+
<Box sx={{ minWidth: 0, flex: 1 }}>
|
|
311
|
+
<Typography level="title-sm">Siriwat K.</Typography>
|
|
312
|
+
<Typography level="body-xs">siriwatk@test.com</Typography>
|
|
313
|
+
</Box>
|
|
314
|
+
<IconButton size="sm" variant="plain" color="neutral">
|
|
315
|
+
<LogoutRoundedIcon />
|
|
316
|
+
</IconButton>
|
|
317
|
+
</Box>
|
|
318
|
+
</Sheet>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// In production, we register a service worker to serve assets from local cache.
|
|
2
|
+
|
|
3
|
+
// This lets the app load faster on subsequent visits in production, and gives
|
|
4
|
+
// it offline capabilities. However, it also means that developers (and users)
|
|
5
|
+
// will only see deployed updates on the "N+1" visit to a page, since previously
|
|
6
|
+
// cached resources are updated in the background.
|
|
7
|
+
|
|
8
|
+
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
|
|
9
|
+
// This link also includes instructions on opting out of this behavior.
|
|
10
|
+
|
|
11
|
+
export default function register() {
|
|
12
|
+
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
|
13
|
+
window.addEventListener('load', () => {
|
|
14
|
+
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
|
15
|
+
navigator.serviceWorker
|
|
16
|
+
.register(swUrl)
|
|
17
|
+
.then(registration => {
|
|
18
|
+
// eslint-disable-next-line no-param-reassign
|
|
19
|
+
registration.onupdatefound = () => {
|
|
20
|
+
const installingWorker = registration.installing;
|
|
21
|
+
installingWorker.onstatechange = () => {
|
|
22
|
+
if (installingWorker.state === 'installed') {
|
|
23
|
+
if (navigator.serviceWorker.controller) {
|
|
24
|
+
// At this point, the old content will have been purged and
|
|
25
|
+
// the fresh content will have been added to the cache.
|
|
26
|
+
// It's the perfect time to display a "New content is
|
|
27
|
+
// available; please refresh." message in your web app.
|
|
28
|
+
console.log('New content is available; please refresh.'); // eslint-disable-line no-console
|
|
29
|
+
} else {
|
|
30
|
+
// At this point, everything has been precached.
|
|
31
|
+
// It's the perfect time to display a
|
|
32
|
+
// "Content is cached for offline use." message.
|
|
33
|
+
console.log('Content is cached for offline use.'); // eslint-disable-line no-console
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
})
|
|
39
|
+
.catch(error => {
|
|
40
|
+
console.error('Error during service worker registration:', error);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function unregister() {
|
|
47
|
+
if ('serviceWorker' in navigator) {
|
|
48
|
+
navigator.serviceWorker.ready.then(registration => {
|
|
49
|
+
registration.unregister();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|