Skip to content

Commit eb6f487

Browse files
committed
add actionable Button component
1 parent 0004f1d commit eb6f487

File tree

7 files changed

+124
-14
lines changed

7 files changed

+124
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,88 @@
1+
import { useCallback, useState } from 'react';
12
import cx from 'classnames';
2-
import { Button } from 'decentraland-ui2';
3+
import { Button, Divider, IconButton, Menu, MenuItem } from 'decentraland-ui2';
4+
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
35

4-
import type { Props } from './types';
6+
import type { Props, ActionsProps } from './types';
57

68
import './styles.css';
79

8-
export function ButtonComponent({ children, className = '', onClick, ...props }: Props) {
10+
export function ButtonComponent({
11+
children,
12+
className = '',
13+
onClick,
14+
actions = [],
15+
actionableIcon,
16+
...props
17+
}: Props) {
918
return (
1019
<Button
1120
{...props}
1221
className={cx('Button', className)}
1322
onClick={onClick}
1423
>
1524
{children}
25+
<Actions
26+
actions={actions}
27+
icon={actionableIcon}
28+
/>
1629
</Button>
1730
);
1831
}
32+
33+
function Actions({ actions, icon }: ActionsProps) {
34+
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
35+
const open = Boolean(anchorEl);
36+
37+
const handleOpen = useCallback((event: React.MouseEvent<HTMLElement, MouseEvent>) => {
38+
event.stopPropagation();
39+
setAnchorEl(event.currentTarget);
40+
}, []);
41+
42+
const handleClose = useCallback((event: React.MouseEvent<HTMLElement, MouseEvent>) => {
43+
event.stopPropagation();
44+
setAnchorEl(null);
45+
}, []);
46+
47+
const handleClick = useCallback(
48+
(fn: () => void) => (event: React.MouseEvent<HTMLElement, MouseEvent>) => {
49+
event.stopPropagation();
50+
setAnchorEl(null);
51+
fn();
52+
},
53+
[],
54+
);
55+
56+
if (!actions.length) return null;
57+
58+
return (
59+
<div className="Actions">
60+
<Divider
61+
orientation="vertical"
62+
flexItem
63+
sx={{ mx: 0.5 }}
64+
/>
65+
<IconButton
66+
onClick={handleOpen}
67+
size="large"
68+
>
69+
{icon ?? <ArrowDropDownIcon />}
70+
</IconButton>
71+
<Menu
72+
id="ActionsMenu"
73+
anchorEl={anchorEl}
74+
open={open}
75+
onClose={handleClose}
76+
>
77+
{actions.map(({ label, onClick }, i) => (
78+
<MenuItem
79+
key={i}
80+
onClick={handleClick(onClick)}
81+
>
82+
{label}
83+
</MenuItem>
84+
))}
85+
</Menu>
86+
</div>
87+
);
88+
}

packages/renderer/src/components/Button/styles.css

+17
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
background-color: var(--dcl-dark);
2525
}
2626

27+
.Button.MuiButton-colorPrimary:hover:has(.Actions:hover) {
28+
background-color: var(--dcl);
29+
}
30+
2731
/* Color secondary */
2832
.Button.MuiButton-colorSecondary {
2933
background-color: var(--dark-gray);
@@ -49,3 +53,16 @@
4953
.Button.MuiButton-outlined {
5054
background-color: transparent;
5155
}
56+
57+
.Button.MuiButton-root .Actions {
58+
display: flex;
59+
margin: 5px;
60+
}
61+
62+
.Button.MuiButton-root:has(.Actions) {
63+
padding: 0 0 0 20px;
64+
}
65+
66+
.Button.MuiButton-root .MuiIconButton-root {
67+
padding: 0;
68+
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
import type { ReactNode } from 'react';
12
import type { ButtonOwnProps } from 'decentraland-ui2';
23

4+
type Action = { label: string; onClick: () => void };
5+
36
export type Props = ButtonOwnProps & {
47
className?: string;
58
onClick?: React.MouseEventHandler<HTMLButtonElement>;
9+
actions?: Action[];
10+
actionableIcon?: ReactNode;
11+
};
12+
13+
export type ActionsProps = {
14+
actions: Action[];
15+
icon?: ReactNode;
616
};

packages/renderer/src/components/EditorPage/component.tsx

+18-8
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { Row } from '../Row';
2323

2424
import './styles.css';
2525

26-
type ModalType = 'publish';
26+
type ModalType = 'publish' | 'publish_history';
2727

2828
export function EditorPage() {
2929
const navigate = useNavigate();
@@ -74,15 +74,19 @@ export function EditorPage() {
7474

7575
const handleOpenModal = useCallback(
7676
(type: ModalType) => () => {
77-
const rpc = iframeRef.current;
78-
if (rpc) {
79-
saveAndGetThumbnail(rpc);
80-
setOpen(type);
81-
}
77+
setOpen(type);
8278
},
83-
[iframeRef.current],
79+
[],
8480
);
8581

82+
const handleOpenPublish = useCallback(() => {
83+
const rpc = iframeRef.current;
84+
if (rpc) {
85+
saveAndGetThumbnail(rpc);
86+
setOpen('publish');
87+
}
88+
}, [iframeRef.current]);
89+
8690
const handleCloseModal = useCallback(() => {
8791
setOpen(undefined);
8892
}, []);
@@ -174,8 +178,14 @@ export function EditorPage() {
174178
<Button
175179
color="primary"
176180
disabled={loadingPublish}
177-
onClick={handleOpenModal('publish')}
181+
onClick={handleOpenPublish}
178182
startIcon={loadingPublish ? <Loader size={20} /> : <PublicIcon />}
183+
actions={[
184+
{
185+
label: t('editor.header.actions.publish_history'),
186+
onClick: handleOpenModal('publish_history'),
187+
},
188+
]}
179189
>
180190
{t('editor.header.actions.publish')}
181191
</Button>

packages/renderer/src/modules/store/translation/locales/en.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"actions": {
3838
"code": "Code",
3939
"preview": "Preview",
40-
"publish": "Publish"
40+
"publish": "Publish",
41+
"publish_history": "Publishing History"
4142
}
4243
}
4344
},

packages/renderer/src/modules/store/translation/locales/es.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"actions": {
3838
"code": "Código",
3939
"preview": "Previsualizar",
40-
"publish": "Publicar"
40+
"publish": "Publicar",
41+
"publish_history": "Historial de Publicaciones"
4142
}
4243
}
4344
},

packages/renderer/src/modules/store/translation/locales/zh.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"actions": {
3838
"code": "代码",
3939
"preview": "预览",
40-
"publish": "发布"
40+
"publish": "发布",
41+
"publish_history": "出版历史"
4142
}
4243
}
4344
},

0 commit comments

Comments
 (0)