Setting up Canon
Signed-off-by: Charles de Dreuille <charles.dedreuille@gmail.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname), {
|
||||
extends: ['plugin:storybook/recommended'],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import type { StorybookConfig } from '@storybook/react-webpack5';
|
||||
const { VanillaExtractPlugin } = require('@vanilla-extract/webpack-plugin');
|
||||
import { merge } from 'webpack-merge';
|
||||
|
||||
import { join, dirname } from 'path';
|
||||
|
||||
/**
|
||||
* This function is used to resolve the absolute path of a package.
|
||||
* It is needed in projects that use Yarn PnP or are set up within a monorepo.
|
||||
*/
|
||||
function getAbsolutePath(value: string): any {
|
||||
return dirname(require.resolve(join(value, 'package.json')));
|
||||
}
|
||||
const config: StorybookConfig = {
|
||||
stories: [
|
||||
'../src/docs/**/*.mdx',
|
||||
'../src/components/**/*.mdx',
|
||||
'../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)',
|
||||
],
|
||||
staticDirs: ['../static'],
|
||||
addons: [
|
||||
getAbsolutePath('@storybook/addon-webpack5-compiler-swc'),
|
||||
getAbsolutePath('@storybook/addon-onboarding'),
|
||||
getAbsolutePath('@storybook/addon-essentials'),
|
||||
getAbsolutePath('@chromatic-com/storybook'),
|
||||
getAbsolutePath('@storybook/addon-interactions'),
|
||||
// getAbsolutePath("@storybook/addon-styling-webpack")
|
||||
],
|
||||
framework: {
|
||||
name: getAbsolutePath('@storybook/react-webpack5'),
|
||||
options: {
|
||||
plugins: [new VanillaExtractPlugin()],
|
||||
},
|
||||
},
|
||||
webpackFinal: config => {
|
||||
return merge(config, {
|
||||
plugins: [new VanillaExtractPlugin()],
|
||||
});
|
||||
},
|
||||
};
|
||||
export default config;
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import type { Preview, ReactRenderer } from '@storybook/react';
|
||||
import {
|
||||
withThemeByClassName,
|
||||
withThemeByDataAttribute,
|
||||
} from '@storybook/addon-themes';
|
||||
|
||||
import '../src/theme/styles.css';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
backgrounds: {
|
||||
disable: true,
|
||||
},
|
||||
},
|
||||
decorators: [
|
||||
withThemeByDataAttribute<ReactRenderer>({
|
||||
themes: {
|
||||
light: 'light',
|
||||
dark: 'dark',
|
||||
},
|
||||
defaultTheme: 'light',
|
||||
}),
|
||||
(Story, context) => {
|
||||
const theme = context.globals.theme || 'light';
|
||||
const backgroundColor = theme === 'light' ? '#ffffff' : '#000000';
|
||||
|
||||
document.body.style.backgroundColor = backgroundColor;
|
||||
|
||||
const docsStoryElements = document.getElementsByClassName('docs-story');
|
||||
Array.from(docsStoryElements).forEach(element => {
|
||||
(element as HTMLElement).style.backgroundColor = backgroundColor;
|
||||
});
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -0,0 +1,12 @@
|
||||
# @backstage/canon
|
||||
|
||||
_This package was created through the Backstage CLI_.
|
||||
|
||||
## Installation
|
||||
|
||||
Install the package via Yarn:
|
||||
|
||||
```sh
|
||||
cd <package-dir> # if within a monorepo
|
||||
yarn add @backstage/canon
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-canon
|
||||
title: '@backstage/canon'
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-web-library
|
||||
owner: maintainers
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"name": "@backstage/canon",
|
||||
"version": "0.0.0",
|
||||
"backstage": {
|
||||
"role": "web-library"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"keywords": [
|
||||
"backstage"
|
||||
],
|
||||
"homepage": "https://backstage.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "packages/canon"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"test": "backstage-cli package test",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@base_ui/react": "^1.0.0-alpha.3",
|
||||
"@vanilla-extract/css": "^1.16.0",
|
||||
"@vanilla-extract/dynamic": "^2.1.2",
|
||||
"@vanilla-extract/recipes": "^0.5.5",
|
||||
"@vanilla-extract/sprinkles": "^1.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@chromatic-com/storybook": "^3.2.2",
|
||||
"@eslint/js": "^9.13.0",
|
||||
"@storybook/addon-essentials": "^8.4.4",
|
||||
"@storybook/addon-interactions": "^8.4.4",
|
||||
"@storybook/addon-onboarding": "^8.4.4",
|
||||
"@storybook/addon-styling-webpack": "^1.0.1",
|
||||
"@storybook/addon-themes": "^8.4.4",
|
||||
"@storybook/addon-webpack5-compiler-swc": "^1.0.5",
|
||||
"@storybook/blocks": "^8.4.4",
|
||||
"@storybook/react": "^8.4.4",
|
||||
"@storybook/react-webpack5": "^8.4.4",
|
||||
"@storybook/test": "^8.4.4",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@types/react": "^18.3.11",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@vanilla-extract/rollup-plugin": "^1.3.10",
|
||||
"@vanilla-extract/webpack-plugin": "^2.3.14",
|
||||
"eslint": "^9.13.0",
|
||||
"eslint-plugin-react-hooks": "^5.0.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.13",
|
||||
"eslint-plugin-storybook": "^0.11.0",
|
||||
"globals": "^15.11.0",
|
||||
"mini-css-extract-plugin": "^2.9.2",
|
||||
"storybook": "^8.4.4",
|
||||
"typescript": "~5.6.2",
|
||||
"typescript-eslint": "^8.10.0",
|
||||
"webpack-merge": "^6.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0",
|
||||
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2024 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 { style } from '@vanilla-extract/css';
|
||||
|
||||
export const base = style({
|
||||
fontFamily: 'var(--canon-font-sans)',
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
import { Canvas, Meta, Unstyled } from '@storybook/blocks';
|
||||
import * as BoxStories from './box.stories';
|
||||
import { PropsTable } from '../../storybook/props-table';
|
||||
import { Chip } from '../../storybook/chip';
|
||||
import * as Table from '../../storybook/table';
|
||||
|
||||
<Meta of={BoxStories} />
|
||||
|
||||
# Box
|
||||
|
||||
Box is the lowest-level component in Canon. We use it internally to build all of our components.
|
||||
|
||||
<Canvas of={BoxStories.Basic} />
|
||||
|
||||
<Unstyled>
|
||||
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.HeaderRow>
|
||||
<Table.HeaderCell>Prop</Table.HeaderCell>
|
||||
<Table.HeaderCell>Type</Table.HeaderCell>
|
||||
<Table.HeaderCell>Default</Table.HeaderCell>
|
||||
<Table.HeaderCell>Description</Table.HeaderCell>
|
||||
</Table.HeaderRow>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>background</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>string</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>transparent</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The background color of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>display</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>block</Chip>
|
||||
<Chip>flex</Chip>
|
||||
<Chip>inline-block</Chip>
|
||||
<Chip>inline-flex</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>block</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The display property of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>padding</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>number</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>0</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The padding of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>paddingX</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>number</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>0</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The horizontal padding of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>paddingY</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>number</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>0</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The vertical padding of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>paddingLeft</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>number</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>0</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The left padding of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>paddingRight</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>number</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Chip>0</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The right padding of the box.</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
|
||||
</Unstyled>
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2024 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 type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Box } from './box';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Box',
|
||||
component: Box,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
// tags: ['autodocs'],
|
||||
} satisfies Meta<typeof Box>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Basic: Story = {
|
||||
render: () => (
|
||||
<Box padding="medium" background="background">
|
||||
Basic Box
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
export const Responsive: Story = {
|
||||
render: () => (
|
||||
<Box
|
||||
display={{ xs: 'block', sm: 'flex' }}
|
||||
padding={{ xs: 'small', sm: 'medium', lg: 'large' }}
|
||||
background="background"
|
||||
>
|
||||
Responsive Box
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
export const FlexContainer: Story = {
|
||||
render: () => (
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
padding="large"
|
||||
background="background"
|
||||
>
|
||||
<Box padding="medium" background="background">
|
||||
Item 1
|
||||
</Box>
|
||||
<Box padding="medium" background="background">
|
||||
Item 2
|
||||
</Box>
|
||||
<Box padding="medium" background="background">
|
||||
Item 3
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
export const Nested: Story = {
|
||||
render: () => (
|
||||
<Box padding="large" background="background">
|
||||
<Box padding="medium" background="background">
|
||||
Header
|
||||
</Box>
|
||||
<Box
|
||||
display="flex"
|
||||
padding="medium"
|
||||
background="background"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Box padding="small" background="background">
|
||||
Sidebar
|
||||
</Box>
|
||||
<Box padding="small" background="background">
|
||||
Main Content
|
||||
</Box>
|
||||
</Box>
|
||||
<Box padding="medium" background="background">
|
||||
Footer
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
export const Alignment: Story = {
|
||||
render: () => (
|
||||
<Box
|
||||
display="flex"
|
||||
padding="large"
|
||||
background="background"
|
||||
justifyContent="center"
|
||||
alignItems="center"
|
||||
style={{ height: '200px' }}
|
||||
>
|
||||
<Box padding="medium" background="background">
|
||||
Centered Content
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
// Example showing different spacing combinations
|
||||
export const Spacing: Story = {
|
||||
render: () => (
|
||||
<Box display="flex" flexDirection="column" gap="medium">
|
||||
<Box padding="small" background="background">
|
||||
Small Padding
|
||||
</Box>
|
||||
<Box padding="medium" background="background">
|
||||
Medium Padding
|
||||
</Box>
|
||||
<Box padding="large" background="background">
|
||||
Large Padding
|
||||
</Box>
|
||||
<Box paddingX="large" paddingY="small" background="background">
|
||||
Mixed Padding
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
|
||||
// Example showing different display values
|
||||
export const DisplayVariants: Story = {
|
||||
render: () => (
|
||||
<Box display="flex" flexDirection="column" gap="medium">
|
||||
<Box padding="medium" background="background" display="block">
|
||||
Display Block
|
||||
</Box>
|
||||
<Box padding="medium" background="background" display="flex">
|
||||
Display Flex
|
||||
</Box>
|
||||
<Box padding="medium" background="background" display="inline">
|
||||
Display Inline
|
||||
</Box>
|
||||
</Box>
|
||||
),
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2024 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 { createElement } from 'react';
|
||||
import { sprinkles, Sprinkles } from './sprinkles.css';
|
||||
import { base } from './box.css';
|
||||
|
||||
type HTMLProperties = Omit<
|
||||
React.AllHTMLAttributes<HTMLElement>,
|
||||
keyof Sprinkles
|
||||
>;
|
||||
|
||||
type BoxProps = Sprinkles &
|
||||
HTMLProperties & {
|
||||
as?: keyof JSX.IntrinsicElements;
|
||||
};
|
||||
|
||||
export const Box = ({ as = 'div', className, style, ...props }: BoxProps) => {
|
||||
const sprinklesProps: Record<string, unknown> = {};
|
||||
const nativeProps: Record<string, unknown> = {};
|
||||
|
||||
// Split props between sprinkles and native HTML props
|
||||
Object.entries(props).forEach(([key, value]) => {
|
||||
if (value === undefined) return;
|
||||
|
||||
if (sprinkles.properties.has(key as keyof Sprinkles)) {
|
||||
sprinklesProps[key] = value;
|
||||
} else {
|
||||
nativeProps[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
const sprinklesClassName = sprinkles(sprinklesProps);
|
||||
|
||||
return createElement(as, {
|
||||
className: [base, sprinklesClassName, className].filter(Boolean).join(' '),
|
||||
style,
|
||||
...nativeProps,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2024 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles';
|
||||
|
||||
const space = {
|
||||
none: 0,
|
||||
small: '4px',
|
||||
medium: '8px',
|
||||
large: '16px',
|
||||
// etc.
|
||||
};
|
||||
|
||||
const colors = {
|
||||
background: '#eff6ff',
|
||||
};
|
||||
|
||||
const responsiveProperties = defineProperties({
|
||||
conditions: {
|
||||
xs: {},
|
||||
sm: { '@media': 'screen and (min-width: 640px)' },
|
||||
md: { '@media': 'screen and (min-width: 768px)' },
|
||||
lg: { '@media': 'screen and (min-width: 1024px)' },
|
||||
xl: { '@media': 'screen and (min-width: 1280px)' },
|
||||
'2xl': { '@media': 'screen and (min-width: 1536px)' },
|
||||
},
|
||||
defaultCondition: 'xs',
|
||||
properties: {
|
||||
display: ['none', 'flex', 'block', 'inline'],
|
||||
flexDirection: ['row', 'column'],
|
||||
justifyContent: [
|
||||
'stretch',
|
||||
'flex-start',
|
||||
'center',
|
||||
'flex-end',
|
||||
'space-around',
|
||||
'space-between',
|
||||
],
|
||||
alignItems: ['stretch', 'flex-start', 'center', 'flex-end'],
|
||||
paddingTop: space,
|
||||
paddingBottom: space,
|
||||
paddingLeft: space,
|
||||
paddingRight: space,
|
||||
// fontFamily: font,
|
||||
gap: space,
|
||||
// etc.
|
||||
},
|
||||
shorthands: {
|
||||
padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'],
|
||||
paddingX: ['paddingLeft', 'paddingRight'],
|
||||
paddingY: ['paddingTop', 'paddingBottom'],
|
||||
placeItems: ['justifyContent', 'alignItems'],
|
||||
},
|
||||
});
|
||||
|
||||
const colorProperties = defineProperties({
|
||||
conditions: {
|
||||
lightMode: {},
|
||||
darkMode: { '@media': '(prefers-color-scheme: dark)' },
|
||||
},
|
||||
defaultCondition: 'lightMode',
|
||||
properties: {
|
||||
color: colors,
|
||||
background: colors,
|
||||
},
|
||||
});
|
||||
|
||||
export const sprinkles = createSprinkles(responsiveProperties, colorProperties);
|
||||
|
||||
// It's a good idea to export the Sprinkles type too
|
||||
export type Sprinkles = Parameters<typeof sprinkles>[0];
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2024 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 { recipe } from '@vanilla-extract/recipes';
|
||||
// import { vars } from '../../theme/themes.css';
|
||||
|
||||
export const button = recipe({
|
||||
base: {
|
||||
all: 'unset',
|
||||
display: 'inline-block',
|
||||
userSelect: 'none',
|
||||
fontFamily: 'var(--canon-font-sans)',
|
||||
fontWeight: 600,
|
||||
fontSize: '0.875rem',
|
||||
lineHeight: '1.5',
|
||||
padding: 0,
|
||||
transition: 'all 150ms ease',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
variants: {
|
||||
variant: {
|
||||
primary: {
|
||||
backgroundColor: 'var(--button-primary-background-color)',
|
||||
color: 'var(--button-primary-text-color)',
|
||||
borderRadius: 'var(--button-primary-border-radius)',
|
||||
border: `1px solid var(--button-primary-border-color)`,
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--button-primary-background-color-hover)',
|
||||
borderColor: 'var(--button-primary-border-color-hover)',
|
||||
},
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: 'transparent',
|
||||
color: 'var(--button-secondary-text-color)',
|
||||
borderRadius: 'var(--button-secondary-border-radius)',
|
||||
border: `1px solid var(--button-secondary-border-color)`,
|
||||
'&:hover': {
|
||||
backgroundColor: 'var(--button-secondary-background-color-hover)',
|
||||
borderColor: 'var(--button-secondary-border-color-hover)',
|
||||
},
|
||||
},
|
||||
},
|
||||
size: {
|
||||
small: {
|
||||
paddingLeft: '16px',
|
||||
paddingRight: '16px',
|
||||
height: 'var(--button-size-small)',
|
||||
},
|
||||
medium: {
|
||||
paddingLeft: '32px',
|
||||
paddingRight: '32px',
|
||||
height: 'var(--button-size-medium)',
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
true: {
|
||||
opacity: 0.3,
|
||||
cursor: 'not-allowed',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2024 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 type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Button } from './button';
|
||||
|
||||
const meta = {
|
||||
title: 'Components/Button',
|
||||
component: Button,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
size: {
|
||||
control: 'select',
|
||||
options: ['small', 'medium'],
|
||||
},
|
||||
},
|
||||
args: {
|
||||
size: 'medium',
|
||||
},
|
||||
} satisfies Meta<typeof Button>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
children: 'Primary button',
|
||||
},
|
||||
};
|
||||
|
||||
export const Secondary: Story = {
|
||||
args: {
|
||||
children: 'Secondary button',
|
||||
variant: 'secondary',
|
||||
},
|
||||
};
|
||||
|
||||
export const Sizes: Story = {
|
||||
args: {
|
||||
children: 'Button',
|
||||
},
|
||||
render: args => (
|
||||
<div style={{ display: 'flex', gap: '10px' }}>
|
||||
<Button {...args} size="small" />
|
||||
<Button {...args} size="medium" />
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
children: 'Button',
|
||||
disabled: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomTheme: Story = {
|
||||
args: {
|
||||
children: 'Custom Button',
|
||||
},
|
||||
decorators: [
|
||||
Story => (
|
||||
<div
|
||||
style={
|
||||
{
|
||||
'--button-primary-background-color': 'blue',
|
||||
'--button-primary-border-color': 'blue',
|
||||
'--button-primary-text-color': 'white',
|
||||
'--button-primary-border-radius': '8px',
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<Story />
|
||||
</div>
|
||||
),
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2024 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 { button } from './button.css';
|
||||
import { Box } from '../box/box';
|
||||
|
||||
export interface ButtonProps {
|
||||
size?: 'small' | 'medium';
|
||||
variant?: 'primary' | 'secondary';
|
||||
children: React.ReactNode;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export const Button = ({
|
||||
size = 'medium',
|
||||
variant = 'primary',
|
||||
children,
|
||||
disabled,
|
||||
...props
|
||||
}: ButtonProps) => {
|
||||
return (
|
||||
<Box
|
||||
{...props}
|
||||
as="button"
|
||||
disabled={disabled}
|
||||
className={button({ size, variant, disabled })}
|
||||
>
|
||||
{children}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
@@ -0,0 +1,41 @@
|
||||
:root {
|
||||
--button-primary-background-color: #1ed760;
|
||||
--button-primary-background-color-hover: #3be477;
|
||||
--button-primary-background-color-active: #1abc54;
|
||||
--button-primary-border-color: #1ed760;
|
||||
--button-primary-border-color-hover: #3be477;
|
||||
--button-primary-border-color-active: #1abc54;
|
||||
--button-primary-text-color: #000;
|
||||
--button-primary-border-radius: 9999px;
|
||||
--button-secondary-background-color: transparent;
|
||||
--button-secondary-background-color-hover: transparent;
|
||||
--button-secondary-background-color-active: rgba(0, 0, 0, 0.03);
|
||||
--button-secondary-border-color: #000;
|
||||
--button-secondary-border-color-hover: #000;
|
||||
--button-secondary-border-color-active: #000;
|
||||
--button-secondary-text-color: #000;
|
||||
--button-secondary-border-radius: 9999px;
|
||||
--button-size-small: 32px;
|
||||
--button-size-medium: 48px;
|
||||
}
|
||||
|
||||
[data-theme='dark'] {
|
||||
--button-primary-background-color: #1ed760;
|
||||
--button-primary-background-color-hover: #3be477;
|
||||
--button-primary-background-color-active: #1abc54;
|
||||
--button-primary-border-color: #1ed760;
|
||||
--button-primary-border-color-hover: #3be477;
|
||||
--button-primary-border-color-active: #1abc54;
|
||||
--button-primary-text-color: #000;
|
||||
--button-primary-border-radius: 9999px;
|
||||
--button-secondary-background-color: transparent;
|
||||
--button-secondary-background-color-hover: transparent;
|
||||
--button-secondary-background-color-active: rgba(255, 255, 255, 0.1);
|
||||
--button-secondary-border-color: #fff;
|
||||
--button-secondary-border-color-hover: #fff;
|
||||
--button-secondary-border-color-active: #fff;
|
||||
--button-secondary-text-color: #fff;
|
||||
--button-secondary-border-radius: 9999px;
|
||||
--button-size-small: 32px;
|
||||
--button-size-medium: 48px;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Unstyled } from '@storybook/blocks';
|
||||
import { Text } from '../storybook/text';
|
||||
import { ComponentStatus } from '../storybook/component-status';
|
||||
import { Columns } from '../storybook/columns';
|
||||
|
||||

|
||||
|
||||
<Unstyled>
|
||||
|
||||
<Text style={{ marginTop: '64px' }}>
|
||||
Welcome to the Canon, the new library for building Backstage plugins. This
|
||||
project is still under active development but we will make sure to document
|
||||
the API as we go. We are aiming to improve the general UI of Backstage and
|
||||
plugins across Backstage. This new library will take time to build but we are
|
||||
building it incrementally with not conflict with the existing theming system.
|
||||
</Text>
|
||||
|
||||
<Columns style={{ marginTop: '64px' }}>
|
||||
<ComponentStatus
|
||||
name="Theming system"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/theme--docs"
|
||||
/>
|
||||
<ComponentStatus name="Storybook setup" status="inProgress" />
|
||||
<ComponentStatus name="Tokens" status="inProgress" />
|
||||
<ComponentStatus
|
||||
name="Box"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/components-box--docs"
|
||||
/>
|
||||
<ComponentStatus
|
||||
name="Button"
|
||||
status="inProgress"
|
||||
link="/?path=/docs/components-button--docs"
|
||||
/>
|
||||
<ComponentStatus name="Input" status="notStarted" />
|
||||
<ComponentStatus name="Select" status="notStarted" />
|
||||
<ComponentStatus name="Checkbox" status="notStarted" />
|
||||
<ComponentStatus name="Radio" status="notStarted" />
|
||||
<ComponentStatus name="Switch" status="notStarted" />
|
||||
<ComponentStatus name="Tooltip" status="notStarted" />
|
||||
<ComponentStatus name="Header" status="notStarted" />
|
||||
<ComponentStatus name="Tabs" status="notStarted" />
|
||||
</Columns>
|
||||
|
||||
</Unstyled>
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Unstyled, Source } from '@storybook/blocks';
|
||||
import { Title } from '../storybook/title';
|
||||
import { Text } from '../storybook/text';
|
||||
import { Chip } from '../storybook/chip';
|
||||
import * as Table from '../storybook/table';
|
||||
|
||||
<Unstyled>
|
||||
|
||||
<Title type="h1">Theming</Title>
|
||||
<Text>
|
||||
Backstage ships with a default theme with a light and dark mode variant. The
|
||||
themes are provided as a part of the{' '}
|
||||
<a href="https://github.com/backstage/backstage">@backstage/canon</a> package,
|
||||
which also includes utilities for customizing the default theme, or creating
|
||||
completely new themes.
|
||||
</Text>
|
||||
|
||||
<Title type="h2">Light & Dark modes</Title>
|
||||
<Text>
|
||||
By default we are supporting both light and dark modes. Each user can opt to
|
||||
choose what theme they want to use or to use their system decide what theme to
|
||||
use. If you want to create your own theme, you will have to set both light and
|
||||
dark themes following the instructions below. If you only set one of them, the
|
||||
other mode will fallback to the default theme.
|
||||
</Text>
|
||||
|
||||
<Title type="h2">How to create your own theme</Title>
|
||||
<Text>
|
||||
To create your own theme, you will have to define the variables below. To do
|
||||
that, create a theme.css file and import it in your application. Here's an
|
||||
example below on how to set your light and dark mode.
|
||||
</Text>
|
||||
<Source
|
||||
code={`/** Light theme **/
|
||||
[data-theme='light'] {
|
||||
--canon-accent: #1ed760;
|
||||
--canon-bg: #fff;
|
||||
--canon-surface-1: #f5f5f5;
|
||||
--canon-surface-2: #000;
|
||||
--canon-outline: #666;
|
||||
--canon-outline-focus: #ccc;
|
||||
--canon-text-primary: #f0f0f0;
|
||||
--canon-text-secondary: #666;
|
||||
--canon-font-sans: 'Geist', serif;
|
||||
--canon-font-monospace: 'Monospace', monospace;
|
||||
--canon-font-emoji: 'Apple Color Emoji', 'Segoe UI Emoji';
|
||||
/* ... other values */
|
||||
}
|
||||
|
||||
/** Dark theme **/
|
||||
[data-theme='dark'] {
|
||||
--canon-accent: #1ed760;
|
||||
--canon-bg: #000;
|
||||
--canon-surface-1: #f5f5f5;
|
||||
--canon-surface-2: #000;
|
||||
--canon-outline: #666;
|
||||
--canon-outline-focus: #ccc;
|
||||
--canon-text-primary: #fff;
|
||||
--canon-text-secondary: #666;
|
||||
--canon-font-sans: 'Geist', serif;
|
||||
--canon-font-monospace: 'Monospace', monospace;
|
||||
--canon-font-emoji: 'Apple Color Emoji', 'Segoe UI Emoji';
|
||||
/* ... other values */
|
||||
}
|
||||
`}
|
||||
language="css"
|
||||
dark
|
||||
/>
|
||||
|
||||
<Title type="h2">Colors</Title>
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.HeaderRow>
|
||||
<Table.HeaderCell>Prop</Table.HeaderCell>
|
||||
<Table.HeaderCell>Description</Table.HeaderCell>
|
||||
</Table.HeaderRow>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>--canon-accent</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The accent color for the theme.</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Chip>--canon-bg</Chip>
|
||||
</Table.Cell>
|
||||
<Table.Cell>The background color for the theme.</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
|
||||
<Title type="h2">Typography</Title>
|
||||
<Text>
|
||||
Our theming is system is still a work in progress. We will be adding more
|
||||
features and documentation over time.
|
||||
</Text>
|
||||
|
||||
</Unstyled>
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2024 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.
|
||||
*/
|
||||
|
||||
// Components
|
||||
export { Button } from './components/button/button';
|
||||
export { Box } from './components/box/box';
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2024 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 { style } from '@vanilla-extract/css';
|
||||
|
||||
export const chipStyles = style({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
fontFamily: 'Geist Mono, monospace',
|
||||
fontSize: '13px',
|
||||
borderRadius: '6px',
|
||||
padding: '0px 8px',
|
||||
height: '24px',
|
||||
backgroundColor: '#eaf2fd',
|
||||
color: '#2563eb',
|
||||
marginRight: '4px',
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2024 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 { chipStyles } from './chip.css';
|
||||
|
||||
export const Chip = ({ children }: { children: React.ReactNode }) => {
|
||||
return <span className={chipStyles}>{children}</span>;
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2024 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 { style } from '@vanilla-extract/css';
|
||||
|
||||
export const styles = style({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(2, 1fr)',
|
||||
rowGap: '20px',
|
||||
columnGap: '80px',
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2024 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 { styles } from './columns.css';
|
||||
|
||||
export const Columns = ({
|
||||
children,
|
||||
style,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
}) => {
|
||||
return (
|
||||
<div className={styles} style={style}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2024 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 { style } from '@vanilla-extract/css';
|
||||
import { recipe } from '@vanilla-extract/recipes';
|
||||
|
||||
export const container = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
|
||||
export const title = style({
|
||||
color: '#3b59ff',
|
||||
fontFamily: '"Geist", sans-serif',
|
||||
fontSize: '16px',
|
||||
fontWeight: '400',
|
||||
textDecoration: 'none',
|
||||
});
|
||||
|
||||
export const pill = recipe({
|
||||
base: {
|
||||
fontFamily: '"Geist", sans-serif',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
color: '#000',
|
||||
borderRadius: '40px',
|
||||
padding: '0px 8px',
|
||||
height: '24px',
|
||||
fontSize: '12px',
|
||||
fontWeight: '600',
|
||||
borderStyle: 'solid',
|
||||
borderWidth: '1px',
|
||||
marginLeft: '8px',
|
||||
},
|
||||
variants: {
|
||||
status: {
|
||||
notStarted: {
|
||||
backgroundColor: '#F2F2F2',
|
||||
borderColor: '#CDCDCD',
|
||||
color: '#888888',
|
||||
},
|
||||
inProgress: {
|
||||
backgroundColor: '#FFF2B9',
|
||||
borderColor: '#FFD000',
|
||||
color: '#D79927',
|
||||
},
|
||||
done: {
|
||||
backgroundColor: '#D7F9D7',
|
||||
borderColor: '#4ED14A',
|
||||
color: '#3A9837',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2024 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 { container, pill, title } from './component-status.css';
|
||||
|
||||
export const ComponentStatus = ({
|
||||
name,
|
||||
status = 'notStarted',
|
||||
style,
|
||||
link,
|
||||
}: {
|
||||
name: string;
|
||||
status: 'notStarted' | 'inProgress' | 'done';
|
||||
style?: React.CSSProperties;
|
||||
link?: string;
|
||||
}) => {
|
||||
return (
|
||||
<div className={container} style={style}>
|
||||
{link ? (
|
||||
<a href={link} className={title}>
|
||||
{name}
|
||||
</a>
|
||||
) : (
|
||||
<span className={title}>{name}</span>
|
||||
)}
|
||||
<span className={pill({ status })}>
|
||||
{status === 'notStarted' && 'Not Started'}
|
||||
{status === 'inProgress' && 'In Progress'}
|
||||
{status === 'done' && 'Done'}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2024 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 {
|
||||
tableStyles,
|
||||
cellStyles,
|
||||
headerCellStyles,
|
||||
rowStyles,
|
||||
wrapperStyles,
|
||||
chipStyles,
|
||||
headerRowStyles,
|
||||
typeStyles,
|
||||
} from './props-table.css';
|
||||
|
||||
type PropsTableData = {
|
||||
prop: string;
|
||||
type: string | string[];
|
||||
default: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
export const PropsTable = ({ data }: { data: PropsTableData[] }) => {
|
||||
return (
|
||||
<div className={wrapperStyles}>
|
||||
<table className={tableStyles}>
|
||||
<thead className={headerRowStyles}>
|
||||
<tr className={rowStyles}>
|
||||
<th className={`${cellStyles} ${headerCellStyles}`}>Prop</th>
|
||||
<th className={`${cellStyles} ${headerCellStyles}`}>Type</th>
|
||||
<th className={`${cellStyles} ${headerCellStyles}`}>Default</th>
|
||||
<th className={`${cellStyles} ${headerCellStyles}`}>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map(item => (
|
||||
<tr className={rowStyles}>
|
||||
<td className={cellStyles}>
|
||||
<span className={chipStyles}>{item.prop}</span>
|
||||
</td>
|
||||
<td className={cellStyles}>
|
||||
<div className={typeStyles}>
|
||||
{Array.isArray(item.type) ? (
|
||||
item.type.map(type => (
|
||||
<span className={chipStyles}>{type}</span>
|
||||
))
|
||||
) : (
|
||||
<span className={chipStyles}>{item.type}</span>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className={cellStyles}>
|
||||
<span className={chipStyles}>{item.default}</span>
|
||||
</td>
|
||||
<td className={cellStyles}>{item.description}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2024 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 { style } from '@vanilla-extract/css';
|
||||
|
||||
export const wrapperStyles = style({
|
||||
border: '1px solid #e7e7e7',
|
||||
borderRadius: '4px',
|
||||
overflow: 'hidden',
|
||||
});
|
||||
|
||||
export const tableStyles = style({
|
||||
width: '100%',
|
||||
margin: '0 !important',
|
||||
padding: '0 !important',
|
||||
});
|
||||
|
||||
export const cellStyles = style({
|
||||
padding: '12px 16px !important',
|
||||
border: 'none !important',
|
||||
textAlign: 'left',
|
||||
backgroundColor: 'white !important',
|
||||
});
|
||||
|
||||
export const headerCellStyles = style({
|
||||
backgroundColor: '#f5f5f5 !important',
|
||||
fontWeight: 'bold',
|
||||
});
|
||||
|
||||
export const rowStyles = style({
|
||||
border: 'none !important',
|
||||
borderBottom: '1px solid #e7e7e7 !important',
|
||||
selectors: {
|
||||
'&:last-child': {
|
||||
borderBottom: 'none !important',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const chipStyles = style({
|
||||
display: 'inline-block',
|
||||
fontSize: '14px !important',
|
||||
border: '1px solid #e7e7e7',
|
||||
borderRadius: '6px',
|
||||
padding: '0px 6px',
|
||||
height: '24px',
|
||||
});
|
||||
|
||||
export const headerRowStyles = style({
|
||||
borderBottom: '1px solid #e7e7e7 !important',
|
||||
});
|
||||
|
||||
export const typeStyles = style({
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'row',
|
||||
gap: '8px',
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2024 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 {
|
||||
cellStyles,
|
||||
headerCellStyles,
|
||||
tableStyles,
|
||||
wrapperStyles,
|
||||
rowStyles,
|
||||
} from './table.css';
|
||||
|
||||
export const Root = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<div className={wrapperStyles}>
|
||||
<table className={tableStyles}>{children}</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = ({ children }: { children: React.ReactNode }) => {
|
||||
return <thead>{children}</thead>;
|
||||
};
|
||||
|
||||
export const Body = ({ children }: { children: React.ReactNode }) => {
|
||||
return <tbody>{children}</tbody>;
|
||||
};
|
||||
|
||||
export const HeaderRow = ({ children }: { children: React.ReactNode }) => {
|
||||
return <tr>{children}</tr>;
|
||||
};
|
||||
|
||||
export const HeaderCell = ({ children }: { children: React.ReactNode }) => {
|
||||
return <th className={`${cellStyles} ${headerCellStyles}`}>{children}</th>;
|
||||
};
|
||||
|
||||
export const Row = ({ children }: { children: React.ReactNode }) => {
|
||||
return <tr className={rowStyles}>{children}</tr>;
|
||||
};
|
||||
|
||||
export const Cell = ({ children }: { children: React.ReactNode }) => {
|
||||
return <td className={cellStyles}>{children}</td>;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2024 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 { style } from '@vanilla-extract/css';
|
||||
|
||||
export const wrapperStyles = style({
|
||||
border: '1px solid #e7e7e7',
|
||||
borderRadius: '4px',
|
||||
overflow: 'hidden',
|
||||
});
|
||||
|
||||
export const tableStyles = style({
|
||||
width: '100%',
|
||||
margin: '0 !important',
|
||||
padding: '0 !important',
|
||||
borderSpacing: '0px',
|
||||
borderCollapse: 'collapse',
|
||||
});
|
||||
|
||||
export const cellStyles = style({
|
||||
padding: '12px 16px !important',
|
||||
border: 'none !important',
|
||||
textAlign: 'left',
|
||||
backgroundColor: 'white !important',
|
||||
fontFamily: '"Geist", sans-serif',
|
||||
fontSize: '16px',
|
||||
fontWeight: '300',
|
||||
});
|
||||
|
||||
export const headerRowStyles = style({
|
||||
borderBottom: '1px solid #e7e7e7',
|
||||
});
|
||||
|
||||
export const headerCellStyles = style({
|
||||
backgroundColor: '#f5f5f5 !important',
|
||||
borderBottom: '1px solid #e7e7e7 !important',
|
||||
fontWeight: '500',
|
||||
});
|
||||
|
||||
export const rowStyles = style({
|
||||
border: 'none',
|
||||
borderBottom: '1px solid #e7e7e7',
|
||||
selectors: {
|
||||
'&:last-child': {
|
||||
borderBottom: 'none',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const chipStyles = style({
|
||||
display: 'inline-block',
|
||||
fontSize: '14px !important',
|
||||
border: '1px solid #e7e7e7',
|
||||
borderRadius: '6px',
|
||||
padding: '0px 6px',
|
||||
height: '24px',
|
||||
});
|
||||
|
||||
export const typeStyles = style({
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
flexDirection: 'row',
|
||||
gap: '8px',
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2024 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 { textStyles } from './text.css';
|
||||
|
||||
export const Text = ({
|
||||
children,
|
||||
style,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
}) => {
|
||||
return (
|
||||
<div className={textStyles} style={style}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2024 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 { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const textStyles = style({
|
||||
fontFamily: '"Geist", sans-serif',
|
||||
fontSize: '18px',
|
||||
lineHeight: '28px',
|
||||
margin: '0',
|
||||
fontWeight: '300',
|
||||
paddingBottom: '16px',
|
||||
});
|
||||
|
||||
globalStyle(`${textStyles} p`, {
|
||||
fontFamily: '"Geist", sans-serif',
|
||||
fontSize: '18px',
|
||||
lineHeight: '28px',
|
||||
margin: '0',
|
||||
fontWeight: '300',
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2024 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 { titleStyles } from './title.css';
|
||||
|
||||
export const Title = ({
|
||||
children,
|
||||
style,
|
||||
type = 'h1',
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
type?: 'h1' | 'h2' | 'h3';
|
||||
}) => {
|
||||
let Component = 'h1';
|
||||
if (type === 'h1') Component = 'h1';
|
||||
if (type === 'h2') Component = 'h2';
|
||||
if (type === 'h3') Component = 'h3';
|
||||
|
||||
return React.createElement(Component, {
|
||||
className: titleStyles({ type }),
|
||||
style,
|
||||
children,
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2024 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 { recipe } from '@vanilla-extract/recipes';
|
||||
|
||||
export const titleStyles = recipe({
|
||||
base: {
|
||||
fontFamily: '"Geist", sans-serif',
|
||||
margin: '0',
|
||||
fontWeight: '500',
|
||||
border: 'none',
|
||||
},
|
||||
variants: {
|
||||
type: {
|
||||
h1: {
|
||||
fontSize: '40px',
|
||||
lineHeight: '48px',
|
||||
marginBottom: '32px',
|
||||
marginTop: '0px',
|
||||
},
|
||||
h2: {
|
||||
fontSize: '24px',
|
||||
lineHeight: '32px',
|
||||
marginBottom: '12px',
|
||||
marginTop: '52px',
|
||||
},
|
||||
h3: {
|
||||
fontSize: '20px',
|
||||
lineHeight: '28px',
|
||||
marginBottom: '12px',
|
||||
marginTop: '52px',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2024 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
|
||||
*/
|
||||
|
||||
/* Geist font */
|
||||
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap');
|
||||
@import url('https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap');
|
||||
|
||||
/* Theme */
|
||||
@import './theme.css';
|
||||
|
||||
/* Components */
|
||||
@import '../components/button/styles.css';
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Light theme */
|
||||
:root {
|
||||
--canon-accent: #1ed760;
|
||||
--canon-bg: #fff;
|
||||
--canon-surface-1: #f5f5f5;
|
||||
--canon-surface-2: #000;
|
||||
--canon-outline: #666;
|
||||
--canon-outline-focus: #ccc;
|
||||
--canon-text-primary: #f0f0f0;
|
||||
--canon-text-secondary: #666;
|
||||
|
||||
--canon-font-sans: 'Geist', serif;
|
||||
--canon-font-monospace: 'Monospace', monospace;
|
||||
--canon-font-emoji: 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji';
|
||||
}
|
||||
|
||||
/* Dark theme */
|
||||
[data-theme='dark'] {
|
||||
--canon-accent: #1ed760;
|
||||
--canon-bg: #fff;
|
||||
--canon-surface-1: #f5f5f5;
|
||||
--canon-surface-2: #000;
|
||||
--canon-outline: #666;
|
||||
--canon-outline-focus: #ccc;
|
||||
--canon-text-primary: #f0f0f0;
|
||||
--canon-text-secondary: #666;
|
||||
|
||||
--canon-font-sans: 'Geist', serif;
|
||||
--canon-font-monospace: 'Monospace', monospace;
|
||||
--canon-font-emoji: 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
|
||||
'Noto Color Emoji';
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "@backstage/cli/config/tsconfig.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"outDir": "dist-types",
|
||||
"rootDir": "."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user