Web App: Fix button styles (#2478)
This commit is contained in:
parent
172f03f474
commit
573583ce67
138
src/components/main/WebAppModal.module.scss
Normal file
138
src/components/main/WebAppModal.module.scss
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
.root {
|
||||||
|
:global {
|
||||||
|
.modal-header {
|
||||||
|
border-bottom: 1px solid var(--color-dividers);
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
height: 75%;
|
||||||
|
justify-content: center;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
border-bottom-right-radius: var(--border-radius-default);
|
||||||
|
border-bottom-left-radius: var(--border-radius-default);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.modal-dialog {
|
||||||
|
background-color: var(--color-background);
|
||||||
|
border-radius: 0;
|
||||||
|
height: 100%;
|
||||||
|
max-width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
max-height: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-icon {
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(-45deg);
|
||||||
|
|
||||||
|
&,
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
width: 1.125rem;
|
||||||
|
height: 0.125rem;
|
||||||
|
border-radius: 0.125rem;
|
||||||
|
background-color: var(--color-text-secondary);
|
||||||
|
transition: transform var(--slide-transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.state-back {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
transform: rotate(45deg) scaleX(0.75) translate(0, -0.375rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
transform: rotate(-45deg) scaleX(0.75) translate(0, 0.375rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.frame {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&.with-button {
|
||||||
|
height: calc(100% - 3.5rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
transform: translateY(100%);
|
||||||
|
transition: 0.25s ease-in-out transform;
|
||||||
|
|
||||||
|
&.visible {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-button-spinner {
|
||||||
|
position: absolute;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.web-app-popup {
|
||||||
|
:global(.modal-dialog) {
|
||||||
|
max-width: min(30rem, 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.without-title :global(.modal-content) {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.modal-content) {
|
||||||
|
padding-left: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,122 +0,0 @@
|
|||||||
.WebAppModal {
|
|
||||||
.modal-header {
|
|
||||||
border-bottom: 1px solid var(--color-dividers);
|
|
||||||
padding: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-dialog {
|
|
||||||
height: 75%;
|
|
||||||
justify-content: center;
|
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
margin: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
border-bottom-right-radius: var(--border-radius-default);
|
|
||||||
border-bottom-left-radius: var(--border-radius-default);
|
|
||||||
}
|
|
||||||
|
|
||||||
.web-app-frame {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 0;
|
|
||||||
|
|
||||||
&.with-button {
|
|
||||||
height: calc(100% - 56px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.web-app-button {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
border-radius: 0;
|
|
||||||
transform: translateY(100%);
|
|
||||||
transition: 0.25s ease-in-out transform;
|
|
||||||
|
|
||||||
&.visible {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.Spinner {
|
|
||||||
position: absolute;
|
|
||||||
right: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.modal-dialog {
|
|
||||||
background-color: var(--color-background);
|
|
||||||
border-radius: 0;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
max-height: none;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animated-close-icon {
|
|
||||||
position: absolute;
|
|
||||||
transform: rotate(-45deg);
|
|
||||||
|
|
||||||
&,
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
width: 1.125rem;
|
|
||||||
height: 0.125rem;
|
|
||||||
border-radius: 0.125rem;
|
|
||||||
background-color: var(--color-text-secondary);
|
|
||||||
transition: transform var(--slide-transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before,
|
|
||||||
&::after {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.state-back {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
transform: rotate(45deg) scaleX(0.75) translate(0, -0.375rem);
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
transform: rotate(-45deg) scaleX(0.75) translate(0, 0.375rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.web-app-popup {
|
|
||||||
.modal-dialog {
|
|
||||||
max-width: min(30rem, 100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.without-title .modal-content {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
padding-left: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -31,7 +31,7 @@ import MenuItem from '../ui/MenuItem';
|
|||||||
import Spinner from '../ui/Spinner';
|
import Spinner from '../ui/Spinner';
|
||||||
import ConfirmDialog from '../ui/ConfirmDialog';
|
import ConfirmDialog from '../ui/ConfirmDialog';
|
||||||
|
|
||||||
import './WebAppModal.scss';
|
import styles from './WebAppModal.module.scss';
|
||||||
|
|
||||||
type WebAppButton = {
|
type WebAppButton = {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
@ -101,6 +101,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
const [headerColor, setHeaderColor] = useState(extractCurrentThemeParams().bg_color);
|
const [headerColor, setHeaderColor] = useState(extractCurrentThemeParams().bg_color);
|
||||||
const [confirmClose, setConfirmClose] = useState(false);
|
const [confirmClose, setConfirmClose] = useState(false);
|
||||||
const [isCloseModalOpen, openCloseModal, closeCloseModal] = useFlag(false);
|
const [isCloseModalOpen, openCloseModal, closeCloseModal] = useFlag(false);
|
||||||
|
const [isLoaded, markLoaded, markUnloaded] = useFlag(false);
|
||||||
const [popupParams, setPopupParams] = useState<PopupOptions | undefined>();
|
const [popupParams, setPopupParams] = useState<PopupOptions | undefined>();
|
||||||
const { isMobile } = useAppLayout();
|
const { isMobile } = useAppLayout();
|
||||||
const prevPopupParams = usePrevious(popupParams);
|
const prevPopupParams = usePrevious(popupParams);
|
||||||
@ -204,7 +205,7 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
reloadFrame, sendEvent, sendViewport, sendTheme,
|
reloadFrame, sendEvent, sendViewport, sendTheme,
|
||||||
} = useWebAppFrame(frameRef, isOpen, isSimple, handleEvent);
|
} = useWebAppFrame(frameRef, isOpen, isSimple, handleEvent, markLoaded);
|
||||||
|
|
||||||
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
|
const shouldShowMainButton = mainButton?.isVisible && mainButton.text.trim().length > 0;
|
||||||
|
|
||||||
@ -315,8 +316,9 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
setConfirmClose(false);
|
setConfirmClose(false);
|
||||||
closeCloseModal();
|
closeCloseModal();
|
||||||
setPopupParams(undefined);
|
setPopupParams(undefined);
|
||||||
|
markUnloaded();
|
||||||
}
|
}
|
||||||
}, [closeCloseModal, isOpen]);
|
}, [closeCloseModal, isOpen, markUnloaded]);
|
||||||
|
|
||||||
const MoreMenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {
|
const MoreMenuButton: FC<{ onTrigger: () => void; isOpen?: boolean }> = useMemo(() => {
|
||||||
return ({ onTrigger, isOpen: isMenuOpen }) => (
|
return ({ onTrigger, isOpen: isMenuOpen }) => (
|
||||||
@ -335,8 +337,8 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
}, [isMobile]);
|
}, [isMobile]);
|
||||||
|
|
||||||
const backButtonClassName = buildClassName(
|
const backButtonClassName = buildClassName(
|
||||||
'animated-close-icon',
|
styles.closeIcon,
|
||||||
isBackButtonVisible && 'state-back',
|
isBackButtonVisible && styles.stateBack,
|
||||||
);
|
);
|
||||||
|
|
||||||
const header = useMemo(() => {
|
const header = useMemo(() => {
|
||||||
@ -361,6 +363,11 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
<MenuItem icon="bots" onClick={openBotChat}>{lang('BotWebViewOpenBot')}</MenuItem>
|
<MenuItem icon="bots" onClick={openBotChat}>{lang('BotWebViewOpenBot')}</MenuItem>
|
||||||
)}
|
)}
|
||||||
<MenuItem icon="reload" onClick={handleRefreshClick}>{lang('WebApp.ReloadPage')}</MenuItem>
|
<MenuItem icon="reload" onClick={handleRefreshClick}>{lang('WebApp.ReloadPage')}</MenuItem>
|
||||||
|
{attachBot?.hasSettings && (
|
||||||
|
<MenuItem icon="settings" onClick={handleSettingsButtonClick}>
|
||||||
|
{lang('Settings')}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
{bot?.isAttachBot && (
|
{bot?.isAttachBot && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={attachBot ? 'stop' : 'install'}
|
icon={attachBot ? 'stop' : 'install'}
|
||||||
@ -370,11 +377,6 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
{lang(attachBot ? 'WebApp.RemoveBot' : 'WebApp.AddToAttachmentAdd')}
|
{lang(attachBot ? 'WebApp.RemoveBot' : 'WebApp.AddToAttachmentAdd')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
)}
|
)}
|
||||||
{attachBot?.hasSettings && (
|
|
||||||
<MenuItem icon="settings" onClick={handleSettingsButtonClick}>
|
|
||||||
{lang('Settings')}
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -425,17 +427,18 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="WebAppModal"
|
className={styles.root}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
header={header}
|
header={header}
|
||||||
hasCloseButton
|
hasCloseButton
|
||||||
style={`background-color: ${backgroundColor}`}
|
style={`background-color: ${backgroundColor}`}
|
||||||
>
|
>
|
||||||
|
<Spinner className={buildClassName(styles.loadingSpinner, isLoaded && styles.hide)} />
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<>
|
<>
|
||||||
<iframe
|
<iframe
|
||||||
className={buildClassName('web-app-frame', shouldDecreaseWebFrameSize && 'with-button')}
|
className={buildClassName(styles.frame, shouldDecreaseWebFrameSize && styles.withButton)}
|
||||||
src={url}
|
src={url}
|
||||||
title={`${bot?.firstName} Web App`}
|
title={`${bot?.firstName} Web App`}
|
||||||
sandbox={SANDBOX_ATTRIBUTES}
|
sandbox={SANDBOX_ATTRIBUTES}
|
||||||
@ -445,16 +448,16 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className={buildClassName(
|
className={buildClassName(
|
||||||
'web-app-button',
|
styles.mainButton,
|
||||||
shouldShowMainButton && 'visible',
|
shouldShowMainButton && styles.visible,
|
||||||
shouldHideButton && 'hidden',
|
shouldHideButton && styles.hidden,
|
||||||
)}
|
)}
|
||||||
style={`background-color: ${mainButtonCurrentColor}; color: ${mainButtonCurrentTextColor}`}
|
style={`background-color: ${mainButtonCurrentColor}; color: ${mainButtonCurrentTextColor}`}
|
||||||
disabled={!mainButtonCurrentIsActive}
|
disabled={!mainButtonCurrentIsActive}
|
||||||
onClick={handleMainButtonClick}
|
onClick={handleMainButtonClick}
|
||||||
>
|
>
|
||||||
{mainButtonCurrentText}
|
{mainButtonCurrentText}
|
||||||
{mainButton?.isProgressVisible && <Spinner color="white" />}
|
{mainButton?.isProgressVisible && <Spinner className={styles.mainButtonSpinner} color="white" />}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -475,16 +478,18 @@ const WebAppModal: FC<OwnProps & StateProps> = ({
|
|||||||
title={renderingPopupParams.title || NBSP}
|
title={renderingPopupParams.title || NBSP}
|
||||||
onClose={handlePopupModalClose}
|
onClose={handlePopupModalClose}
|
||||||
hasCloseButton
|
hasCloseButton
|
||||||
className={buildClassName('web-app-popup', !renderingPopupParams.title?.trim().length && 'without-title')}
|
className={
|
||||||
|
buildClassName(styles.webAppPopup, !renderingPopupParams.title?.trim().length && styles.withoutTitle)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{renderingPopupParams.message}
|
{renderingPopupParams.message}
|
||||||
<div className="dialog-buttons mt-2">
|
<div className="dialog-buttons mt-2">
|
||||||
{renderingPopupParams.buttons.map((button) => (
|
{renderingPopupParams.buttons.map((button) => (
|
||||||
<Button
|
<Button
|
||||||
key={button.id || button.text || button.type}
|
key={button.id || button.type}
|
||||||
|
className="confirm-dialog-button"
|
||||||
color={button.type === 'destructive' ? 'danger' : 'primary'}
|
color={button.type === 'destructive' ? 'danger' : 'primary'}
|
||||||
isText
|
isText
|
||||||
fluid
|
|
||||||
size="smaller"
|
size="smaller"
|
||||||
// eslint-disable-next-line react/jsx-no-bind
|
// eslint-disable-next-line react/jsx-no-bind
|
||||||
onClick={() => handlePopupClose(button.id)}
|
onClick={() => handlePopupClose(button.id)}
|
||||||
|
|||||||
@ -169,11 +169,26 @@ const useWebAppFrame = (
|
|||||||
isOpen: boolean,
|
isOpen: boolean,
|
||||||
isSimpleView: boolean,
|
isSimpleView: boolean,
|
||||||
onEvent: (event: WebAppInboundEvent) => void,
|
onEvent: (event: WebAppInboundEvent) => void,
|
||||||
|
onLoad?: () => void,
|
||||||
) => {
|
) => {
|
||||||
const ignoreEventsRef = useRef<boolean>(false);
|
const ignoreEventsRef = useRef<boolean>(false);
|
||||||
const lastFrameSizeRef = useRef<{ width: number; height: number; isResizing?: boolean }>();
|
const lastFrameSizeRef = useRef<{ width: number; height: number; isResizing?: boolean }>();
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!ref.current || !isOpen) return undefined;
|
||||||
|
|
||||||
|
const handleLoad = () => {
|
||||||
|
onLoad?.();
|
||||||
|
};
|
||||||
|
|
||||||
|
const frame = ref.current;
|
||||||
|
frame.addEventListener('load', handleLoad);
|
||||||
|
return () => {
|
||||||
|
frame.removeEventListener('load', handleLoad);
|
||||||
|
};
|
||||||
|
}, [onLoad, ref, isOpen]);
|
||||||
|
|
||||||
const reloadFrame = useCallback((url: string) => {
|
const reloadFrame = useCallback((url: string) => {
|
||||||
if (!ref.current) return;
|
if (!ref.current) return;
|
||||||
const frame = ref.current;
|
const frame = ref.current;
|
||||||
@ -228,6 +243,10 @@ const useWebAppFrame = (
|
|||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data) as WebAppInboundEvent;
|
const data = JSON.parse(event.data) as WebAppInboundEvent;
|
||||||
// Handle some app requests here to simplify hook usage
|
// Handle some app requests here to simplify hook usage
|
||||||
|
if (data.eventType === 'web_app_ready') {
|
||||||
|
onLoad?.();
|
||||||
|
}
|
||||||
|
|
||||||
if (data.eventType === 'web_app_request_viewport') {
|
if (data.eventType === 'web_app_request_viewport') {
|
||||||
sendViewport(windowSize.isResizing);
|
sendViewport(windowSize.isResizing);
|
||||||
}
|
}
|
||||||
@ -263,7 +282,7 @@ const useWebAppFrame = (
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Ignore other messages
|
// Ignore other messages
|
||||||
}
|
}
|
||||||
}, [isSimpleView, onEvent, sendCustomStyle, sendEvent, sendTheme, sendViewport, windowSize.isResizing]);
|
}, [isSimpleView, onEvent, sendCustomStyle, sendEvent, sendTheme, sendViewport, onLoad, windowSize.isResizing]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { width, height, isResizing } = windowSize;
|
const { width, height, isResizing } = windowSize;
|
||||||
|
|||||||
@ -185,7 +185,7 @@ const Button: FC<OwnProps> = ({
|
|||||||
title={ariaLabel}
|
title={ariaLabel}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
dir={isRtl ? 'rtl' : undefined}
|
dir={isRtl ? 'rtl' : undefined}
|
||||||
style={buildStyle(backgroundImage && `background-image: url(${backgroundImage})`)}
|
style={buildStyle(style, backgroundImage && `background-image: url(${backgroundImage})`)}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -174,7 +174,7 @@
|
|||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
.confirm-dialog-button + .confirm-dialog-button {
|
.confirm-dialog-button + .confirm-dialog-button {
|
||||||
margin-left: 1rem;
|
margin-right: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const Spinner: FC<{
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={buildClassName(
|
<div className={buildClassName(
|
||||||
'Spinner', className, color, backgroundColor && 'with-background', `bg-${backgroundColor}`,
|
'Spinner', className, color, backgroundColor && 'with-background', backgroundColor && `bg-${backgroundColor}`,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div />
|
<div />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user