Merge pull request #898 from ONLYOFFICE/bugfix/login

Bugfix/login
This commit is contained in:
Alexey Safronov 2022-10-24 12:02:46 +03:00 committed by GitHub
commit 9a37b55b80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 322 additions and 29 deletions

View File

@ -38,6 +38,9 @@ class SettingsStore {
? window.RendererProcessVariable?.theme?.type === "dark"
? Dark
: Base
: window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? Dark
: Base;
trustedDomains = [];
trustedDomainsType = 0;

View File

@ -2,13 +2,15 @@ import React from "react";
import styled from "styled-components";
import { tablet, hugeMobile } from "@docspace/components/utils/device";
import Base from "../themes/base";
const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
padding: 32px;
background: #ffffff;
box-shadow: 0px 5px 20px rgba(4, 15, 27, 0.07);
background: ${(props) => props.theme.formWrapper.background};
box-shadow: ${(props) => props.theme.formWrapper.boxShadow};
border-radius: 12px;
max-width: 320px;
min-width: 320px;
@ -24,13 +26,17 @@ const StyledWrapper = styled.div`
box-shadow: none;
max-width: 343px;
min-width: 343px;
background: #ffffff;
background: transparent;
}
`;
StyledWrapper.defaultProps = { theme: Base };
const FormWrapper = (props) => {
const { children } = props;
return <StyledWrapper>{children}</StyledWrapper>;
return <StyledWrapper {...props}>{children}</StyledWrapper>;
};
FormWrapper.defaultProps = { theme: Base };
export default FormWrapper;

View File

@ -17,7 +17,7 @@ const StyledOuter = styled.div`
}
path {
fill: ${(props) =>
props.color ? props.color : props.theme.iconButton.color};
props.color ? props.color : props.theme.iconButton.color} !important;
}
}
&:hover {

View File

@ -368,7 +368,6 @@ class PasswordInput extends React.Component {
<>
<InputBlock
className="input-relative"
id={id}
name={inputName}
hasError={hasError}
isDisabled={isDisabled}
@ -412,10 +411,12 @@ class PasswordInput extends React.Component {
style,
simpleView,
isDisabled,
id,
} = this.props;
return (
<StyledInput
id={id}
onValidateInput={onValidateInput}
className={className}
style={style}

View File

@ -2732,6 +2732,8 @@ const Base = {
login: {
linkColor: link,
textColor: gray,
navBackground: "#F8F9F9",
headerColor: black,
register: {
backgroundColor: grayLight,
@ -2975,6 +2977,11 @@ const Base = {
border: "1px solid #eceef1",
},
},
formWrapper: {
background: white,
boxShadow: "0px 5px 20px rgba(4, 15, 27, 0.07)",
},
};
export default Base;

View File

@ -2738,6 +2738,8 @@ const Dark = {
login: {
linkColor: "#E06A1B",
textColor: "#858585",
navBackground: "#282828",
headerColor: white,
register: {
backgroundColor: "#292929",
@ -2980,6 +2982,11 @@ const Dark = {
border: "1px solid #858585",
},
},
formWrapper: {
background: black,
boxShadow: "0px 5px 20px rgba(0, 0, 0, 0.16);",
},
};
export default Dark;

View File

@ -96,6 +96,7 @@ declare global {
capabilities: ICapabilities;
match: MatchType;
currentColorScheme: ITheme;
isAuth: boolean;
}
interface DevRequest {

View File

@ -5,6 +5,7 @@ import InvalidRoute from "./components/Invalid";
import CodeLogin from "./components/CodeLogin";
import initLoginStore from "../store";
import { Provider as MobxProvider } from "mobx-react";
import SimpleNav from "../client/components/sub-components/SimpleNav";
interface ILoginProps extends IInitialState {
isDesktopEditor?: boolean;
@ -13,6 +14,7 @@ const App: React.FC<ILoginProps> = (props) => {
const loginStore = initLoginStore(props.currentColorScheme);
return (
<MobxProvider {...loginStore}>
<SimpleNav />
<Switch>
<Route path="/login/error">
<InvalidRoute />

View File

@ -1,5 +1,6 @@
import React, { useState, useCallback } from "react";
import React, { useEffect, useState, useCallback } from "react";
import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
import { ButtonsWrapper, LoginFormWrapper } from "./StyledLogin";
import Logo from "../../../../../public/images/docspace.big.react.svg";
import Text from "@docspace/components/text";
@ -20,6 +21,8 @@ import FormWrapper from "@docspace/components/form-wrapper";
import Register from "./sub-components/register-container";
import { ColorTheme, ThemeType } from "@docspace/common/components/ColorTheme";
import SSOIcon from "../../../../../public/images/sso.react.svg";
import { Dark, Base } from "@docspace/components/themes";
import { useMounted } from "../helpers/useMounted";
interface ILoginProps extends IInitialState {
isDesktopEditor?: boolean;
@ -31,6 +34,9 @@ const Login: React.FC<ILoginProps> = ({
capabilities,
isDesktopEditor,
match,
currentColorScheme,
theme,
setTheme,
}) => {
const [isLoading, setIsLoading] = useState(false);
const [moreAuthVisible, setMoreAuthVisible] = useState(false);
@ -40,6 +46,16 @@ const Login: React.FC<ILoginProps> = ({
const { ssoLabel, ssoUrl } = capabilities;
const { t } = useTranslation(["Login", "Common"]);
const mounted = useMounted();
useEffect(() => {
const theme =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? Dark
: Base;
setTheme(theme);
}, []);
const ssoExists = () => {
if (ssoUrl) return true;
@ -155,13 +171,40 @@ const Login: React.FC<ILoginProps> = ({
setRecoverDialogVisible(!recoverDialogVisible);
};
const getBgPattern = () => {
switch (currentColorScheme.id) {
case 1:
return "url('/static/images/background.pattern.react.svg')";
case 2:
return "url('/static/images/background.pattern.orange.react.svg')";
case 3:
return "url('/static/images/background.pattern.green.react.svg')";
case 4:
return "url('/static/images/background.pattern.red.react.svg')";
case 5:
return "url('/static/images/background.pattern.purple.react.svg')";
case 6:
return "url('/static/images/background.pattern.lightBlue.react.svg')";
case 7:
return "url('/static/images/background.pattern.black.react.svg')";
default:
return "url('/static/images/background.pattern.react.svg')";
}
};
const bgPattern = getBgPattern();
if (!mounted) return <></>;
return (
<LoginFormWrapper
id="login-page"
enabledJoin={enabledJoin}
isDesktop={isDesktopEditor}
className="with-background-pattern"
//className="with-background-pattern"
bgPattern={bgPattern}
>
<ColorTheme themeId={ThemeType.LinkForgotPassword}>
<ColorTheme themeId={ThemeType.LinkForgotPassword} theme={theme}>
<Logo className="logo-wrapper" />
<Text
fontSize="23px"
@ -171,7 +214,7 @@ const Login: React.FC<ILoginProps> = ({
>
{greetingSettings}
</Text>
<FormWrapper>
<FormWrapper id="login-form" theme={theme}>
{ssoExists() && <ButtonsWrapper>{ssoButton()}</ButtonsWrapper>}
{oauthDataExists() && (
<>
@ -225,9 +268,19 @@ const Login: React.FC<ILoginProps> = ({
emailPlaceholderText={t("RecoverContactEmailPlaceholder")}
/>
</ColorTheme>
{!checkIsSSR() && enabledJoin && <Register enabledJoin={enabledJoin} />}
{!checkIsSSR() && enabledJoin && (
<Register
enabledJoin={enabledJoin}
currentColorScheme={currentColorScheme}
/>
)}
</LoginFormWrapper>
);
};
export default Login;
export default inject(({ loginStore }) => {
return {
theme: loginStore.theme,
setTheme: loginStore.setTheme,
};
})(observer(Login));

View File

@ -57,6 +57,7 @@ export const LoginContainer = styled.div`
width: 100%;
padding-bottom: 32px;
min-height: 32px;
color: ${(props) => props.theme.login.headerColor};
@media ${hugeMobile} {
padding-top: 32px;
@ -68,7 +69,7 @@ export const LoginContainer = styled.div`
}
.or-label {
margin: 0 8px;
margin: 0 32px;
}
.line {
@ -133,11 +134,9 @@ export const LoginContainer = styled.div`
}
.auth-form-container {
margin: 32px 213px 0 213px;
width: 320px;
@media ${tablet} {
margin: 32px 0 0 0;
width: 100%;
}
@media ${hugeMobile} {
@ -145,6 +144,14 @@ export const LoginContainer = styled.div`
width: 100%;
}
.field-body{
input, .password-input > div {
background: ${(props) => props.theme.input.backgroundColor};
color: ${(props) => props.theme.input.color};
border-color: ${(props) => props.theme.input.borderColor};
}
}
.login-forgot-wrapper {
margin-bottom: 14px;
.login-checkbox-wrapper {
@ -155,6 +162,22 @@ export const LoginContainer = styled.div`
display: flex;
align-items: flex-start;
svg{
margin-right: 8px !important;
rect{
fill: ${(props) => props.theme.checkbox.fillColor};
stroke: ${(props) => props.theme.checkbox.borderColor};
}
path{
fill: ${(props) => props.theme.checkbox.arrowColor};
}
}
.checkbox-text{
color: ${(props) => props.theme.checkbox.arrowColor};
}
label {
justify-content: center;
}
@ -207,6 +230,10 @@ export const LoginContainer = styled.div`
height: 46px;
padding-bottom: 64px;
path:last-child {
fill: ${(props) => props.theme.client.home.logoColor};
}
@media ${hugeMobile} {
display: none;
}
@ -216,6 +243,7 @@ export const LoginContainer = styled.div`
interface ILoginFormWrapperProps {
enabledJoin?: boolean;
isDesktop?: boolean;
bgPattern?: string;
}
export const LoginFormWrapper = styled.div`
@ -228,4 +256,19 @@ export const LoginFormWrapper = styled.div`
: css`1fr`};
width: 100%;
height: 100vh;
background-image: ${props => props.bgPattern};
background-repeat: no-repeat;
background-attachment: fixed;
background-size: 100% 100%;
@media (max-width: 1024px) {
background-size: cover;
}
@media (max-width: 428px) {
background-image: none;
height: calc(100vh - 48px);
}
`;

View File

@ -253,6 +253,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
errorMessage={!password.trim() ? t("Common:RequiredField") : ""} //TODO: Add wrong password server error
>
<PasswordInput
className="password-input"
simpleView={true}
passwordSettings={settings}
id="password"
@ -275,6 +276,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
<div className="login-checkbox-wrapper">
<div className="remember-wrapper">
<Checkbox
id="login-checkbox"
className="login-checkbox"
isChecked={isChecked}
onChange={onChangeCheckbox}
@ -282,6 +284,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
helpButton={
!checkIsSSR() && (
<HelpButton
color="#A3A9AE"
helpButtonHeaderContent={t("CookieSettingsTitle")}
tooltipContent={
<Text fontSize="12px">{t("RememberHelper")}</Text>
@ -319,7 +322,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
id="submit"
className="login-button"
primary
size="normal"
size="medium"
scale={true}
label={
isLoading ? t("Common:LoadingProcessing") : t("Common:LoginButton")
@ -352,7 +355,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
color="#316DAA"
type="action"
isHovered={true}
className="recover-link"
className="login-link recover-link"
onClick={onRecoverDialogVisible}
>
{t("RecoverAccess")}

View File

@ -0,0 +1,34 @@
import React from "react";
import styled from "styled-components";
import { inject, observer } from "mobx-react";
import { hugeMobile } from "@docspace/components/utils/device";
import { ReactSVG } from "react-svg";
const StyledNav = styled.div`
display: none;
height: 48px;
align-items: center;
justify-content: center;
background-color: ${(props) => props.theme.login.navBackground};
svg {
path:last-child {
fill: ${(props) => props.theme.client.home.logoColor};
}
}
@media ${hugeMobile} {
display: flex;
}
`;
const SimpleNav = ({ theme }) => {
return (
<StyledNav theme={theme}>
<ReactSVG src="/static/images/logo.docspace.react.svg" />
</StyledNav>
);
};
export default inject(({ loginStore }) => {
return { theme: loginStore.theme };
})(observer(SimpleNav));

View File

@ -16,6 +16,7 @@ interface IRegisterProps {
trustedDomainsType?: number;
trustedDomains?: string[];
theme?: any;
currentColorScheme: ITheme;
}
const StyledRegister = styled(Box)`
@ -41,6 +42,7 @@ const Register: React.FC<IRegisterProps> = (props) => {
trustedDomainsType,
trustedDomains,
theme,
currentColorScheme,
} = props;
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
@ -108,7 +110,7 @@ const Register: React.FC<IRegisterProps> = (props) => {
return enabledJoin && !isAuthenticated ? (
<>
<StyledRegister onClick={onRegisterClick}>
<Text color={theme.login.register.textColor}>{t("Register")}</Text>
<Text color={currentColorScheme.accentColor}>{t("Register")}</Text>
</StyledRegister>
{visible && (

View File

@ -0,0 +1,15 @@
import { useState, useEffect } from "react";
export const useMounted = () => {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
return () => {
setMounted(false);
};
}, []);
return mounted;
};

View File

@ -31,7 +31,7 @@ app.use("/login", express.static(path.resolve(path.join(__dirname, "client"))));
app.use(logger("dev", { stream: stream }));
app.get("*", async (req: ILoginRequest, res: Response) => {
app.get("*", async (req: ILoginRequest, res: Response, next) => {
const { i18n, cookies, headers, query, t, url } = req;
let initialState: IInitialState;
let assets: assetsType;
@ -41,6 +41,11 @@ app.get("*", async (req: ILoginRequest, res: Response) => {
try {
initialState = await getInitialState(query);
if (initialState.isAuth) {
res.redirect('/');
next();
}
let currentLanguage = initialState.portalSettings.culture;
if (cookies && cookies[LANGUAGE]) {

View File

@ -7,6 +7,7 @@ import {
getCapabilities,
getAppearanceTheme,
} from "@docspace/common/api/settings";
import { checkIsAuthenticated } from "@docspace/common/api/user";
export const getAssets = (): assetsType => {
const manifest = fs.readFileSync(
@ -55,7 +56,8 @@ export const getInitialState = async (
buildInfo: IBuildInfo,
providers: ProvidersType,
capabilities: ICapabilities,
availableThemes: IThemes;
availableThemes: IThemes,
isAuth: any;
[
portalSettings,
@ -63,12 +65,14 @@ export const getInitialState = async (
providers,
capabilities,
availableThemes,
isAuth,
] = await Promise.all([
getSettings(),
getBuildVersion(),
getAuthProviders(),
getCapabilities(),
getAppearanceTheme(),
checkIsAuthenticated()
]);
const currentColorScheme = availableThemes.themes.find((theme) => {
@ -82,6 +86,7 @@ export const getInitialState = async (
capabilities,
match: query,
currentColorScheme,
isAuth
};
return initialState;

View File

@ -83,6 +83,75 @@ const template: Template = (
<!-- <meta name="apple-mobile-web-app-capable" content="yes" /> -->
<link rel="apple-touch-icon" href="/appIcon-180.png" />
${styleTags}
<style>
@media (prefers-color-scheme: light) {
body {
background-color: #fff;
}
#login-page > div > svg > path:last-child {
fill: #333;
}
#login-page > div > p {
color: #333;
}
#login-form {
background-color: #fff;
box-shadow: 0px 5px 20px rgba(4, 15, 27, 0.07);
}
#login, #password > div, #password > div > input {
background: #fff;
border-color: #D0D5DA;
}
#login-checkbox > svg > rect {
fill: #fff;
stroke: #D0D5DA;
}
#login-checkbox > div > span {
color: #333;
}
}
@media (prefers-color-scheme: dark) {
body {
background-color: #333;
}
#login-page > div > svg > path:last-child {
fill: #fff;
}
#login-page > div > p {
color: #fff;
}
#login-form {
background-color: #333;
box-shadow: 0px 5px 20px rgba(0, 0, 0, 0.16);
}
#login, #password > div, #password > div > input {
background: #282828;
border-color: #474747;
}
#login-checkbox > svg > rect {
fill: #282828;
stroke: #474747;
}
#login-checkbox > div > span {
color: #fff;
}
}
</style>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>

View File

@ -1,15 +1,22 @@
import { makeAutoObservable } from "mobx";
import { getAppearanceTheme } from "@docspace/common/api/settings";
import { Base } from "@docspace/components/themes";
class LoginStore {
currentColorScheme: ITheme | null = null;
appearanceTheme: IThemes | [] = [];
selectedThemeId: number | null = null;
theme = Base;
constructor(currentColorScheme: ITheme) {
makeAutoObservable(this);
this.currentColorScheme = currentColorScheme;
}
setTheme = (theme) => {
this.theme = theme;
}
setCurrentColorScheme = (currentColorScheme: ITheme) => {
this.currentColorScheme = currentColorScheme;
};

View File

@ -0,0 +1,5 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M64.6252 690.408L-919.12 986.976C-1004.49 1013.18 -1013.6 1072.53 -939.494 1119.65L-74.1381 1702.89C14.1367 1767.84 98.0781 1792.04 227.343 1745.01L1209.66 1449.78C1295.03 1423.58 1304.14 1364.23 1230.04 1317.1L403.802 732.878C315.028 664.676 226.063 647.445 64.6252 690.408Z" fill="#6E6E6E"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M1209.36 391.601L2228.17 575.78C2315.2 592.373 2330.62 649.928 2262.64 704.433L1472.4 1373.42C1405.32 1431.31 1281.37 1464.53 1197.69 1447.04L178.872 1262.86C91.8424 1246.27 76.4229 1188.71 144.405 1134.21L934.649 465.22C1012.63 397.338 1126.59 377.497 1209.36 391.601Z" fill="#6E6E6E"/>
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M967.484 836.396L881.673 1868.31C875.172 1956.68 926.767 1986.47 997.002 1934.91L1847.63 1344.62C1920.9 1294.81 1985.06 1183.66 1989.83 1098.29L2075.64 66.374C2082.14 -21.9972 2030.55 -51.7898 1960.31 -0.221198L1109.68 590.062C1023.94 647.831 975.285 752.781 967.484 836.396Z" fill="#6E6E6E"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,5 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M64.6252 690.408L-919.12 986.976C-1004.49 1013.18 -1013.6 1072.53 -939.494 1119.65L-74.1381 1702.89C14.1367 1767.84 98.0781 1792.04 227.343 1745.01L1209.66 1449.78C1295.03 1423.58 1304.14 1364.23 1230.04 1317.1L403.802 732.878C315.028 664.676 226.063 647.445 64.6252 690.408Z" fill="#22C386"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M1209.36 391.601L2228.17 575.78C2315.2 592.373 2330.62 649.928 2262.64 704.433L1472.4 1373.42C1405.32 1431.31 1281.37 1464.53 1197.69 1447.04L178.872 1262.86C91.8424 1246.27 76.4229 1188.71 144.405 1134.21L934.649 465.22C1012.63 397.338 1126.59 377.497 1209.36 391.601Z" fill="#22C386"/>
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M967.484 836.396L881.673 1868.31C875.172 1956.68 926.767 1986.47 997.002 1934.91L1847.63 1344.62C1920.9 1294.81 1985.06 1183.66 1989.83 1098.29L2075.64 66.374C2082.14 -21.9972 2030.55 -51.7898 1960.31 -0.221198L1109.68 590.062C1023.94 647.831 975.285 752.781 967.484 836.396Z" fill="#22C386"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,5 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M64.6252 690.408L-919.12 986.976C-1004.49 1013.18 -1013.6 1072.53 -939.494 1119.65L-74.1381 1702.89C14.1367 1767.84 98.0781 1792.04 227.343 1745.01L1209.66 1449.78C1295.03 1423.58 1304.14 1364.23 1230.04 1317.1L403.802 732.878C315.028 664.676 226.063 647.445 64.6252 690.408Z" fill="#13B7EC"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M1209.36 391.601L2228.17 575.78C2315.2 592.373 2330.62 649.928 2262.64 704.433L1472.4 1373.42C1405.32 1431.31 1281.37 1464.53 1197.69 1447.04L178.872 1262.86C91.8424 1246.27 76.4229 1188.71 144.405 1134.21L934.649 465.22C1012.63 397.338 1126.59 377.497 1209.36 391.601Z" fill="#13B7EC"/>
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M967.484 836.396L881.673 1868.31C875.172 1956.68 926.767 1986.47 997.002 1934.91L1847.63 1344.62C1920.9 1294.81 1985.06 1183.66 1989.83 1098.29L2075.64 66.374C2082.14 -21.9972 2030.55 -51.7898 1960.31 -0.221198L1109.68 590.062C1023.94 647.831 975.285 752.781 967.484 836.396Z" fill="#13B7EC"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,5 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M64.6252 690.408L-919.12 986.976C-1004.49 1013.18 -1013.6 1072.53 -939.494 1119.65L-74.1381 1702.89C14.1367 1767.84 98.0781 1792.04 227.343 1745.01L1209.66 1449.78C1295.03 1423.58 1304.14 1364.23 1230.04 1317.1L403.802 732.878C315.028 664.676 226.063 647.445 64.6252 690.408Z" fill="#FF9933"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M1209.36 391.601L2228.17 575.78C2315.2 592.373 2330.62 649.928 2262.64 704.433L1472.4 1373.42C1405.32 1431.31 1281.37 1464.53 1197.69 1447.04L178.872 1262.86C91.8424 1246.27 76.4229 1188.71 144.405 1134.21L934.649 465.22C1012.63 397.338 1126.59 377.497 1209.36 391.601Z" fill="#FF9933"/>
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M967.484 836.396L881.673 1868.31C875.172 1956.68 926.767 1986.47 997.002 1934.91L1847.63 1344.62C1920.9 1294.81 1985.06 1183.66 1989.83 1098.29L2075.64 66.374C2082.14 -21.9972 2030.55 -51.7898 1960.31 -0.221198L1109.68 590.062C1023.94 647.831 975.285 752.781 967.484 836.396Z" fill="#FF9933"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,5 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M64.6252 690.408L-919.12 986.976C-1004.49 1013.18 -1013.6 1072.53 -939.494 1119.65L-74.1381 1702.89C14.1367 1767.84 98.0781 1792.04 227.343 1745.01L1209.66 1449.78C1295.03 1423.58 1304.14 1364.23 1230.04 1317.1L403.802 732.878C315.028 664.676 226.063 647.445 64.6252 690.408Z" fill="#8570BD"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M1209.36 391.601L2228.17 575.78C2315.2 592.373 2330.62 649.928 2262.64 704.433L1472.4 1373.42C1405.32 1431.31 1281.37 1464.53 1197.69 1447.04L178.872 1262.86C91.8424 1246.27 76.4229 1188.71 144.405 1134.21L934.649 465.22C1012.63 397.338 1126.59 377.497 1209.36 391.601Z" fill="#8570BD"/>
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M967.484 836.396L881.673 1868.31C875.172 1956.68 926.767 1986.47 997.002 1934.91L1847.63 1344.62C1920.9 1294.81 1985.06 1183.66 1989.83 1098.29L2075.64 66.374C2082.14 -21.9972 2030.55 -51.7898 1960.31 -0.221198L1109.68 590.062C1023.94 647.831 975.285 752.781 967.484 836.396Z" fill="#8570BD"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,5 @@
<svg width="1440" height="1024" viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.1" fill-rule="evenodd" clip-rule="evenodd" d="M64.6252 690.408L-919.12 986.976C-1004.49 1013.18 -1013.6 1072.53 -939.494 1119.65L-74.1381 1702.89C14.1367 1767.84 98.0781 1792.04 227.343 1745.01L1209.66 1449.78C1295.03 1423.58 1304.14 1364.23 1230.04 1317.1L403.802 732.878C315.028 664.676 226.063 647.445 64.6252 690.408Z" fill="#F27564"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M1209.36 391.601L2228.17 575.78C2315.2 592.373 2330.62 649.928 2262.64 704.433L1472.4 1373.42C1405.32 1431.31 1281.37 1464.53 1197.69 1447.04L178.872 1262.86C91.8424 1246.27 76.4229 1188.71 144.405 1134.21L934.649 465.22C1012.63 397.338 1126.59 377.497 1209.36 391.601Z" fill="#F27564"/>
<path opacity="0.2" fill-rule="evenodd" clip-rule="evenodd" d="M967.484 836.396L881.673 1868.31C875.172 1956.68 926.767 1986.47 997.002 1934.91L1847.63 1344.62C1920.9 1294.81 1985.06 1183.66 1989.83 1098.29L2075.64 66.374C2082.14 -21.9972 2030.55 -51.7898 1960.31 -0.221198L1109.68 590.062C1023.94 647.831 975.285 752.781 967.484 836.396Z" fill="#F27564"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -5847,9 +5847,9 @@ __metadata:
linkType: hard
"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0, @types/node@npm:^18.6.1":
version: 18.11.2
resolution: "@types/node@npm:18.11.2"
checksum: 0ff5c90fb9ab653e018b858479aea4d2f763b07b31f9502383d408936f525ca37cac82ea27774a0dd0356ff9badba2792a6a3fff94f79fd7c82ee2a892c43ed5
version: 18.11.3
resolution: "@types/node@npm:18.11.3"
checksum: 3a2a9142d891a90a195c296149bf64a69cc0abcc42f543be911ab22b2e0ead85ff077f90af92f0f13f6e3e5e72501469200fd753dfd1101825d4646a89d3ee47
languageName: node
linkType: hard
@ -8646,9 +8646,9 @@ __metadata:
linkType: hard
"caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001125, caniuse-lite@npm:^1.0.30001400":
version: 1.0.30001422
resolution: "caniuse-lite@npm:1.0.30001422"
checksum: 29c950944b33ce242068402e679a5651d1289033381dcad7295cf14b589a6bd93d5bf32aa458bacaba9b25597731e0278c84ee588910ae774eab0585be88df62
version: 1.0.30001423
resolution: "caniuse-lite@npm:1.0.30001423"
checksum: fe443f323f5dc6a858ef7d7deddb93db5e5f9a35e22970c4a65c4ef793bb696c1e2f038df572722d9edf29021e43ed16f5131faafde783563bd0d9eccf486592
languageName: node
linkType: hard
@ -16351,13 +16351,13 @@ __metadata:
linkType: hard
"loader-utils@npm:^2.0.0":
version: 2.0.2
resolution: "loader-utils@npm:2.0.2"
version: 2.0.3
resolution: "loader-utils@npm:2.0.3"
dependencies:
big.js: ^5.2.2
emojis-list: ^3.0.0
json5: ^2.1.2
checksum: 9078d1ed47cadc57f4c6ddbdb2add324ee7da544cea41de3b7f1128e8108fcd41cd3443a85b7ee8d7d8ac439148aa221922774efe4cf87506d4fb054d5889303
checksum: d055c61ce5927b64cb4af40218606603a7d3a39adb7b6eec116bb31d19203875950e478152dea056de404eced8e87e9bfd336ec636591ded040ea451f63c7d88
languageName: node
linkType: hard