v8: Update login page design (#33923)

* Theme: Initial draft of dark login page

* update

* Updated login background

* Updates

* anim test

* Anim tweak

* Animate login box

* Updates

* Updating login page

* Improve footer readability on login page

* Fix sign up button
This commit is contained in:
Torkel Ödegaard 2021-05-11 16:34:44 +02:00 committed by GitHub
parent b3c4b08f03
commit 4fabade35c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 195 additions and 55 deletions

View File

@ -15,6 +15,10 @@ export const sharedInputStyle = (theme: GrafanaTheme2, invalid = false) => {
const background = theme.components.input.background; const background = theme.components.input.background;
const textColor = theme.components.input.text; const textColor = theme.components.input.text;
// Cannot use our normal borders for this color for some reason due the alpha values in them.
// Need to colors without alpha channel
const autoFillBorder = theme.isDark ? '#2e2f35' : '#bab4ca';
return css` return css`
background: ${background}; background: ${background};
line-height: ${theme.typography.body.lineHeight}; line-height: ${theme.typography.body.lineHeight};
@ -28,6 +32,7 @@ export const sharedInputStyle = (theme: GrafanaTheme2, invalid = false) => {
/* Welcome to 2005. This is a HACK to get rid od Chromes default autofill styling */ /* Welcome to 2005. This is a HACK to get rid od Chromes default autofill styling */
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0), inset 0 0 0 100px ${background}!important; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0), inset 0 0 0 100px ${background}!important;
-webkit-text-fill-color: ${textColor} !important; -webkit-text-fill-color: ${textColor} !important;
border-color: ${autoFillBorder};
} }
&:-webkit-autofill:focus { &:-webkit-autofill:focus {

View File

@ -1,6 +1,7 @@
import React, { FC } from 'react'; import React, { FC } from 'react';
import { css, cx } from '@emotion/css'; import { css, cx } from '@emotion/css';
import { useTheme } from '@grafana/ui'; import { useTheme2 } from '@grafana/ui';
import { colorManipulator } from '@grafana/data';
export interface BrandComponentProps { export interface BrandComponentProps {
className?: string; className?: string;
@ -12,10 +13,21 @@ const LoginLogo: FC<BrandComponentProps> = ({ className }) => {
}; };
const LoginBackground: FC<BrandComponentProps> = ({ className, children }) => { const LoginBackground: FC<BrandComponentProps> = ({ className, children }) => {
const theme = useTheme(); const theme = useTheme2();
const background = css` const background = css`
background: url(public/img/login_background_${theme.isDark ? 'dark' : 'light'}.svg); &:before {
background-size: cover; content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
background: url(public/img/g8_login_${theme.isDark ? 'dark' : 'light'}.svg);
background-size: cover;
opacity: 0;
transition: opacity 3s ease-in-out;
}
`; `;
return <div className={cx(background, className)}>{children}</div>; return <div className={cx(background, className)}>{children}</div>;
@ -26,9 +38,9 @@ const MenuLogo: FC<BrandComponentProps> = ({ className }) => {
}; };
const LoginBoxBackground = () => { const LoginBoxBackground = () => {
const theme = useTheme(); const theme = useTheme2();
return css` return css`
background: ${theme.isLight ? 'rgba(6, 30, 200, 0.1 )' : 'rgba(18, 28, 41, 0.65)'}; background: ${colorManipulator.alpha(theme.colors.background.primary, 0.7)};
background-size: cover; background-size: cover;
`; `;
}; };
@ -41,13 +53,6 @@ export class Branding {
static AppTitle = 'Grafana'; static AppTitle = 'Grafana';
static LoginTitle = 'Welcome to Grafana'; static LoginTitle = 'Welcome to Grafana';
static GetLoginSubTitle = () => { static GetLoginSubTitle = () => {
const slogans = [ return null;
"Don't get in the way of the data",
'Your single pane of glass',
'Built better together',
'Democratising data',
];
const count = slogans.length;
return slogans[Math.floor(Math.random() * count)];
}; };
} }

View File

@ -1,28 +1,33 @@
import React, { FC } from 'react'; import React, { FC, useEffect, useState } from 'react';
import { cx, css, keyframes } from '@emotion/css'; import { cx, css, keyframes } from '@emotion/css';
import { useStyles } from '@grafana/ui'; import { useStyles2 } from '@grafana/ui';
import { Branding } from '../Branding/Branding'; import { Branding } from '../Branding/Branding';
import { GrafanaTheme } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { Footer } from '../Footer/Footer'; import { Footer } from '../Footer/Footer';
interface InnerBoxProps { interface InnerBoxProps {
enterAnimation?: boolean; enterAnimation?: boolean;
} }
export const InnerBox: FC<InnerBoxProps> = ({ children, enterAnimation = true }) => { export const InnerBox: FC<InnerBoxProps> = ({ children, enterAnimation = true }) => {
const loginStyles = useStyles(getLoginStyles); const loginStyles = useStyles2(getLoginStyles);
return <div className={cx(loginStyles.loginInnerBox, enterAnimation && loginStyles.enterAnimation)}>{children}</div>; return <div className={cx(loginStyles.loginInnerBox, enterAnimation && loginStyles.enterAnimation)}>{children}</div>;
}; };
export const LoginLayout: FC = ({ children }) => { export const LoginLayout: FC = ({ children }) => {
const loginStyles = useStyles(getLoginStyles); const loginStyles = useStyles2(getLoginStyles);
const subTitle = Branding.GetLoginSubTitle();
const [startAnim, setStartAnim] = useState(false);
useEffect(() => setStartAnim(true), []);
return ( return (
<Branding.LoginBackground className={loginStyles.container}> <Branding.LoginBackground className={cx(loginStyles.container, startAnim && loginStyles.loginAnim)}>
<div className={cx(loginStyles.loginContent, Branding.LoginBoxBackground())}> <div className={cx(loginStyles.loginContent, Branding.LoginBoxBackground(), 'login-content-box')}>
<div className={loginStyles.loginLogoWrapper}> <div className={loginStyles.loginLogoWrapper}>
<Branding.LoginLogo className={loginStyles.loginLogo} /> <Branding.LoginLogo className={loginStyles.loginLogo} />
<div className={loginStyles.titleWrapper}> <div className={loginStyles.titleWrapper}>
<h1 className={loginStyles.mainTitle}>{Branding.LoginTitle}</h1> <h1 className={loginStyles.mainTitle}>{Branding.LoginTitle}</h1>
<h3 className={loginStyles.subTitle}>{Branding.GetLoginSubTitle()}</h3> {subTitle && <h3 className={loginStyles.subTitle}>{Branding.GetLoginSubTitle()}</h3>}
</div> </div>
</div> </div>
<div className={loginStyles.loginOuterBox}>{children}</div> <div className={loginStyles.loginOuterBox}>{children}</div>
@ -43,20 +48,33 @@ to{
transform: translate(0px, 0px); transform: translate(0px, 0px);
}`; }`;
export const getLoginStyles = (theme: GrafanaTheme) => { export const getLoginStyles = (theme: GrafanaTheme2) => {
const bgColor = theme.isDark ? theme.palette.black : theme.palette.white; const bgColor = theme.isDark ? '#000' : theme.colors.background.canvas;
return { return {
container: css` container: css({
min-height: 100vh; minHeight: '100vh',
background-position: center; backgroundPosition: 'center',
background-repeat: no-repeat; backgroundRepeat: 'no-repeat',
background-color: ${bgColor}; backgroundColor: bgColor,
min-width: 100%; minWidth: '100%',
margin-left: 0; marginLeft: 0,
display: flex; display: 'flex',
flex-direction: column; flexDirection: 'column',
align-items: center; alignItems: 'center',
justify-content: center;
[theme.breakpoints.up('md')]: {
justifyContent: 'center',
},
}),
loginAnim: css`
&:before {
opacity: 1;
}
.login-content-box {
opacity: 1;
}
`, `,
submitButton: css` submitButton: css`
justify-content: center; justify-content: center;
@ -72,7 +90,7 @@ export const getLoginStyles = (theme: GrafanaTheme) => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
padding: ${theme.spacing.lg}; padding: ${theme.spacing(3)};
`, `,
titleWrapper: css` titleWrapper: css`
text-align: center; text-align: center;
@ -82,10 +100,10 @@ export const getLoginStyles = (theme: GrafanaTheme) => {
`, `,
subTitle: css` subTitle: css`
font-size: ${theme.typography.size.md}; font-size: ${theme.typography.size.md};
color: ${theme.colors.textSemiWeak}; color: ${theme.colors.text.secondary};
`, `,
loginContent: css` loginContent: css`
max-width: 550px; max-width: 478px;
width: 100%; width: 100%;
display: flex; display: flex;
align-items: stretch; align-items: stretch;
@ -94,8 +112,10 @@ export const getLoginStyles = (theme: GrafanaTheme) => {
justify-content: center; justify-content: center;
z-index: 1; z-index: 1;
min-height: 320px; min-height: 320px;
border-radius: 3px; border-radius: ${theme.shape.borderRadius(4)};
padding: 20px 0; padding: ${theme.spacing(2, 0)};
opacity: 0;
transition: opacity 0.5s ease-in-out;
`, `,
loginOuterBox: css` loginOuterBox: css`
display: flex; display: flex;
@ -104,10 +124,8 @@ export const getLoginStyles = (theme: GrafanaTheme) => {
justify-content: center; justify-content: center;
`, `,
loginInnerBox: css` loginInnerBox: css`
padding: ${theme.spacing.xl}; padding: ${theme.spacing(2)};
@media (max-width: 320px) {
padding: ${theme.spacing.lg};
}
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;

View File

@ -17,8 +17,9 @@ export const UserSignup: FC<{}> = () => {
`} `}
href={href} href={href}
variant="secondary" variant="secondary"
fill="outline"
> >
Sign Up Sign up
</LinkButton> </LinkButton>
</VerticalGroup> </VerticalGroup>
); );

View File

@ -96,7 +96,7 @@ export const SignupInvitedPage: FC<Props> = ({ match }) => {
/> />
</Field> </Field>
<Button type="submit">Sign Up</Button> <Button type="submit">Sign up</Button>
</> </>
)} )}
</Form> </Form>

View File

@ -124,7 +124,7 @@ const getStyles = stylesFactory(() => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
background: url(public/img/getting_started_bg_${theme.type}.svg) no-repeat; // background: url(public/img/getting_started_bg_${theme.type}.svg) no-repeat;
background-size: cover; background-size: cover;
padding: ${theme.spacing.xl} ${theme.spacing.md} 0; padding: ${theme.spacing.xl} ${theme.spacing.md} 0;
`, `,

View File

@ -53,7 +53,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme, complete: boolean) => {
margin-bottom: ${theme.spacing.md}; margin-bottom: ${theme.spacing.md};
`, `,
title: css` title: css`
margin-bottom: 48px; margin-bottom: ${theme.spacing.md};
`, `,
url: css` url: css`
border-top: 1px solid ${theme.colors.border1}; border-top: 1px solid ${theme.colors.border1};

View File

@ -19,7 +19,7 @@ export const TutorialCard: FC<Props> = ({ card }) => {
<div className={cardContent}> <div className={cardContent}>
<div className={styles.type}>{card.type}</div> <div className={styles.type}>{card.type}</div>
<div className={styles.heading}>{card.done ? 'complete' : card.heading}</div> <div className={styles.heading}>{card.done ? 'complete' : card.heading}</div>
<h4>{card.title}</h4> <h4 className={styles.cardTitle}>{card.title}</h4>
<div className={styles.info}>{card.info}</div> <div className={styles.info}>{card.info}</div>
<Icon className={iconStyle(theme, card.done)} name={card.icon} size="xxl" /> <Icon className={iconStyle(theme, card.done)} name={card.icon} size="xxl" />
</div> </div>
@ -37,7 +37,6 @@ const handleTutorialClick = (event: MouseEvent<HTMLAnchorElement>, card: Tutoria
}; };
const getStyles = stylesFactory((theme: GrafanaTheme, complete: boolean) => { const getStyles = stylesFactory((theme: GrafanaTheme, complete: boolean) => {
const textColor = `${complete ? theme.palette.blue95 : '#FFB357'}`;
return { return {
card: css` card: css`
${cardStyle(theme, complete)} ${cardStyle(theme, complete)}
@ -53,14 +52,17 @@ const getStyles = stylesFactory((theme: GrafanaTheme, complete: boolean) => {
} }
`, `,
type: css` type: css`
color: ${textColor}; color: ${theme.colors.textBlue};
text-transform: uppercase; text-transform: uppercase;
`, `,
heading: css` heading: css`
text-transform: uppercase; text-transform: uppercase;
color: ${textColor}; color: ${theme.colors.textBlue};
margin-bottom: ${theme.spacing.sm}; margin-bottom: ${theme.spacing.sm};
`, `,
cardTitle: css`
margin-bottom: ${theme.spacing.md};
`,
info: css` info: css`
margin-bottom: ${theme.spacing.md}; margin-bottom: ${theme.spacing.md};
`, `,

View File

@ -10,7 +10,7 @@ export const cardStyle = stylesFactory((theme: GrafanaTheme, complete: boolean)
const borderGradient = theme.isDark ? darkThemeGradients : lightThemeGradients; const borderGradient = theme.isDark ? darkThemeGradients : lightThemeGradients;
return ` return `
background-color: ${theme.colors.bg1}; background-color: ${theme.colors.bg2};
margin-right: ${theme.spacing.xl}; margin-right: ${theme.spacing.xl};
border: 1px solid ${theme.colors.border1}; border: 1px solid ${theme.colors.border1};
border-bottom-left-radius: ${theme.border.radius.md}; border-bottom-left-radius: ${theme.border.radius.md};
@ -45,5 +45,5 @@ export const iconStyle = stylesFactory(
); );
export const cardContent = css` export const cardContent = css`
padding: 24px 16px; padding: 16px;
`; `;

View File

@ -40,7 +40,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
return { return {
container: css` container: css`
display: flex; display: flex;
background: url(public/img/login_background_${theme.type}.svg) no-repeat; /// background: url(public/img/g8_home_v2.svg) no-repeat;
background-size: cover; background-size: cover;
height: 100%; height: 100%;
align-items: center; align-items: center;

33
public/img/g8_home_v2.svg Normal file
View File

@ -0,0 +1,33 @@
<svg width="1974" height="662" viewBox="0 0 1974 662" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="1974" height="662">
<rect width="1974" height="662" fill="#C4C4C4"/>
</mask>
<g mask="url(#mask0)">
<rect x="-462" y="-412" width="2898" height="1074" fill="black"/>
<ellipse opacity="0.6" cx="981" cy="125" rx="1342" ry="537" fill="url(#paint0_radial)" fill-opacity="0.8"/>
<ellipse opacity="0.25" cx="982" cy="1" rx="1192" ry="386" fill="url(#paint1_radial)"/>
<ellipse opacity="0.6" cx="981" cy="-78" rx="1049" ry="288" fill="url(#paint2_radial)"/>
<ellipse opacity="0.8" cx="983" cy="-134.5" rx="857" ry="212.5" fill="url(#paint3_radial)"/>
</g>
<defs>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(981 125) rotate(90) scale(537 1342)">
<stop stop-color="#4354E6"/>
<stop offset="1" stop-color="#2E24AA" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(982 1) rotate(90) scale(386 1192)">
<stop stop-color="#F89797"/>
<stop offset="0.254209" stop-color="#E6769F" stop-opacity="0.5"/>
<stop offset="1" stop-color="#6E477C" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(981 -78) rotate(90) scale(288 1049)">
<stop stop-color="#FF8A36" stop-opacity="0.6"/>
<stop offset="0.479167" stop-color="#FB5A67" stop-opacity="0.5"/>
<stop offset="1" stop-color="#68105A" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint3_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(983 -134.5) rotate(90) scale(212.5 857)">
<stop offset="0.410941" stop-color="#FBC55A"/>
<stop offset="0.688779" stop-color="#FF8A36" stop-opacity="0.4"/>
<stop offset="1" stop-color="#B71B66" stop-opacity="0"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,39 @@
<svg width="2261" height="1272" viewBox="0 0 2261 1272" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<rect width="2261" height="1272" fill="black"/>
<rect x="-1147" y="-916" width="4532" height="2576" fill="black"/>
<ellipse opacity="0.5" cx="1130.5" cy="-102.5" rx="4422.5" ry="1438.5" fill="url(#paint0_radial)"/>
<ellipse opacity="0.33" cx="1372" cy="-159.5" rx="1832" ry="1455.5" fill="url(#paint1_radial)"/>
<ellipse opacity="0.7" cx="400.5" cy="-509" rx="1860.5" ry="1673" fill="url(#paint2_radial)"/>
<ellipse opacity="0.7" cx="520.5" cy="-305" rx="980.5" ry="702" fill="url(#paint3_radial)"/>
<ellipse opacity="0.5" cx="500" cy="-160" rx="1049" ry="290" fill="url(#paint4_radial)"/>
</g>
<defs>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1130.5 -102.5) rotate(90) scale(1438.5 4422.5)">
<stop stop-color="#4354E6"/>
<stop offset="1" stop-color="#2E24AA" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(1372 -159.5) rotate(90) scale(1455.5 1832)">
<stop stop-color="#F89797"/>
<stop offset="0.484375" stop-color="#D676E6" stop-opacity="0.5"/>
<stop offset="1" stop-color="#4F477C" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(400.5 -509) rotate(90) scale(1673 1860.5)">
<stop stop-color="#FF8A36"/>
<stop offset="0.348958" stop-color="#FB5A67" stop-opacity="0.5"/>
<stop offset="1" stop-color="#68105F" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint3_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(520.5 -305) rotate(90) scale(702 980.5)">
<stop stop-color="#FF8A36"/>
<stop offset="1" stop-color="#833F6E" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint4_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(500 -160) rotate(90) scale(290 1049)">
<stop offset="0.313131" stop-color="#FBC55A"/>
<stop offset="0.597854" stop-color="#FF8A36" stop-opacity="0.5"/>
<stop offset="1" stop-color="#A63D8F" stop-opacity="0"/>
</radialGradient>
<clipPath id="clip0">
<rect width="2261" height="1272" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,27 @@
<svg width="2261" height="1272" viewBox="0 0 2261 1272" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<rect width="2261" height="1272" fill="#FFD597"/>
<rect x="-24" y="-24" width="2307" height="1323" fill="#FFD597"/>
<ellipse cx="-112.5" cy="640.5" rx="2931.5" ry="2470.5" fill="url(#paint0_radial)"/>
<ellipse cx="-238" cy="-864" rx="3314" ry="2081" fill="url(#paint1_radial)"/>
<ellipse cx="2539" cy="2086" rx="2442" ry="1491" fill="url(#paint2_radial)"/>
</g>
<defs>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-112.5 640.5) rotate(90) scale(2470.5 2931.5)">
<stop stop-color="#FF4408"/>
<stop offset="1" stop-color="#FFB728" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint1_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(-238 -864) rotate(90) scale(2081 3314)">
<stop offset="0.3125" stop-color="#733CE9"/>
<stop offset="0.666667" stop-color="#FF469F" stop-opacity="0.5"/>
<stop offset="1" stop-color="#FFBF1C" stop-opacity="0"/>
</radialGradient>
<radialGradient id="paint2_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(2539 2086) rotate(90) scale(1491 2442)">
<stop offset="0.3125" stop-color="white"/>
<stop offset="1" stop-color="#FFD600" stop-opacity="0"/>
</radialGradient>
<clipPath id="clip0">
<rect width="2261" height="1272" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -244,4 +244,5 @@ select:-webkit-autofill:focus {
-webkit-box-shadow: 0 0 0px 1000px $input-bg inset !important; -webkit-box-shadow: 0 0 0px 1000px $input-bg inset !important;
-webkit-text-fill-color: $input-color !important; -webkit-text-fill-color: $input-color !important;
box-shadow: 0 0 0px 1000px $input-bg inset; box-shadow: 0 0 0px 1000px $input-bg inset;
border: 1px solid $input-bg;
} }

View File

@ -49,6 +49,15 @@
bottom: $spacer; bottom: $spacer;
position: absolute; position: absolute;
padding: $space-md 0 $space-md 0; padding: $space-md 0 $space-md 0;
color: $text-color;
a {
color: $text-color;
&:hover {
color: $text-color-strong;
}
}
} }
} }