Merge pull request #463 from ONLYOFFICE/feature/mobile-main-button

Feature/mobile main button
This commit is contained in:
Alexey Safronov 2022-01-20 14:58:55 +03:00 committed by GitHub
commit 4d6b9fe898
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 724 additions and 4 deletions

View File

@ -17,12 +17,14 @@ import ButtonMoveIcon from "../../../../public/images/button.move.react.svg";
import ButtonDuplicateIcon from "../../../../public/images/button.duplicate.react.svg";
import ButtonAlertIcon from "../../../../public/images/button.alert.react.svg";
import commonIconsStyles from "@appserver/components/utils/common-icons-style";
import ButtonPlusIcon from "../../../../public/images/actions.button.plus.react.svg";
import ButtonMinusIcon from "../../../../public/images/actions.button.minus.react.svg";
const StyledButtonAlertIcon = styled(ButtonAlertIcon)`
${commonIconsStyles}
`;
const FloatingButton = ({ id, className, style, ...rest }) => {
const { icon, alert, percent, onClick } = rest;
const { icon, alert, percent, onClick, color } = rest;
return (
<StyledCircleWrap
@ -40,7 +42,7 @@ const FloatingButton = ({ id, className, style, ...rest }) => {
<div className="circle__fill"></div>
</div>
<StyledFloatingButton>
<StyledFloatingButton color={color}>
<IconBox>
{icon == "upload" ? (
<ButtonUploadIcon />
@ -50,6 +52,10 @@ const FloatingButton = ({ id, className, style, ...rest }) => {
<ButtonTrashIcon />
) : icon == "move" ? (
<ButtonMoveIcon />
) : icon == "plus" ? (
<ButtonPlusIcon />
) : icon == "minus" ? (
<ButtonMinusIcon />
) : (
<ButtonDuplicateIcon />
)}
@ -67,10 +73,19 @@ FloatingButton.propTypes = {
id: PropTypes.string,
className: PropTypes.string,
style: PropTypes.object,
icon: PropTypes.oneOf(["upload", "file", "trash", "move", "duplicate"]),
icon: PropTypes.oneOf([
"upload",
"file",
"trash",
"move",
"duplicate",
"plus",
"minus",
]),
alert: PropTypes.bool,
percent: PropTypes.number,
onClick: PropTypes.func,
color: PropTypes.string,
};
FloatingButton.defaultProps = {

View File

@ -72,7 +72,7 @@ const StyledFloatingButton = styled.div`
width: 48px;
height: 48px;
border-radius: 50%;
background: #fff;
background: ${(props) => (props.color ? props.color : "#fff")};
box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.13);
text-align: center;
margin: 3px;

View File

@ -0,0 +1,74 @@
# MainButtonMobile
### Usage
```js
import MainButtonMobile from "@appserver/components/main-button-mobile";
```
```jsx
const actionOptions = [
{
key: "1",
label: "New document",
icon: "static/images/mobile.actions.document.react.svg",
},
{
key: "2",
label: "New presentation",
icon: "static/images/mobile.actions.presentation.react.svg",
},
];
const buttonOptions = [
{
key: "1",
label: "Import point",
},
{
key: "2",
label: "Import point",
},
];
const progressOptions = [
{
key: "1",
label: "Uploads",
percent: 30,
status: `8/10`,
open: true,
},
];
<MainButtonMobile
style={{
top: "90%",
left: "82%",
position: "fixed",
}}
manualWidth="320px"
title="Upload"
withButton={true}
actionOptions={actionOptions}
progressOptions={progressOptions}
isOpenButton={true}
buttonOptions={buttonOptions}
/>;
```
| Props | Type | Required | Values | Default | Description |
| ----------------- | :------------: | :------: | :----: | :-----: | -------------------------------------------------------------------------------------------------- |
| `style` | `obj`, `array` | - | - | - | Accepts css style |
| `actionOptions` | `obj` | - | - | - | Options for drop down items |
| `progressOptions` | `obj` | - | - | - | If you need display progress bar components |
| `buttonOptions` | `obj` | - | - | - | Menu that opens by clicking on the button |
| `onUploadClick` | `func` | - | - | - | The function that will be called after the button click |
| `withButton` | `bool` | - | - | - | Show button inside drop down |
| `isOpenButton` | `bool` | - | - | - | The parameter that is used with buttonOptions is needed to open the menu by clicking on the button |
| `title` | `string` | - | | - | The name of the button in the drop down |
| `percent` | `number` | - | - | - | Loading indicator |
| `manualWidth` | `string` | - | - | - | Required if you need to specify the exact width of the drop down component |
| `opened` | `bool` | - | - | - | Tells when the dropdown should be opened |
| `className` | `string` | - | - | - | Accepts class |
| `onClose` | `func` | - | - | - | if you need close drop down |

View File

@ -0,0 +1,255 @@
import React, { useState, useRef, useEffect } from "react";
import PropTypes from "prop-types";
import {
StyledFloatingButton,
StyledDropDown,
StyledDropDownItem,
StyledContainerAction,
StyledProgressBarContainer,
StyledMobileProgressBar,
StyledProgressContainer,
StyledBar,
StyledButtonWrapper,
StyledButtonOptions,
} from "./styled-main-button";
import IconButton from "../icon-button";
import Button from "../button";
import Text from "../text";
import Scrollbar from "@appserver/components/scrollbar";
import { isMobile, isTablet } from "react-device-detect";
const ProgressBarMobile = ({
label,
status,
percent,
open,
onCancel,
icon,
onClick,
error,
}) => {
const uploadPercent = percent > 100 ? 100 : percent;
return (
<StyledProgressBarContainer isUploading={open}>
<Text onClick={onClick} className="progress-header" color="#657077">
{label}
</Text>
<Text className="progress_count" color="#657077">
{status}
</Text>
<IconButton onClick={onCancel} iconName={icon} size={14} />
<StyledMobileProgressBar>
<StyledBar uploadPercent={uploadPercent} error={error} />
</StyledMobileProgressBar>
</StyledProgressBarContainer>
);
};
ProgressBarMobile.propTypes = {
label: PropTypes.string,
status: PropTypes.string,
percent: PropTypes.number,
open: PropTypes.bool,
onCancel: PropTypes.func,
icon: PropTypes.string,
/** The function that will be called after the progress header click */
onClick: PropTypes.func,
/** If true the progress bar changes color */
error: PropTypes.bool,
};
const MainButtonMobile = (props) => {
const {
className,
style,
opened,
onUploadClick,
actionOptions,
progressOptions,
buttonOptions,
percent,
title,
withButton,
manualWidth,
isOpenButton,
onClose,
} = props;
const [isOpen, setIsOpen] = useState(opened);
const [height, setHeight] = useState("90vh");
const divRef = useRef();
useEffect(() => {
if (opened !== isOpen) {
setIsOpen(opened);
}
}, [opened]);
useEffect(() => {
let height = divRef.current.getBoundingClientRect().height;
height >= window.innerHeight ? setHeight("90vh") : setHeight(height + "px");
}, [isOpen, window.innerHeight]);
const ref = useRef();
const dropDownRef = useRef();
const toggle = (isOpen) => {
if (isOpen && onClose) {
onClose();
}
return setIsOpen(isOpen);
};
const onMainButtonClick = (e) => {
if (isOpen && ref.current.contains(e.target)) return;
toggle(!isOpen);
};
const outsideClick = (e) => {
if (isOpen && ref.current.contains(e.target)) return;
toggle(false);
};
const isUploading = progressOptions
? progressOptions.filter((option) => option.open)
: [];
const renderItems = () => {
return (
<div ref={divRef}>
<StyledContainerAction>
{actionOptions.map((option) => (
<StyledDropDownItem
key={option.key}
label={option.label}
className={option.className}
onClick={option.onClick}
icon={option.icon ? option.icon : ""}
/>
))}
</StyledContainerAction>
<StyledProgressContainer
isUploading={isUploading.length > 0 ? true : false}
isOpenButton={isOpenButton}
>
{progressOptions &&
progressOptions.map((option) => (
<ProgressBarMobile
key={option.key}
label={option.label}
icon={option.icon}
className={option.className}
percent={option.percent}
status={option.status}
open={option.open}
onCancel={option.onCancel}
error={option.error}
/>
))}
</StyledProgressContainer>
<StyledButtonOptions isOpenButton={isOpenButton}>
{isOpenButton && buttonOptions
? buttonOptions.map((option) =>
option.isSeparator ? (
<div key={option.key} className="separator-wrapper">
<div className="is-separator" />
</div>
) : (
<StyledDropDownItem
className={`drop-down-item-button ${
option.isSeparator ? "is-separator" : ""
}`}
key={option.key}
label={option.label}
onClick={option.onClick}
icon={option.icon ? option.icon : ""}
/>
)
)
: ""}
</StyledButtonOptions>
{withButton && (
<StyledButtonWrapper
isUploading={isUploading.length > 0 ? true : false}
isOpenButton={isOpenButton}
>
<Button
label={title}
className="action-mobile-button"
primary
size="large"
onClick={onUploadClick}
/>
</StyledButtonWrapper>
)}
</div>
);
};
const children = renderItems();
return (
<div ref={ref} className={className} style={style}>
<StyledFloatingButton
icon={isOpen ? "minus" : "plus"}
onClick={onMainButtonClick}
percent={percent}
color={"#ed7309"}
/>
<StyledDropDown
open={isOpen}
clickOutsideAction={outsideClick}
manualWidth={manualWidth || "400px"}
directionY="top"
directionX="right"
isMobile={isMobile || isTablet}
heightProp={height}
>
{isMobile || isTablet ? (
<Scrollbar
scrollclass="section-scroll"
stype="mediumBlack"
ref={dropDownRef}
>
{children}
</Scrollbar>
) : (
children
)}
</StyledDropDown>
</div>
);
};
MainButtonMobile.propTypes = {
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Options for drop down items */
actionOptions: PropTypes.array.isRequired,
/** If you need display progress bar components */
progressOptions: PropTypes.array,
/** Menu that opens by clicking on the button */
buttonOptions: PropTypes.array,
/** The function that will be called after the button click */
onUploadClick: PropTypes.func,
/** Show button inside drop down */
withButton: PropTypes.bool,
/** The parameter that is used with buttonOptions is needed to open the menu by clicking on the button */
isOpenButton: PropTypes.bool,
/** The name of the button in the drop down */
title: PropTypes.string,
/** Loading indicator */
percent: PropTypes.number,
/** Required if you need to specify the exact width of the drop down component */
manualWidth: PropTypes.string,
className: PropTypes.string,
/** Tells when the dropdown should be opened */
opened: PropTypes.bool,
/** If you need close drop down */
onClose: PropTypes.func,
};
export default MainButtonMobile;

View File

@ -0,0 +1,175 @@
import React from "react";
import MainButtonMobile from ".";
import { useEffect, useReducer, useState } from "react";
export default {
title: "Components/MainButtonMobile",
component: MainButtonMobile,
parameters: {
docs: { description: { component: "Components/MainButtonMobile" } },
},
};
const Template = ({ ...args }) => {
const maxUploads = 10;
const maxOperations = 7;
const [isOpenUploads, setIsOpenUploads] = useState(false);
const [isOpenOperations, setIsOpenOperations] = useState(false);
const [isOpenButton, setIsOpenButton] = useState(false);
const [opened, setOpened] = useState(null);
const [isUploading, setIsUploading] = useState(false);
const [initialState, setInitialState] = useState({
uploads: 0,
operations: 0,
});
const onUploadClick = () => {
setInitialState({ uploads: 0, operations: 0 });
setIsUploading(true);
setIsOpenUploads(true);
setIsOpenOperations(true);
setIsOpenButton(true);
// setOpened(false);
};
function reducer(state, action) {
switch (action.type) {
case "start":
if (
state.uploads === maxUploads &&
state.operations === maxOperations
) {
setIsUploading(false);
return {
...state,
uploads: state.uploads,
operations: state.operations,
};
}
return {
...state,
uploads:
state.uploads !== maxUploads ? state.uploads + 1 : state.uploads,
operations:
state.operations !== maxOperations
? state.operations + 1
: state.operations,
};
default:
return state;
}
}
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
setOpened(null);
if (isUploading) {
const id = setInterval(() => {
dispatch({ type: "start" });
}, 1000);
return () => clearInterval(id);
}
}, [dispatch, isUploading]);
const uploadPercent = (state.uploads / maxUploads) * 100;
const operationPercent = (state.operations / maxOperations) * 100;
const actionOptions = [
{
key: "1",
label: "New document",
icon: "static/images/mobile.actions.document.react.svg",
},
{
key: "2",
label: "New presentation",
icon: "static/images/mobile.actions.presentation.react.svg",
},
{
key: "3",
label: "New spreadsheet",
icon: "static/images/mobile.actions.spreadsheet.react.svg",
},
{
key: "4",
label: "New folder",
icon: "static/images/mobile.actions.folder.react.svg",
},
];
const progressOptions = [
{
key: "1",
label: "Uploads",
icon: "/static/images/mobile.actions.remove.react.svg",
percent: uploadPercent,
status: `${state.uploads}/${maxUploads}`,
open: isOpenUploads,
onCancel: () => setIsOpenUploads(false),
},
{
key: "2",
label: "Other operations",
icon: "/static/images/mobile.actions.remove.react.svg",
percent: operationPercent,
status: `3 files not loaded`,
open: isOpenOperations,
onCancel: () => setIsOpenOperations(false),
error: true,
},
];
const buttonOptions = [
{
key: "1",
label: "Import point",
icon: "static/images/mobile.star.react.svg",
onClick: () => setIsOpenButton(false),
},
{
key: "2",
label: "Import point",
icon: "static/images/mobile.star.react.svg",
onClick: () => setIsOpenButton(false),
},
{
key: "3",
label: "Import point",
isSeparator: true,
},
{
key: "4",
label: "Import point",
icon: "static/images/mobile.star.react.svg",
onClick: () => setIsOpenButton(false),
},
];
return (
<MainButtonMobile
{...args}
style={{ position: "absolute", top: "87%", left: "87%" }}
actionOptions={actionOptions}
progressOptions={progressOptions}
buttonOptions={buttonOptions}
onUploadClick={onUploadClick}
withButton={true}
isOpenButton={isOpenButton}
title="Upload"
percent={uploadPercent}
opened={opened}
/>
);
};
export const Default = Template.bind({});
Default.args = {
title: "Upload",
percent: 0,
opened: null,
};

View File

@ -0,0 +1,161 @@
import styled, { css } from "styled-components";
import Base from "../themes/base";
import DropDown from "../drop-down";
import DropDownItem from "../drop-down-item";
import FloatingButton from "@appserver/common/components/FloatingButton";
const StyledFloatingButton = styled(FloatingButton)`
.circle__mask + div {
svg {
margin-top: 4px;
}
}
${(props) =>
props.percent === 0 &&
css`
.circle__mask {
clip: none;
}
.circle__fill {
animation: none;
transform: none;
background: none !important;
}
`}
.circle__mask,
.circle__mask + div {
z-index: 250;
}
.circle__mask .circle__fill {
background-color: #fff;
}
`;
const StyledDropDown = styled(DropDown)`
bottom: ${(props) => props.theme.mainButtonMobile.dropDown.bottom};
right: ${(props) => props.theme.mainButtonMobile.dropDown.right};
z-index: ${(props) => props.theme.mainButtonMobile.dropDown.zIndex};
height: ${(props) => (props.isMobile ? props.heightProp : "auto")};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding: 0px;
.section-scroll {
padding-right: 0px !important;
}
.separator-wrapper {
padding: 23px;
}
.is-separator {
height: 1px;
width: 100%;
background-color: #fff;
}
.drop-down-item-button {
color: #fff;
svg {
path {
fill: #fff;
}
}
&:hover {
background-color: #3a6c9e;
}
}
.action-mobile-button {
width: 100%;
background-color: #265a8f;
border-radius: 3px;
font-size: 13px;
display: block;
}
`;
const StyledButtonOptions = styled.div`
padding: ${(props) => (props.isOpenButton ? "23px 0px" : "0px")};
background-color: #265a8f;
color: #fff;
`;
const StyledContainerAction = styled.div`
padding: 22px 0px 13px;
`;
const StyledProgressContainer = styled.div`
background-color: ${(props) => (props.isUploading ? "#ECEEF1" : "#fff")};
cursor: default;
padding: ${(props) => (props.isUploading ? "16px 23px 7px;" : "0px")};
`;
const StyledButtonWrapper = styled.div`
padding: ${(props) => (props.isOpenButton ? "0px" : "16px 23px 34px")};
display: ${(props) => (props.isOpenButton ? "none" : "block")};
background-color: ${(props) => (props.isUploading ? "#ECEEF1" : "#fff")};
`;
const StyledProgressBarContainer = styled.div`
display: ${(props) => (props.isUploading ? "flex" : "none")};
flex-wrap: wrap;
width: 100%;
padding-bottom: 24px;
.progress-header {
width: 50%;
&:hover {
cursor: pointer;
}
}
.progress_count {
width: 42%;
text-align: right;
margin-right: 6px;
}
`;
const StyledMobileProgressBar = styled.div`
width: 100%;
background-color: rgb(48%, 58%, 69%, 0.4);
border-radius: 2px;
margin-top: 16px;
`;
const StyledBar = styled.div`
width: ${(props) => props.uploadPercent}%;
height: 4px;
opacity: 1;
background: ${(props) =>
props.error
? "#C96C27"
: "linear-gradient(225deg, #2274aa 0%, #0f4071 100%)"}; ;
`;
StyledDropDown.defaultProps = { theme: Base };
const StyledDropDownItem = styled(DropDownItem)`
padding: 7px 23px;
`;
export {
StyledFloatingButton,
StyledDropDown,
StyledDropDownItem,
StyledContainerAction,
StyledProgressBarContainer,
StyledMobileProgressBar,
StyledProgressContainer,
StyledBar,
StyledButtonWrapper,
StyledButtonOptions,
};

View File

@ -167,6 +167,18 @@ const Base = {
bodyPadding: "16px 0",
},
mainButtonMobile: {
dropDown: {
right: "15%",
bottom: "15%",
width: "400px",
},
dropDownItem: {
padding: "10px",
},
},
mainButton: {
backgroundColor: orangeMain,
disableBackgroundColor: orangeDisabled,

View File

@ -0,0 +1,3 @@
<svg width="14" height="2" viewBox="0 0 14 2" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="14" height="2" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 144 B

View File

@ -0,0 +1,3 @@
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 6V0H6V6H0V8H6V14H8V8H14V6H8Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 200 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 2C2 1.44772 2.44772 1 3 1H11L14 4.11111V14C14 14.5523 13.5523 15 13 15H3C2.44772 15 2 14.5523 2 14V2Z" stroke="#333333" stroke-width="2" stroke-linejoin="round"/>
<path d="M4 5H10M4 8H12M4 11H12" stroke="#333333" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 347 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.00329 1H1.00391C0.450371 1 0.00214033 1.44967 0.00391148 2.0032L0.0423083 14.0032C0.0440714 14.5542 0.491268 15 1.0423 15H15.0015C15.5538 15 16.0015 14.5523 16.0015 14V4.99571C16.0015 4.44342 15.5538 3.99571 15.0015 3.99571H9.00096L6.00329 1ZM5.00379 3H3.00519C2.45116 3 2.00272 3.45045 2.0052 4.00448L2.04104 12.0045C2.0435 12.555 2.49049 13 3.04103 13H13.0015C13.5538 13 14.0015 12.5523 14.0015 12V6.99571C14.0015 6.44342 13.5538 5.99571 13.0015 5.99571H8.00147L5.00379 3Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 648 B

View File

@ -0,0 +1,5 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 4V11C2 11.5523 2.44772 12 3 12H6M14 4V11C14 11.5523 13.5523 12 13 12H10M6 12V13C6 14.1046 6.89543 15 8 15V15C9.10457 15 10 14.1046 10 13V12M6 12H10" stroke="#333333" stroke-width="2" stroke-linejoin="round"/>
<path d="M1 3V2H4M15 3V2H12M4 2V1H5V2M4 2H5M5 2H11M11 2V1H12V2M11 2H12" stroke="#333333" stroke-width="2" stroke-linejoin="round"/>
<path d="M6 9.5V4.5L11 7L6 9.5Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 506 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 8C2 4.68629 4.68629 2 8 2C11.3137 2 14 4.68629 14 8C14 11.3137 11.3137 14 8 14C4.68629 14 2 11.3137 2 8ZM8 0C3.58172 0 0 3.58172 0 8C0 12.4183 3.58172 16 8 16C12.4183 16 16 12.4183 16 8C16 3.58172 12.4183 0 8 0ZM11.7074 10.2938L9.41412 8.00086L11.7075 5.70749L10.2933 4.29328L7.9998 6.58677L5.70588 4.29322L4.29178 5.70755L6.58558 8.00098L4.29328 10.2933L5.7075 11.7075L7.99991 9.41508L10.2933 11.7081L11.7074 10.2938Z" fill="#A3A9AE"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 1V15M1 7H15" stroke="#333333" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 1C1.89543 1 1 1.89543 1 3V5H3V3H5V1H3ZM9 1V3L13 3V5H15V3C15 1.89543 14.1046 1 13 1H9ZM15 9H13V13H9V15H13C14.1046 15 15 14.1046 15 13V9ZM5 15V13H3V9H1V13C1 14.1046 1.89543 15 3 15H5Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 416 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="15" viewBox="0 0 16 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99996 0C8.39009 0 8.74461 0.226888 8.90802 0.581154L10.6485 4.35457L14.7751 4.84384C15.1625 4.88977 15.4879 5.15682 15.6084 5.52786C15.729 5.8989 15.6227 6.30618 15.3363 6.57106L12.2854 9.39243L13.0953 13.4682C13.1713 13.8509 13.0179 14.2428 12.7022 14.4721C12.3866 14.7015 11.9664 14.7263 11.626 14.5357L7.99996 12.506L4.3739 14.5357C4.03347 14.7263 3.6133 14.7015 3.29768 14.4721C2.98205 14.2428 2.8286 13.8509 2.90464 13.4682L3.71449 9.39243L0.663612 6.57106C0.377181 6.30618 0.270949 5.8989 0.391507 5.52786C0.512066 5.15682 0.837401 4.88977 1.22482 4.84384L5.3514 4.35457L7.0919 0.581154C7.25531 0.226888 7.60982 0 7.99996 0ZM7.99996 3.38751L6.93306 5.70055C6.78739 6.01636 6.48811 6.2338 6.14274 6.27475L3.61322 6.57466L5.48336 8.30411C5.7387 8.54024 5.85301 8.89207 5.78523 9.23319L5.28881 11.7316L7.51152 10.4874C7.81499 10.3175 8.18493 10.3175 8.4884 10.4874L10.7111 11.7316L10.2147 9.23319C10.1469 8.89207 10.2612 8.54024 10.5166 8.30411L12.3867 6.57466L9.85718 6.27475C9.51181 6.2338 9.21253 6.01636 9.06686 5.70055L7.99996 3.38751Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB