PublicDashboards: Title logo and footer redesign (#74769)

---------

Co-authored-by: Agnès Toulet <35176601+AgnesToulet@users.noreply.github.com>
pull/76575/head
Juan Cabanas 2 years ago committed by GitHub
parent e0f32f4363
commit cdca1518d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .betterer.results
  2. 8
      docs/sources/setup-grafana/configure-grafana/configure-custom-branding/index.md
  3. 34
      pkg/api/dtos/frontend_settings.go
  4. 37
      public/app/features/dashboard/components/PublicDashboard/PublicDashboardsFooter.tsx
  5. 55
      public/app/features/dashboard/components/PublicDashboard/usePublicDashboardConfig.tsx
  6. 54
      public/app/features/dashboard/components/PublicDashboardFooter/PublicDashboardsFooter.tsx
  7. 10
      public/app/features/dashboard/containers/PublicDashboardPage.tsx
  8. 70
      public/img/grafana_text_logo_dark.svg
  9. 20
      public/img/grafana_text_logo_light.svg

@ -3251,11 +3251,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Do not use any type assertions.", "4"], [0, 0, 0, "Do not use any type assertions.", "4"],
[0, 0, 0, "Unexpected any. Specify a different type.", "5"] [0, 0, 0, "Unexpected any. Specify a different type.", "5"]
], ],
"public/app/features/dashboard/components/PublicDashboardFooter/PublicDashboardsFooter.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"],
[0, 0, 0, "Styles should be written using objects.", "2"]
],
"public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx:5381": [ "public/app/features/dashboard/components/PublicDashboardNotAvailable/PublicDashboardNotAvailable.tsx:5381": [
[0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "0"],
[0, 0, 0, "Styles should be written using objects.", "1"], [0, 0, 0, "Styles should be written using objects.", "1"],

@ -120,18 +120,22 @@ To customize the footer of a public dashboard, add the following section to the
```ini ```ini
[white_labeling.public_dashboards] [white_labeling.public_dashboards]
# Hides the footer for the public dashboards if set to "true". If # Hides the footer for the public dashboards if set to `true`.
# example: footer_hide = "true" # example: footer_hide = "true"
;footer_hide = ;footer_hide =
# Set to text shown in the footer # Set to text shown in the footer
;footer_text = ;footer_text =
# Set to complete url to override public dashboard footer logo # Set to complete url to override public dashboard footer logo. Default is `grafana-logo` and will display the Grafana logo.
# An empty value will hide the footer logo.
;footer_logo = ;footer_logo =
# Set to link for the footer # Set to link for the footer
;footer_link = ;footer_link =
# Set to `true` to hide the Grafana logo next to the title
;header_logo_hide =
``` ```
If you specify `footer_hide` to `true`, all the other values are ignored because the footer will not be shown. If you specify `footer_hide` to `true`, all the other values are ignored because the footer will not be shown.

@ -93,27 +93,27 @@ type FrontendSettingsFooterConfigItemDTO struct {
} }
// Enterprise-only // Enterprise-only
type FrontendSettingsPublicDashboardFooterConfigDTO struct { type FrontendSettingsPublicDashboardConfigDTO struct {
Hide bool `json:"hide"` FooterHide bool `json:"footerHide"`
Text string `json:"text"` FooterText string `json:"footerText"`
Logo string `json:"logo"` FooterLogo string `json:"footerLogo"`
Link string `json:"link"` FooterLink string `json:"footerLink"`
HeaderLogoHide bool `json:"headerLogoHide"`
} }
// Enterprise-only // Enterprise-only
type FrontendSettingsWhitelabelingDTO struct { type FrontendSettingsWhitelabelingDTO struct {
Links []FrontendSettingsFooterConfigItemDTO `json:"links"` Links []FrontendSettingsFooterConfigItemDTO `json:"links"`
LoginTitle string `json:"loginTitle"` LoginTitle string `json:"loginTitle"`
AppTitle *string `json:"appTitle,omitempty"`
AppTitle *string `json:"appTitle,omitempty"` LoginLogo *string `json:"loginLogo,omitempty"`
LoginLogo *string `json:"loginLogo,omitempty"` MenuLogo *string `json:"menuLogo,omitempty"`
MenuLogo *string `json:"menuLogo,omitempty"` LoginBackground *string `json:"loginBackground,omitempty"`
LoginBackground *string `json:"loginBackground,omitempty"` LoginSubtitle *string `json:"loginSubtitle,omitempty"`
LoginSubtitle *string `json:"loginSubtitle,omitempty"` LoginBoxBackground *string `json:"loginBoxBackground,omitempty"`
LoginBoxBackground *string `json:"loginBoxBackground,omitempty"` LoadingLogo *string `json:"loadingLogo,omitempty"`
LoadingLogo *string `json:"loadingLogo,omitempty"` HideEdition *bool `json:"hideEdition,omitempty"`
HideEdition *bool `json:"hideEdition,omitempty"` PublicDashboard *FrontendSettingsPublicDashboardConfigDTO `json:"publicDashboard,omitempty"`
PublicDashboardFooter *FrontendSettingsPublicDashboardFooterConfigDTO `json:"publicDashboardFooter,omitempty"` // PR TODO: type this properly
} }
type FrontendSettingsSqlConnectionLimitsDTO struct { type FrontendSettingsSqlConnectionLimitsDTO struct {

@ -0,0 +1,37 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { useGetPublicDashboardConfig } from './usePublicDashboardConfig';
export const PublicDashboardFooter = function () {
const styles = useStyles2(getStyles);
const conf = useGetPublicDashboardConfig();
return conf.footerHide ? null : (
<div className={styles.footer}>
<a className={styles.link} href={conf.footerLink} target="_blank" rel="noreferrer noopener">
{conf.footerText} <img className={styles.logoImg} alt="" src={conf.footerLogo} />
</a>
</div>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
footer: css({
display: 'flex',
justifyContent: 'end',
height: '30px',
padding: theme.spacing(0, 2, 0, 1),
}),
link: css({
display: 'flex',
alignItems: 'center',
}),
logoImg: css({
height: '16px',
marginLeft: theme.spacing(0.5),
}),
});

@ -0,0 +1,55 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, useTheme2 } from '@grafana/ui';
const FOOTER_URL = 'https://grafana.com/?src=grafananet&cnt=public-dashboards';
const GRAFANA_LOGO_LIGHT_URL = 'public/img/grafana_text_logo_light.svg';
const GRAFANA_LOGO_DARK_URL = 'public/img/grafana_text_logo_dark.svg';
const GRAFANA_LOGO_DEFAULT_VALUE = 'grafana-logo';
export interface PublicDashboardCfg {
footerHide: boolean;
footerText: React.ReactNode;
footerLogo: string;
footerLink: string;
headerLogoHide: boolean;
}
const useGetConfig = (cfg?: PublicDashboardCfg) => {
const theme = useTheme2();
const styles = useStyles2(getStyles);
const { footerHide, footerText, footerLink, footerLogo, headerLogoHide } = cfg || {
footerHide: false,
footerText: 'Powered by',
footerLogo: GRAFANA_LOGO_DEFAULT_VALUE,
footerLink: FOOTER_URL,
headerLogoHide: false,
};
return {
footerHide,
footerText: <span className={styles.text}>{footerText}</span>,
footerLogo:
footerLogo === GRAFANA_LOGO_DEFAULT_VALUE
? theme.isDark
? GRAFANA_LOGO_LIGHT_URL
: GRAFANA_LOGO_DARK_URL
: footerLogo,
footerLink,
headerLogoHide,
};
};
export let useGetPublicDashboardConfig = (): PublicDashboardCfg => useGetConfig();
export function setPublicDashboardConfigFn(cfg: PublicDashboardCfg) {
useGetPublicDashboardConfig = (): PublicDashboardCfg => useGetConfig(cfg);
}
const getStyles = (theme: GrafanaTheme2) => ({
text: css({
color: theme.colors.text.secondary,
fontSize: theme.typography.body.fontSize,
}),
});

@ -1,54 +0,0 @@
import { css } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
export interface PublicDashboardFooterCfg {
hide: boolean;
text: string;
logo: string;
link: string;
}
export const PublicDashboardFooter = function () {
const styles = useStyles2(getStyles);
const conf = getPublicDashboardFooterConfig();
return conf.hide ? null : (
<div className={styles.footer}>
<a className={styles.link} href={conf.link} target="_blank" rel="noreferrer noopener">
{conf.text} <img className={styles.logoImg} alt="" src={conf.logo}></img>
</a>
</div>
);
};
export function setPublicDashboardFooterConfigFn(fn: typeof getPublicDashboardFooterConfig) {
getPublicDashboardFooterConfig = fn;
}
export let getPublicDashboardFooterConfig = (): PublicDashboardFooterCfg => ({
hide: false,
text: 'powered by Grafana',
logo: 'public/img/grafana_icon.svg',
link: 'https://grafana.com/',
});
const getStyles = (theme: GrafanaTheme2) => ({
footer: css`
display: flex;
justify-content: end;
height: 30px;
padding: ${theme.spacing(0, 2, 0, 1)};
`,
link: css`
display: flex;
gap: 4px;
justify-content: end;
align-items: center;
`,
logoImg: css`
height: 100%;
padding: ${theme.spacing(0.25, 0, 0.5, 0)};
`,
});

@ -14,7 +14,8 @@ import { useSelector, useDispatch } from 'app/types';
import { DashNavTimeControls } from '../components/DashNav/DashNavTimeControls'; import { DashNavTimeControls } from '../components/DashNav/DashNavTimeControls';
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed'; import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading'; import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
import { PublicDashboardFooter } from '../components/PublicDashboardFooter/PublicDashboardsFooter'; import { PublicDashboardFooter } from '../components/PublicDashboard/PublicDashboardsFooter';
import { useGetPublicDashboardConfig } from '../components/PublicDashboard/usePublicDashboardConfig';
import { PublicDashboardNotAvailable } from '../components/PublicDashboardNotAvailable/PublicDashboardNotAvailable'; import { PublicDashboardNotAvailable } from '../components/PublicDashboardNotAvailable/PublicDashboardNotAvailable';
import { DashboardGrid } from '../dashgrid/DashboardGrid'; import { DashboardGrid } from '../dashgrid/DashboardGrid';
import { getTimeSrv } from '../services/TimeSrv'; import { getTimeSrv } from '../services/TimeSrv';
@ -37,13 +38,18 @@ const selectors = e2eSelectors.pages.PublicDashboard;
const Toolbar = ({ dashboard }: { dashboard: DashboardModel }) => { const Toolbar = ({ dashboard }: { dashboard: DashboardModel }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const conf = useGetPublicDashboardConfig();
const onChangeTimeZone = (timeZone: TimeZone) => { const onChangeTimeZone = (timeZone: TimeZone) => {
dispatch(updateTimeZoneForSession(timeZone)); dispatch(updateTimeZoneForSession(timeZone));
}; };
return ( return (
<PageToolbar title={dashboard.title} buttonOverflowAlignment="right"> <PageToolbar
title={dashboard.title}
pageIcon={!conf.headerLogoHide ? 'grafana' : undefined}
buttonOverflowAlignment="right"
>
{!dashboard.timepicker.hidden && ( {!dashboard.timepicker.hidden && (
<DashNavTimeControls dashboard={dashboard} onChangeTimeZone={onChangeTimeZone} /> <DashNavTimeControls dashboard={dashboard} onChangeTimeZone={onChangeTimeZone} />
)} )}

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 394 92.9" style="enable-background:new 0 0 394 92.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:#414142;}
.st1{fill:url(#SVGID_1_);}
</style>
<g>
<path class="st0" d="M160.7,50.1C160.1,66.3,147.3,79,131.4,79c-16.8,0-29.2-13.6-29.2-30c0-16.5,13.5-30.1,30-30.1
c7.4,0,14.7,3.2,20.9,8.9l-4.8,5.9c-4.7-4.1-10.4-6.9-16.1-6.9c-12.1,0-22,9.9-22,22.1c0,12.4,9.3,22,21.3,22
c10.7,0,19.1-7.8,20.8-17.9h-24.3V46h32.8L160.7,50.1L160.7,50.1z"/>
<path class="st0" d="M188.6,46.2h-4.5c-4.9,0-8.9,4-8.9,9v23.3h-8v-40h6.6v3.4c2.2-2.2,5.6-3.4,9.4-3.4h8.6L188.6,46.2z"/>
<path class="st0" d="M232.1,78.5h-6.8v-5c-5.2,5.1-13.5,7.6-21.9,3.9c-6.2-2.7-10.9-8.4-12.1-15.1c-2.4-12.9,7.6-24.4,20.3-24.4
c5.4,0,10.1,2.2,13.7,5.7v-5h6.9L232.1,78.5L232.1,78.5z M223.9,61.4c1.9-8.1-4.3-15.5-12.3-15.5c-6.9,0-12.6,5.7-12.6,12.5
c0,7.8,6.8,13.8,14.8,12.4C218.8,70,222.8,66.2,223.9,61.4z"/>
<path class="st0" d="M248.2,36.3v2.2h12.7v7h-12.7v32.9h-7.9v-42c0-8.8,6.3-14,14.2-14h9.6l-3.2,7.5h-6.4
C251,30.1,248.2,32.9,248.2,36.3z"/>
<path class="st0" d="M303.3,78.5h-6.8v-5c-5.2,5.1-13.5,7.6-21.9,3.9c-6.2-2.7-10.9-8.4-12.1-15.1c-2.4-12.9,7.6-24.4,20.3-24.4
c5.4,0,10.1,2.2,13.7,5.7v-5h6.9L303.3,78.5L303.3,78.5z M295.1,61.4c1.9-8.1-4.3-15.5-12.3-15.5c-7,0-12.5,5.7-12.5,12.5
c0,7.8,6.8,13.8,14.8,12.4C290,70,294,66.2,295.1,61.4z"/>
<path class="st0" d="M346,54.8v23.7h-8V54.8c0-5-4.1-9-9-9c-5,0-9,4-9,9v23.7h-8v-40h6.6V42c2.9-2.6,6.7-4.1,10.7-4.1
C338.6,37.9,346,45.5,346,54.8z"/>
<path class="st0" d="M393,78.5h-6.8v-5c-5.2,5.1-13.5,7.6-21.9,3.9c-6.2-2.7-10.9-8.4-12.1-15.1c-2.4-12.9,7.6-24.4,20.3-24.4
c5.4,0,10.1,2.2,13.7,5.7v-5h6.9L393,78.5L393,78.5z M384.8,61.4c1.9-8.1-4.3-15.5-12.3-15.5c-7,0-12.5,5.7-12.5,12.5
c0,7.8,6.8,13.8,14.8,12.4C379.6,70,383.6,66.2,384.8,61.4z"/>
</g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="42.81" y1="-19.8217" x2="42.81" y2="65.0744" gradientTransform="matrix(1 0 0 -1 0 94)">
<stop offset="0" style="stop-color:#FCEE1D"/>
<stop offset="1" style="stop-color:#F15A29"/>
</linearGradient>
<path class="st1" d="M85.4,41c-0.1-1.6-0.4-3.4-0.9-5.3c-0.5-2-1.3-4.1-2.4-6.4c-1.1-2.2-2.6-4.6-4.5-6.9c-0.7-0.9-1.6-1.8-2.4-2.6
c1.3-5.2-1.6-9.7-1.6-9.7c-5-0.3-8.2,1.6-9.4,2.4c-0.2-0.1-0.4-0.2-0.6-0.2c-0.8-0.4-1.7-0.7-2.6-0.9s-1.8-0.5-2.8-0.8
c-0.9-0.2-1.9-0.4-2.9-0.6c-0.2,0-0.3-0.1-0.5-0.1c-2.2-7-8.5-9.9-8.5-9.9c-7,4.4-8.3,10.6-8.3,10.6s0,0.1-0.1,0.4
c-0.4,0.1-0.8,0.2-1.2,0.3c-0.5,0.2-1.1,0.4-1.6,0.6c-0.5,0.2-1.1,0.4-1.6,0.6c-1,0.4-2.1,1-3.1,1.5c-1,0.6-2,1.2-2.9,1.8
c-0.1-0.1-0.2-0.1-0.2-0.1c-9.7-3.7-18.3,0.8-18.3,0.8C8.4,26.8,13,33.3,13.9,34.5c-0.2,0.6-0.4,1.3-0.6,1.9
c-0.7,2.3-1.2,4.7-1.6,7.2c-0.1,0.3-0.1,0.7-0.1,1.1C2.7,49.1,0,58.1,0,58.1c7.5,8.6,16.1,9.1,16.1,9.1c0,0,0,0,0,0
c1.1,2,2.4,3.8,3.8,5.6c0.6,0.7,1.2,1.4,1.9,2.1c-2.7,7.8,0.4,14.2,0.4,14.2c8.3,0.3,13.8-3.6,14.9-4.5c0.8,0.3,1.7,0.5,2.5,0.8
c2.5,0.7,5.2,1,7.8,1.2c0.7,0,1.3,0,2,0h0.3l0.2,0l0.4,0l0.4,0l0,0c3.9,5.6,10.8,6.4,10.8,6.4c4.9-5.2,5.2-10.3,5.2-11.4l0,0
c0,0,0,0,0-0.1c0-0.1,0-0.2,0-0.2l0,0c0-0.1,0-0.2,0-0.2c1-0.7,2-1.5,2.9-2.3c2-1.8,3.7-3.8,5.1-6c0.1-0.2,0.3-0.4,0.4-0.6
c5.5,0.3,9.4-3.4,9.4-3.4c-0.9-5.8-4.2-8.6-4.9-9.1l0,0c0,0,0,0-0.1,0s-0.1,0-0.1,0l0,0c0,0-0.1,0-0.1-0.1c0-0.3,0.1-0.7,0.1-1
c0-0.6,0.1-1.2,0.1-1.9v-0.5v-0.2v-0.1c0-0.2,0-0.1,0-0.2l0-0.4l0-0.5c0-0.2,0-0.3,0-0.5c0-0.2,0-0.3-0.1-0.5l-0.1-0.5l-0.1-0.5
c-0.1-0.6-0.2-1.3-0.4-1.9c-0.6-2.5-1.6-4.8-2.8-7c-1.3-2.1-2.9-4-4.7-5.6c-1.8-1.6-3.8-2.9-5.9-3.8s-4.3-1.6-6.5-1.8
c-1.1-0.1-2.2-0.2-3.3-0.2l-0.4,0h-0.1c0,0-0.2,0-0.1,0l-0.2,0l-0.4,0c-0.2,0-0.3,0-0.5,0c-0.6,0-1.1,0.1-1.7,0.2
c-2.2,0.4-4.3,1.2-6.1,2.3c-1.8,1.1-3.4,2.5-4.7,4c-1.3,1.5-2.3,3.3-3,5s-1.1,3.6-1.2,5.4c0,0.4,0,0.9,0,1.3c0,0.1,0,0.2,0,0.3
l0,0.4c0,0.2,0,0.4,0,0.6c0.1,0.9,0.2,1.8,0.5,2.6c0.5,1.7,1.2,3.2,2.2,4.5c1,1.3,2.1,2.3,3.3,3.2c1.2,0.8,2.5,1.4,3.8,1.8
c1.3,0.4,2.5,0.5,3.8,0.5c0.2,0,0.3,0,0.5,0c0.1,0,0.2,0,0.2,0s0.2,0,0.2,0c0.1,0,0.2,0,0.4,0c0,0,0.1,0,0.1,0l0.1,0
c0.1,0,0.2,0,0.2,0c0.2,0,0.3-0.1,0.4-0.1c0.1,0,0.3-0.1,0.4-0.1c0.3-0.1,0.5-0.1,0.8-0.2c0.5-0.2,1-0.4,1.5-0.6
c0.5-0.2,0.9-0.5,1.3-0.8c0.1-0.1,0.2-0.2,0.3-0.2c0.4-0.3,0.5-0.9,0.2-1.3c-0.3-0.4-0.8-0.5-1.2-0.2c-0.1,0-0.2,0.1-0.3,0.2
c-0.3,0.2-0.7,0.3-1.1,0.5c-0.4,0.1-0.8,0.2-1.2,0.3c-0.2,0-0.4,0.1-0.6,0.1c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0-0.3,0s-0.2,0-0.3,0
c-0.1,0-0.3,0-0.4,0c0,0-0.1,0,0,0h0l-0.1,0c-0.1,0-0.1,0-0.2,0c-0.1,0-0.2,0-0.3,0c-0.9-0.1-1.9-0.4-2.8-0.8
c-0.9-0.4-1.8-1-2.6-1.7s-1.5-1.6-2-2.5s-0.9-2-1.1-3.2c-0.1-0.6-0.1-1.2-0.1-1.7c0-0.2,0-0.3,0-0.5c0,0,0,0,0,0v-0.1l0-0.1
c0-0.1,0-0.2,0-0.2c0-0.3,0.1-0.6,0.1-0.9c0.4-2.5,1.7-4.9,3.6-6.7c0.5-0.5,1-0.9,1.5-1.2c0.5-0.4,1.1-0.7,1.7-1
c0.6-0.3,1.2-0.5,1.9-0.7c0.7-0.2,1.3-0.3,2-0.3c0.3,0,0.7,0,1,0c0.1,0,0.2,0,0.2,0l0.3,0l0.2,0c0.1,0,0,0,0,0h0.1l0.3,0
c0.7,0.1,1.5,0.2,2.2,0.3c1.4,0.3,2.8,0.8,4.2,1.6c2.6,1.5,4.8,3.7,6.2,6.4c0.7,1.4,1.2,2.8,1.4,4.3c0.1,0.4,0.1,0.8,0.1,1.1l0,0.3
l0,0.3c0,0.1,0,0.2,0,0.3c0,0.1,0,0.2,0,0.3v0.2l0,0.3c0,0.2,0,0.5,0,0.7c0,0.4-0.1,0.8-0.1,1.2c-0.1,0.4-0.1,0.8-0.2,1.2
c-0.1,0.4-0.2,0.8-0.3,1.2c-0.2,0.8-0.5,1.6-0.8,2.4c-0.6,1.5-1.4,3-2.4,4.4c-2,2.7-4.7,4.9-7.7,6.3c-1.5,0.7-3.2,1.2-4.8,1.5
c-0.8,0.1-1.7,0.2-2.5,0.2l-0.2,0h-0.1h-0.3h-0.4h-0.2c0.1,0,0,0,0,0h-0.1c-0.5,0-0.9,0-1.3-0.1c-1.8-0.1-3.6-0.4-5.3-0.9
s-3.4-1.2-5-2c-3.2-1.7-6-4-8.2-6.8c-1.1-1.4-2.1-2.9-2.9-4.5c-0.8-1.6-1.4-3.2-1.9-4.9c-0.5-1.7-0.8-3.4-0.9-5.2l0-0.3l0-0.1V50
v-0.1l0-0.3v-0.1v-0.1v-0.2l0-0.4v-0.1c0,0,0,0,0,0v-0.2c0-0.2,0-0.4,0-0.6c0-0.9,0.1-1.7,0.2-2.6c0.1-0.9,0.3-1.8,0.4-2.7
s0.4-1.8,0.6-2.6c0.5-1.7,1.1-3.4,1.8-4.9c1.5-3.1,3.4-5.9,5.6-8.1c0.6-0.6,1.2-1.1,1.8-1.6c0.6-0.5,1.2-1,1.9-1.4
c0.7-0.4,1.3-0.8,2-1.2c0.3-0.2,0.7-0.4,1-0.5c0.2-0.1,0.4-0.2,0.5-0.2s0.4-0.2,0.5-0.2c0.7-0.3,1.5-0.6,2.2-0.8
c0.2-0.1,0.4-0.1,0.6-0.2s0.4-0.1,0.6-0.2c0.4-0.1,0.8-0.2,1.2-0.3c0.2,0,0.4-0.1,0.6-0.1c0.2,0,0.4-0.1,0.6-0.1
c0.2,0,0.4-0.1,0.6-0.1l0.3,0l0.3,0c0.2,0,0.4-0.1,0.6-0.1c0.2,0,0.4,0,0.7-0.1c0.2,0,0.5-0.1,0.7-0.1c0.1,0,0.3,0,0.4,0l0.3,0
l0.1,0l0.2,0c0.2,0,0.4,0,0.7,0l0.3,0c0,0,0.1,0,0,0h0.1l0.1,0c0.2,0,0.4,0,0.6,0c0.8,0,1.5,0,2.2,0c1.5,0.1,3,0.2,4.4,0.5
c2.8,0.5,5.5,1.4,7.9,2.6c2.4,1.2,4.6,2.6,6.5,4.2c0.1,0.1,0.2,0.2,0.3,0.3c0.1,0.1,0.2,0.2,0.3,0.3c0.2,0.2,0.4,0.4,0.7,0.6
s0.4,0.4,0.6,0.6c0.2,0.2,0.4,0.4,0.6,0.6c0.8,0.9,1.5,1.7,2.2,2.6c1.3,1.7,2.4,3.5,3.3,5.1c0.1,0.1,0.1,0.2,0.2,0.3
c0.1,0.1,0.1,0.2,0.2,0.3c0.1,0.2,0.2,0.4,0.3,0.6c0.1,0.2,0.2,0.4,0.3,0.6c0.1,0.2,0.2,0.4,0.2,0.6c0.3,0.8,0.6,1.5,0.8,2.2
c0.4,1.1,0.7,2.1,0.9,3c0.1,0.3,0.4,0.6,0.8,0.5c0.4,0,0.7-0.3,0.7-0.7C85.6,43.4,85.5,42.3,85.4,41z"/>
</svg>

After

Width:  |  Height:  |  Size: 6.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

Loading…
Cancel
Save