[Home] first homepage template to storybook + two more home components (#8434)

* add new toolkit component

Signed-off-by: Emma Indal <emmai@spotify.com>

* add toolkit content test

Signed-off-by: Emma Indal <emmai@spotify.com>

* add key to toolkit items

Signed-off-by: Emma Indal <emmai@spotify.com>

* add reusable company logo component

Signed-off-by: Emma Indal <emmai@spotify.com>

* export root ref from search plugin

Signed-off-by: Emma Indal <emmai@spotify.com>

* add homepage template to storybook

Signed-off-by: Emma Indal <emmai@spotify.com>

* export new homepage components from plugin

Signed-off-by: Emma Indal <emmai@spotify.com>

* fix imports

Signed-off-by: Emma Indal <emmai@spotify.com>

* add search plugin to dependencies

Signed-off-by: Emma Indal <emmai@spotify.com>

* add home plugin changeset

Signed-off-by: Emma Indal <emmai@spotify.com>

* add storybook changeset

Signed-off-by: Emma Indal <emmai@spotify.com>

* delete changeset for storybook

Signed-off-by: Emma Indal <emma.indahl@gmail.com>

* delete duplicated search context provider

Signed-off-by: Emma Indal <emmai@spotify.com>

* use list item text props

Signed-off-by: Emma Indal <emmai@spotify.com>

* update home plugin documentation + add customize app docs

Signed-off-by: Emma Indal <emmai@spotify.com>

* named exports

Signed-off-by: Emma Indal <emmai@spotify.com>

* add homepage components to storybook

Signed-off-by: Emma Indal <emmai@spotify.com>

* use app config as default for company logo

Signed-off-by: Emma Indal <emmai@spotify.com>

* rename homepage template

Signed-off-by: Emma Indal <emmai@spotify.com>

* use props instead of context for tools, update Content component of card extension to accept props

Signed-off-by: Emma Indal <emmai@spotify.com>

* fix api reports + docstrings + markers

Signed-off-by: Emma Indal <emmai@spotify.com>

* export ToolkitContentProps instead of Tool

Signed-off-by: Emma Indal <emmai@spotify.com>

* docs and stories fixups

Signed-off-by: Emma Indal <emmai@spotify.com>

* do not export rootRouteRef from search plugin

Signed-off-by: Emma Indal <emmai@spotify.com>

* update docs links

Signed-off-by: Emma Indal <emmai@spotify.com>

* change unpacking of props

Signed-off-by: Emma Indal <emmai@spotify.com>

* delete extra fragment

Signed-off-by: Emma Indal <emmai@spotify.com>

* fixup searchbar border styles

Signed-off-by: Emma Indal <emmai@spotify.com>
This commit is contained in:
Emma Indal
2022-01-10 11:40:07 +01:00
committed by GitHub
parent 5b516c1395
commit bdf1419d20
23 changed files with 833 additions and 33 deletions
+11 -7
View File
@@ -26,7 +26,7 @@ export type ComponentRenderer = {
};
type ComponentParts = {
Content: () => JSX.Element;
Content: (props?: any) => JSX.Element;
Actions?: () => JSX.Element;
Settings?: () => JSX.Element;
ContextProvider?: (props: any) => JSX.Element;
@@ -34,6 +34,13 @@ type ComponentParts = {
type RendererProps = { title: string } & ComponentParts;
type CardExtensionProps<T> = ComponentRenderer & { title?: string } & T;
/**
* An extension creator to create card based components for the homepage
*
* @public
*/
export function createCardExtension<T>({
title,
components,
@@ -48,11 +55,8 @@ export function createCardExtension<T>({
component: {
lazy: () =>
components().then(({ Content, Actions, Settings, ContextProvider }) => {
const CardExtension = ({
Renderer,
title: overrideTitle,
...childProps
}: ComponentRenderer & { title?: string } & T) => {
const CardExtension = (props: CardExtensionProps<T>) => {
const { Renderer, title: overrideTitle, ...childProps } = props;
const app = useApp();
const { Progress } = app.getComponents();
const [settingsOpen, setSettingsOpen] = React.useState(false);
@@ -103,7 +107,7 @@ export function createCardExtension<T>({
<Settings />
</SettingsModal>
)}
<Content />
<Content {...childProps} />
</InfoCard>
);
@@ -0,0 +1,79 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TemplateBackstageLogo } from '../../templates';
import { HomePageCompanyLogo } from '../../plugin';
import { rootRouteRef } from '../../routes';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/core-app-api';
import { Grid, makeStyles } from '@material-ui/core';
import React, { ComponentType } from 'react';
export default {
title: 'Plugins/Home/Components/CompanyLogo',
decorators: [
(Story: ComponentType<{}>) =>
wrapInTestApp(
<TestApiProvider
apis={[
[configApiRef, new ConfigReader({ app: { title: 'My App' } })],
]}
>
<Story />
</TestApiProvider>,
{
mountedRoutes: { '/hello-company-logo': rootRouteRef },
},
),
],
};
const useLogoStyles = makeStyles(theme => ({
container: {
margin: theme.spacing(5, 0),
},
svg: {
width: 'auto',
height: 100,
},
path: {
fill: '#7df3e1',
},
}));
export const Default = () => {
const { container } = useLogoStyles();
return (
<Grid container justifyContent="center" spacing={6}>
<HomePageCompanyLogo className={container} />
</Grid>
);
};
export const CustomLogo = () => {
const { container, svg, path } = useLogoStyles();
return (
<Grid container justifyContent="center" spacing={6}>
<HomePageCompanyLogo
className={container}
logo={<TemplateBackstageLogo classes={{ svg, path }} />}
/>
</Grid>
);
};
@@ -0,0 +1,43 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CompanyLogo } from './CompanyLogo';
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/core-app-api';
import { Typography } from '@material-ui/core';
import React from 'react';
describe('<CompanyLogo>', () => {
it('should have a fall back if logo is not provided', async () => {
const { getByRole } = await renderInTestApp(
<TestApiProvider
apis={[[configApiRef, new ConfigReader({ app: { title: 'My App' } })]]}
>
<CompanyLogo />
</TestApiProvider>,
);
expect(getByRole('heading', { name: 'My App' })).toBeInTheDocument();
});
it('should show provided company logo', async () => {
const { getByRole } = await renderInTestApp(
<CompanyLogo logo={<Typography variant="h1">Backstage</Typography>} />,
);
expect(getByRole('heading', { name: 'Backstage' })).toBeInTheDocument();
});
});
@@ -0,0 +1,43 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Typography } from '@material-ui/core';
import { configApiRef, useApi } from '@backstage/core-plugin-api';
import React from 'react';
type CompanyLogoProps = {
logo?: React.ReactNode;
className?: string;
};
/**
* A component to display a company logo for the user.
*
* @public
*/
export const CompanyLogo = (props: CompanyLogoProps) => {
const { logo, className } = props;
const configApi = useApi(configApiRef);
return (
<div className={className}>
{logo ? (
<>{logo}</>
) : (
<Typography variant="h1">{configApi.getString('app.title')}</Typography>
)}
</div>
);
};
@@ -0,0 +1,16 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { CompanyLogo } from './CompanyLogo';
@@ -0,0 +1,36 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { renderInTestApp } from '@backstage/test-utils';
import React from 'react';
import { Content } from './Content';
describe('<ToolkitContent>', () => {
test('should render list of tools', async () => {
const { getByText } = await renderInTestApp(
<Content
tools={[
{ label: 'tool', url: '/url', icon: <div>icon</div> },
{ label: 'tool 2', url: '/url-2', icon: <div>icon 2</div> },
]}
/>,
);
expect(getByText('tool')).toBeInTheDocument();
expect(getByText('tool 2')).toBeInTheDocument();
expect(getByText('tool').closest('a')).toHaveAttribute('href', '/url');
expect(getByText('tool 2').closest('a')).toHaveAttribute('href', '/url-2');
});
});
@@ -0,0 +1,88 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Link } from '@backstage/core-components';
import {
makeStyles,
List,
ListItemIcon,
ListItemText,
} from '@material-ui/core';
import React from 'react';
const useStyles = makeStyles(theme => ({
toolkit: {
display: 'flex',
flexWrap: 'wrap',
textAlign: 'center',
},
tool: {
margin: theme.spacing(0.5, 1),
},
label: {
marginTop: theme.spacing(1),
fontSize: '0.9em',
lineHeight: '1.25',
color: theme.palette.text.secondary,
},
icon: {
width: '64px',
height: '64px',
borderRadius: '50px',
justifyContent: 'center',
alignItems: 'center',
boxShadow: theme.shadows[1],
backgroundColor: theme.palette.background.default,
},
}));
type Tool = {
label: string;
url: string;
icon: React.ReactNode;
};
/**
* Props for Toolkit content component {@link Content}.
*
* @public
*/
export type ToolkitContentProps = {
tools: Tool[];
};
/**
* A component to display a list of tools for the user.
*
* @public
*/
export const Content = (props: ToolkitContentProps) => {
const classes = useStyles();
return (
<List className={classes.toolkit}>
{props.tools.map((tool: Tool) => (
<Link key={tool.url} to={tool.url} className={classes.tool}>
<ListItemIcon className={classes.icon}>{tool.icon}</ListItemIcon>
<ListItemText
secondaryTypographyProps={{ className: classes.label }}
secondary={tool.label}
/>
</Link>
))}
</List>
);
};
@@ -0,0 +1,40 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TemplateBackstageLogoIcon } from '../../templates';
import { HomePageToolkit } from '../../plugin';
import { wrapInTestApp } from '@backstage/test-utils';
import { Grid } from '@material-ui/core';
import React, { ComponentType } from 'react';
export default {
title: 'Plugins/Home/Components/Toolkit',
decorators: [(Story: ComponentType<{}>) => wrapInTestApp(<Story />)],
};
export const Default = () => {
return (
<Grid item xs={12} md={6}>
<HomePageToolkit
tools={Array(8).fill({
url: '#',
label: 'link',
icon: <TemplateBackstageLogoIcon />,
})}
/>
</Grid>
);
};
@@ -0,0 +1,18 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Content } from './Content';
export type { ToolkitContentProps } from './Content';
@@ -0,0 +1,18 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './CompanyLogo';
export * from './Toolkit';
+2
View File
@@ -24,6 +24,8 @@ export {
homePlugin,
HomepageCompositionRoot,
HomePageRandomJoke,
HomePageToolkit,
HomePageCompanyLogo,
ComponentAccordion,
ComponentTabs,
ComponentTab,
+29
View File
@@ -19,6 +19,7 @@ import {
createRoutableExtension,
} from '@backstage/core-plugin-api';
import { createCardExtension } from './extensions';
import { ToolkitContentProps } from './homePageComponents';
import { rootRouteRef } from './routes';
@@ -79,6 +80,21 @@ export const WelcomeTitle = homePlugin.provide(
}),
);
/**
* A component to display a company logo for the user.
*
* @public
*/
export const HomePageCompanyLogo = homePlugin.provide(
createComponentExtension({
name: 'CompanyLogo',
component: {
lazy: () =>
import('./homePageComponents/CompanyLogo').then(m => m.CompanyLogo),
},
}),
);
export const HomePageRandomJoke = homePlugin.provide(
createCardExtension<{ defaultCategory?: 'any' | 'programming' }>({
name: 'HomePageRandomJoke',
@@ -86,3 +102,16 @@ export const HomePageRandomJoke = homePlugin.provide(
components: () => import('./homePageComponents/RandomJoke'),
}),
);
/**
* A component to display a list of tools for the user.
*
* @public
*/
export const HomePageToolkit = homePlugin.provide(
createCardExtension<ToolkitContentProps>({
name: 'HomePageToolkit',
title: 'Toolkit',
components: () => import('./homePageComponents/Toolkit'),
}),
);
@@ -0,0 +1,130 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {TemplateBackstageLogo} from './TemplateBackstageLogo';
import {TemplateBackstageLogoIcon} from './TemplateBackstageLogoIcon';
import { HomePageToolkit, HomePageCompanyLogo } from '../plugin';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { Content, Page, InfoCard } from '@backstage/core-components';
import {
HomePageSearchBar,
SearchContextProvider,
searchApiRef,
searchPlugin
} from '@backstage/plugin-search';
import { Grid, makeStyles } from '@material-ui/core';
import React, { ComponentType} from 'react';
export default {
title: 'Plugins/Home/Templates',
decorators: [
(Story: ComponentType<{}>) =>
wrapInTestApp(
<>
<TestApiProvider apis={[[searchApiRef, {query: () => Promise.resolve({results: []})}]]}>
<Story />
</TestApiProvider>
</>,
{
mountedRoutes: {'/hello-company': searchPlugin.routes.root }
}
),
],
};
const useStyles = makeStyles(theme => ({
search: {
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[1],
maxWidth: '60vw',
display: 'flex',
justifyContent: 'space-between',
padding: '8px 0',
borderColor: 'transparent',
borderRadius: '50px',
margin: 'auto',
},
}));
const useLogoStyles = makeStyles(theme => ({
container: {
margin: theme.spacing(5, 0),
},
svg: {
width: 'auto',
height: 100,
},
path: {
fill: '#7df3e1',
},
}));
export const DefaultTemplate = () => {
const { search } = useStyles();
const { svg, path, container } = useLogoStyles();
return (
<SearchContextProvider>
<Page themeId="home">
<Content>
<Grid container justifyContent="center" spacing={6}>
<HomePageCompanyLogo
className={container}
logo={<TemplateBackstageLogo classes={{svg, path}} />}
/>
<Grid container item xs={12} alignItems="center" direction="row">
<HomePageSearchBar
className={search}
placeholder="Search"
/>
</Grid>
<Grid container item xs={12}>
<Grid item xs={12} md={6}>
<InfoCard title="Composable Section">
{/* placeholder for content */}
<div style={{ height: 210 }} />
</InfoCard>
</Grid>
<Grid item xs={12} md={6}>
<HomePageToolkit
tools={Array(8).fill({
url: '#',
label: 'link',
icon: <TemplateBackstageLogoIcon />,
})}
/>
</Grid>
<Grid item xs={12} md={6}>
<InfoCard title="Composable Section">
{/* placeholder for content */}
<div style={{ height: 210 }} />
</InfoCard>
</Grid>
<Grid item xs={12} md={6}>
<InfoCard title="Composable Section">
{/* placeholder for content */}
<div style={{ height: 210 }} />
</InfoCard>
</Grid>
</Grid>
</Grid>
</Content>
</Page>
</SearchContextProvider>
);
};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,46 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { makeStyles } from '@material-ui/core';
const useStyles = makeStyles({
svg: {
width: 'auto',
height: 28,
},
path: {
fill: '#7df3e1',
},
});
export const TemplateBackstageLogoIcon = () => {
const classes = useStyles();
return (
<svg
className={classes.svg}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 337.46 428.5"
>
<path
className={classes.path}
d="M303,166.05a80.69,80.69,0,0,0,13.45-10.37c.79-.77,1.55-1.53,2.3-2.3a83.12,83.12,0,0,0,7.93-9.38A63.69,63.69,0,0,0,333,133.23a48.58,48.58,0,0,0,4.35-16.4c1.49-19.39-10-38.67-35.62-54.22L198.56,0,78.3,115.23,0,190.25l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.69,19.16-18.36,25.52-42.12,13.7-61.87a49.22,49.22,0,0,0-6.8-8.87A89.17,89.17,0,0,0,259,178.29h.15a85.08,85.08,0,0,0,31-5.79A80.88,80.88,0,0,0,303,166.05ZM202.45,225.86c-19.32,18.51-50.4,21.23-75.7,5.9L51.61,186.15l67.45-64.64,76.41,46.38C223,184.58,221.49,207.61,202.45,225.86Zm8.93-82.22-70.65-42.89L205.14,39,274.51,81.1c25.94,15.72,29.31,37,10.55,55A60.69,60.69,0,0,1,211.38,143.64Zm29.86,190c-19.57,18.75-46.17,29.09-74.88,29.09a123.73,123.73,0,0,1-64.1-18.2L0,282.52v24.67L108.6,373.1a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A87.27,87.27,0,0,1,241.24,333.68Zm0-39c-19.57,18.75-46.17,29.08-74.88,29.08a123.81,123.81,0,0,1-64.1-18.19L0,243.53v24.68l108.6,65.91a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.81,66.42-25.69,12.88-12.34,20-27.13,19.68-41.5v-1.78A87.27,87.27,0,0,1,241.24,294.7Zm0-39c-19.57,18.76-46.17,29.09-74.88,29.09a123.81,123.81,0,0,1-64.1-18.19L0,204.55v24.68l108.6,65.91a111.59,111.59,0,0,0,57.76,16.41c24.92,0,48.8-8.8,66.42-25.68,12.88-12.35,20-27.13,19.68-41.5v-1.82A86.09,86.09,0,0,1,241.24,255.71Zm83.7,25.74a94.15,94.15,0,0,1-60.2,25.86h0V334a81.6,81.6,0,0,0,51.74-22.37c14-13.38,21.14-28.11,21-42.64v-2.19A94.92,94.92,0,0,1,324.94,281.45Zm-83.7,91.21c-19.57,18.76-46.17,29.09-74.88,29.09a123.73,123.73,0,0,1-64.1-18.2L0,321.5v24.68l108.6,65.9a111.6,111.6,0,0,0,57.76,16.42c24.92,0,48.8-8.8,66.42-25.69,12.88-12.34,20-27.13,19.68-41.49v-1.79A86.29,86.29,0,0,1,241.24,372.66ZM327,162.45c-.68.69-1.35,1.38-2.05,2.06a94.37,94.37,0,0,1-10.64,8.65,91.35,91.35,0,0,1-11.6,7,94.53,94.53,0,0,1-26.24,8.71,97.69,97.69,0,0,1-14.16,1.57c.5,1.61.9,3.25,1.25,4.9a53.27,53.27,0,0,1,1.14,12V217h.05a84.41,84.41,0,0,0,25.35-5.55,81,81,0,0,0,26.39-16.82c.8-.77,1.5-1.56,2.26-2.34a82.08,82.08,0,0,0,7.93-9.38A63.76,63.76,0,0,0,333,172.17a48.55,48.55,0,0,0,4.32-16.45c.09-1.23.2-2.47.19-3.7V150q-1.08,1.54-2.25,3.09A96.73,96.73,0,0,1,327,162.45Zm0,77.92c-.69.7-1.31,1.41-2,2.1a94.2,94.2,0,0,1-60.2,25.86h0l0,26.67h0a81.6,81.6,0,0,0,51.74-22.37A73.51,73.51,0,0,0,333,250.13a48.56,48.56,0,0,0,4.32-16.44c.09-1.24.2-2.47.19-3.71v-2.19c-.74,1.07-1.46,2.15-2.27,3.21A95.68,95.68,0,0,1,327,240.37Zm0-39c-.69.7-1.31,1.41-2,2.1a93.18,93.18,0,0,1-10.63,8.65,91.63,91.63,0,0,1-11.63,7,95.47,95.47,0,0,1-37.94,10.18h0V256h0a81.65,81.65,0,0,0,51.74-22.37c.8-.77,1.5-1.56,2.26-2.34a82.08,82.08,0,0,0,7.93-9.38A63.76,63.76,0,0,0,333,211.15a48.56,48.56,0,0,0,4.32-16.44c.09-1.24.2-2.48.19-3.71v-2.2c-.74,1.08-1.46,2.16-2.27,3.22A95.68,95.68,0,0,1,327,201.39Z"
/>
</svg>
);
};
+18
View File
@@ -0,0 +1,18 @@
/*
* Copyright 2021 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { TemplateBackstageLogoIcon } from './TemplateBackstageLogoIcon';
export { TemplateBackstageLogo } from './TemplateBackstageLogo'