feat: Extract reusable block & add catalog section to home page
Signed-off-by: Carlos Esteban Lopez <lcarlosesteb@vmware.com>
This commit is contained in:
committed by
Carlos Lopez
parent
c0e0bcc137
commit
2c21d5f6c5
@@ -0,0 +1,43 @@
|
||||
.bannerSection {
|
||||
display: block;
|
||||
|
||||
&:global(.greyBackground) {
|
||||
background: linear-gradient(90.49deg, #121212 15.36%, #282828 70.44%);
|
||||
}
|
||||
|
||||
&:global(.greenGradientBackground) {
|
||||
background: linear-gradient(
|
||||
178.64deg,
|
||||
hsla(0, 0%, 100%, 0) 57.61%,
|
||||
hsla(0, 0%, 100%, 0.17) 127.71%
|
||||
),
|
||||
linear-gradient(
|
||||
144.35deg,
|
||||
rgba(98, 197, 179, 0) 56.68%,
|
||||
rgba(98, 197, 179, 0.59) 109.25%
|
||||
),
|
||||
linear-gradient(
|
||||
192.29deg,
|
||||
rgba(155, 240, 225, 0) 54.17%,
|
||||
rgba(155, 240, 225, 0.67) 137.34%
|
||||
);
|
||||
}
|
||||
|
||||
&:global(.greenBottomGradientBackground) {
|
||||
background: linear-gradient(
|
||||
178.64deg,
|
||||
hsla(0, 0%, 100%, 0) 57.61%,
|
||||
hsla(0, 0%, 100%, 0.17) 127.71%
|
||||
),
|
||||
linear-gradient(
|
||||
144.35deg,
|
||||
rgba(98, 197, 179, 0) 56.68%,
|
||||
rgba(98, 197, 179, 0.59) 109.25%
|
||||
),
|
||||
linear-gradient(
|
||||
192.29deg,
|
||||
rgba(155, 240, 225, 0) 54.17%,
|
||||
rgba(155, 240, 225, 0.67) 137.34%
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
import bannerColumnStyles from './banner-section-columns.module.scss';
|
||||
|
||||
export type IBannerSectionColumnsProps = PropsWithChildren<{
|
||||
header?: ReactNode;
|
||||
// children: ReactNode | ReactNode[];
|
||||
}>;
|
||||
|
||||
export const BannerSectionColumns = ({
|
||||
header,
|
||||
children,
|
||||
}: IBannerSectionColumnsProps) => (
|
||||
<>
|
||||
{header && (
|
||||
<div className="row padding-vert--lg">
|
||||
<div className="col">{header}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{Array.isArray(children) ? (
|
||||
<div className="row">
|
||||
{children.map((child, index) => (
|
||||
<div key={index} className="col padding-bottom--lg">
|
||||
{child}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -0,0 +1,29 @@
|
||||
.bannerSection {
|
||||
display: block;
|
||||
|
||||
&:global(.greyBackground) {
|
||||
background: linear-gradient(90.49deg, #121212 15.36%, #282828 70.44%);
|
||||
}
|
||||
|
||||
&:global(.greenGradientBackground) {
|
||||
background: linear-gradient(70.44deg, #121212 55%, #5d817b);
|
||||
}
|
||||
|
||||
&:global(.greenBottomGradientBackground) {
|
||||
background: linear-gradient(
|
||||
178.64deg,
|
||||
hsla(0, 0%, 100%, 0) 57.61%,
|
||||
hsla(0, 0%, 100%, 0.17) 127.71%
|
||||
),
|
||||
linear-gradient(
|
||||
144.35deg,
|
||||
rgba(98, 197, 179, 0) 56.68%,
|
||||
rgba(98, 197, 179, 0.59) 109.25%
|
||||
),
|
||||
linear-gradient(
|
||||
192.29deg,
|
||||
rgba(155, 240, 225, 0) 54.17%,
|
||||
rgba(155, 240, 225, 0.67) 137.34%
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { PropsWithChildren } from 'react';
|
||||
|
||||
import bannerStyles from './banner-section.module.scss';
|
||||
|
||||
export type IBannerSectionProps = PropsWithChildren<{
|
||||
greyBackground?: boolean;
|
||||
greenGradientBackground?: boolean;
|
||||
greenBottomGradientBackground?: boolean;
|
||||
}>;
|
||||
|
||||
export const BannerSection = ({
|
||||
children,
|
||||
greyBackground = false,
|
||||
greenGradientBackground = false,
|
||||
greenBottomGradientBackground = false,
|
||||
}: IBannerSectionProps) => (
|
||||
<section
|
||||
className={clsx(bannerStyles.bannerSection, {
|
||||
greyBackground,
|
||||
greenGradientBackground,
|
||||
greenBottomGradientBackground,
|
||||
})}
|
||||
>
|
||||
<div className="container">{children}</div>
|
||||
</section>
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
.contentBlock {
|
||||
gap: 1.5rem;
|
||||
display: grid;
|
||||
|
||||
> *,
|
||||
h1,
|
||||
h2 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:global(.bulletLine) {
|
||||
width: 50px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
:global(.actionButtons) {
|
||||
gap: 1rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, auto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import Link from '@docusaurus/Link';
|
||||
import clsx from 'clsx';
|
||||
import React, { FC, PropsWithChildren, ReactNode } from 'react';
|
||||
|
||||
import contentBlockStyles from './content-block.module.scss';
|
||||
|
||||
export interface ContentBlockActionButtonProps {
|
||||
label: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export type IContentBlockProps = PropsWithChildren<{
|
||||
title?: ReactNode;
|
||||
className?: string;
|
||||
topImgSrc?: string;
|
||||
hasBulletLine?: boolean;
|
||||
actionButtons?: ContentBlockActionButtonProps[];
|
||||
}>;
|
||||
|
||||
export const ContentBlock = ({
|
||||
children,
|
||||
title,
|
||||
className,
|
||||
topImgSrc,
|
||||
hasBulletLine,
|
||||
actionButtons,
|
||||
}: IContentBlockProps) => {
|
||||
return (
|
||||
<div className={clsx(className, contentBlockStyles.contentBlock)}>
|
||||
{topImgSrc && <img src={topImgSrc} alt={topImgSrc} />}
|
||||
|
||||
<div className="contentBlockTitle">
|
||||
{hasBulletLine && <div className="bulletLine" />}
|
||||
|
||||
{title && React.isValidElement(title) ? title : <h2>{title}</h2>}
|
||||
</div>
|
||||
|
||||
{children && <p>{children}</p>}
|
||||
|
||||
{actionButtons && (
|
||||
<div className="actionButtons">
|
||||
{actionButtons.map(({ link, label }, index) => (
|
||||
<Link
|
||||
key={index}
|
||||
className="button button--primary button--lg"
|
||||
to={link}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -4,17 +4,20 @@ import Layout from '@theme/Layout';
|
||||
import { clsx } from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import { BannerSection } from '../../components/banner-section/banner-section';
|
||||
import homeStyles from './home.module.scss';
|
||||
import { BannerSectionColumns } from '../../components/banner-section/banner-section-columns';
|
||||
import { ContentBlock } from '@site/src/components/content-block/content-block';
|
||||
|
||||
export function Home() {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<section className={homeStyles.homePage}>
|
||||
<div className="container">
|
||||
<div className="row padding-vert--lg">
|
||||
<div className="col">
|
||||
<div className={homeStyles.homePage}>
|
||||
<BannerSection greyBackground>
|
||||
<BannerSectionColumns
|
||||
header={
|
||||
<div
|
||||
className={clsx(
|
||||
'card',
|
||||
@@ -35,36 +38,28 @@ export function Home() {
|
||||
|
||||
<div className="bannerCloseButton">X</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<ContentBlock
|
||||
className={homeStyles.openPlatformBanner}
|
||||
title={<h1> An open platform for building developer portals</h1>}
|
||||
actionButtons={[
|
||||
{
|
||||
link: 'https://github.com/backstage/backstage#getting-started',
|
||||
label: 'GITHUB',
|
||||
},
|
||||
{
|
||||
link: 'https://info.backstage.spotify.com/office-hours',
|
||||
label: 'OFFICE HOURS',
|
||||
},
|
||||
]}
|
||||
>
|
||||
Powered by a centralized software catalog, Backstage restores
|
||||
order to your infrastructure and enables your product teams to
|
||||
ship high-quality code quickly — without compromising autonomy.
|
||||
</ContentBlock>
|
||||
|
||||
<div className={clsx('row', homeStyles.openPlatformBanner)}>
|
||||
<div className="col padding-bottom--lg">
|
||||
<h1>An open platform for building developer portals</h1>
|
||||
|
||||
<p>
|
||||
Powered by a centralized software catalog, Backstage restores
|
||||
order to your infrastructure and enables your product teams to
|
||||
ship high-quality code quickly — without compromising autonomy.
|
||||
</p>
|
||||
|
||||
<div className="buttonsContainer">
|
||||
<Link
|
||||
to="https://github.com/backstage/backstage#getting-started"
|
||||
className="button button--primary"
|
||||
>
|
||||
GITHUB
|
||||
</Link>
|
||||
<Link
|
||||
to="https://info.backstage.spotify.com/office-hours"
|
||||
className="button button--primary"
|
||||
>
|
||||
OFFICE HOURS
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="col padding-bottom--lg svgContainer">
|
||||
<div className={homeStyles.svgContainer}>
|
||||
<img
|
||||
className="laptopSvg"
|
||||
src={`${siteConfig.baseUrl}img/laptop.svg`}
|
||||
@@ -74,9 +69,96 @@ export function Home() {
|
||||
src={`${siteConfig.baseUrl}animations/backstage-logos-hero-8.gif`}
|
||||
/>
|
||||
</div>
|
||||
</BannerSectionColumns>
|
||||
</BannerSection>
|
||||
|
||||
<BannerSection>
|
||||
<BannerSectionColumns>
|
||||
<ContentBlock
|
||||
title="The Speed Paradox"
|
||||
topImgSrc={`${siteConfig.baseUrl}animations/backstage-speed-paradox-7.gif`}
|
||||
>
|
||||
At Spotify, we've always believed in the speed and ingenuity that
|
||||
comes from having autonomous development teams. But as we learned
|
||||
firsthand, the faster you grow, the more fragmented and complex
|
||||
your software ecosystem becomes. And then everything slows down
|
||||
again.
|
||||
</ContentBlock>
|
||||
|
||||
<ContentBlock
|
||||
title="The Standards Paradox"
|
||||
topImgSrc={`${siteConfig.baseUrl}animations/backstage-standards-paradox-4.gif`}
|
||||
>
|
||||
By centralizing services and standardizing your tooling, Backstage
|
||||
streamlines your development environment from end to end. Instead
|
||||
of restricting autonomy, standardization frees your engineers from
|
||||
infrastructure complexity. So you can return to building and
|
||||
scaling, quickly and safely.
|
||||
</ContentBlock>
|
||||
</BannerSectionColumns>
|
||||
</BannerSection>
|
||||
|
||||
<BannerSection greenGradientBackground>
|
||||
<div className={homeStyles.catalogContainer}>
|
||||
<div className="catalogTitle">
|
||||
<img
|
||||
src={`${siteConfig.baseUrl}animations/backstage-software-catalog-icon-1.gif`}
|
||||
alt="Software Catalog Planet GIF"
|
||||
/>
|
||||
|
||||
<h2 className="text--primary">Backstage Software Catalog</h2>
|
||||
|
||||
<h1>Build an ecosystem, not a wilderness</h1>
|
||||
</div>
|
||||
|
||||
<picture className="catalogImg">
|
||||
<source
|
||||
srcSet={`${siteConfig.baseUrl}img/components-with-filter.png`}
|
||||
media="(min-width: 997px)"
|
||||
/>
|
||||
<img
|
||||
src={`${siteConfig.baseUrl}img/components-with-filter-small.png`}
|
||||
alt=""
|
||||
/>
|
||||
</picture>
|
||||
|
||||
<ContentBlock
|
||||
title="Manage all your software, all in one place"
|
||||
hasBulletLine
|
||||
>
|
||||
Backstage makes it easy for one team to manage 10 services — and
|
||||
makes it possible for your company to manage thousands of them
|
||||
</ContentBlock>
|
||||
|
||||
<ContentBlock
|
||||
title="Backstage makes it easy for one team to manage 10 services — and makes it possible for your company to manage thousands of them"
|
||||
hasBulletLine
|
||||
>
|
||||
Every team can see all the services they own and related resources
|
||||
(deployments, data pipelines, pull request status, etc.)
|
||||
</ContentBlock>
|
||||
|
||||
<ContentBlock title="Metadata on tap" hasBulletLine>
|
||||
All that information can be shared with plugins inside Backstage
|
||||
to enable other management features, like resource monitoring and
|
||||
testing
|
||||
</ContentBlock>
|
||||
|
||||
<ContentBlock title="Not just services" hasBulletLine>
|
||||
Libraries, websites, ML models — you name it, Backstage knows all
|
||||
about it, including who owns it, dependencies, and more
|
||||
</ContentBlock>
|
||||
|
||||
<ContentBlock
|
||||
title="Discoverability & accountability"
|
||||
hasBulletLine
|
||||
>
|
||||
No more orphan software hiding in the dark corners of your tech
|
||||
stack
|
||||
</ContentBlock>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</BannerSection>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,19 +26,41 @@
|
||||
}
|
||||
}
|
||||
|
||||
.openPlatformBanner {
|
||||
:global(.svgContainer) {
|
||||
position: relative;
|
||||
.svgContainer {
|
||||
position: relative;
|
||||
|
||||
:global(img.laptopSvg) {
|
||||
width: 100%;
|
||||
}
|
||||
:global(img.laptopSvg) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:global(img.laptopScreenGif) {
|
||||
position: absolute;
|
||||
top: 3%;
|
||||
left: 17%;
|
||||
width: 70%;
|
||||
:global(img.laptopScreenGif) {
|
||||
position: absolute;
|
||||
top: 3%;
|
||||
left: 17%;
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
|
||||
.catalogContainer {
|
||||
gap: 2rem;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
|
||||
picture {
|
||||
display: block;
|
||||
|
||||
grid-row: 1/3;
|
||||
grid-column: 3/-1;
|
||||
}
|
||||
|
||||
:global(.catalogTitle) {
|
||||
grid-column: 1/3;
|
||||
|
||||
img {
|
||||
max-width: 190px;
|
||||
max-height: 190px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user