Merge pull request #27904 from backstage/canon-improve-box

Update Box component
This commit is contained in:
Charles de Dreuille
2024-11-28 23:32:47 +00:00
committed by GitHub
32 changed files with 674 additions and 1590 deletions
+14
View File
@@ -0,0 +1,14 @@
import { addons } from '@storybook/manager-api';
import { create } from '@storybook/theming';
const theme = create({
base: 'light',
brandTitle: 'My custom Storybook',
brandUrl: 'https://example.com',
brandImage: 'logo.svg',
brandTarget: '_self',
});
addons.setConfig({
theme,
});
+4
View File
@@ -2,6 +2,10 @@ import React from 'react';
import type { Preview, ReactRenderer } from '@storybook/react';
import { withThemeByDataAttribute } from '@storybook/addon-themes';
// Storybook specific styles
import '../docs/components/styles.css';
// Canon specific styles
import '../src/theme/styles.css';
const preview: Preview = {
+45 -15
View File
@@ -1,11 +1,11 @@
import { Unstyled } from '@storybook/blocks';
import { Columns, Text, ComponentStatus, Banner } from './components';
import { Columns, Text, ComponentStatus, Banner, Title } from './components';
<Unstyled>
<img src="header.png" style={{ width: '100%', marginTop: '-16px' }} />
<Text style={{ marginTop: '64px' }}>
<Text style={{ marginTop: '64px', marginBottom: '24px' }}>
Welcome to the Canon, the new design library for 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
@@ -18,32 +18,62 @@ import { Columns, Text, ComponentStatus, Banner } from './components';
will change until we reach a stable release.
</Banner>
<Columns style={{ marginTop: '64px' }}>
<Title style={{ marginTop: '48px' }} type="h2">
Project Status
</Title>
<Text>
We are still in the process of documenting the API and building the
components. You can use the statuses below to see what is ready and what is
coming soon. If there is a component missing that you need, please let us know
by opening an issue on GitHub.
</Text>
<Columns style={{ marginTop: '32px' }}>
<ComponentStatus name="Storybook setup" status="done" />
<ComponentStatus
name="Iconography"
status="done"
link="/?path=/docs/iconography--docs"
/>
<ComponentStatus name="Global tokens" status="inProgress" />
<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"
name="Box component"
status="inProgress"
link="/?path=/docs/components-box--docs"
/>
<ComponentStatus
name="Button"
name="Inline component"
status="inProgress"
link="/?path=/story/components-inline--default"
/>
<ComponentStatus
name="Stack component"
status="inProgress"
link="/?path=/docs/components-stack--default"
/>
<ComponentStatus
name="Button component"
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" />
<ComponentStatus
name="Icon component"
status="inProgress"
link="/?path=/docs/components-icon--docs"
/>
<ComponentStatus name="Input component" status="notStarted" />
<ComponentStatus name="Select component" status="notStarted" />
<ComponentStatus name="Checkbox component" status="notStarted" />
<ComponentStatus name="Radio component" status="notStarted" />
<ComponentStatus name="Switch component" status="notStarted" />
<ComponentStatus name="Tooltip component" status="notStarted" />
<ComponentStatus name="Header component" status="notStarted" />
<ComponentStatus name="Tabs component" status="notStarted" />
</Columns>
</Unstyled>
+20
View File
@@ -0,0 +1,20 @@
import { Unstyled, Source } from '@storybook/blocks';
import { Title, Text, IconLibrary } from './components';
<Unstyled>
<Title type="h1">Iconography</Title>
<Text>
All our default icons are provided by [Remix Icon](https://remixicon.com/). We
don't import all icons to reduce the bundle size but we cherry pick a nice
selection for you to use in your application. The list of names is set down
below. To use an icon, you can use the `Icon` component and pass the name of
the icon you want to use.
</Text>
<Source code={`<Icon name="heart" />`} language="tsx" dark />
<IconLibrary />
</Unstyled>
@@ -0,0 +1,37 @@
/*
* 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 { Icon } from '@backstage/canon';
import type { IconNames } from '@backstage/canon';
import { defaultIcons } from '../../../src/components/Icon/icons';
import { Text } from '../Text';
export const IconLibrary = () => {
const icons = Object.keys(defaultIcons);
return (
<div className="icon-library">
{icons.map(icon => (
<div key={icon} className="icon-library-item">
<div className="icon-library-item-icon">
<Icon name={icon as IconNames} />
</div>
<Text>{icon}</Text>
</div>
))}
</div>
);
};
@@ -0,0 +1,22 @@
.icon-library {
display: grid;
grid-template-columns: repeat(6, 1fr);
gap: 1rem;
}
.icon-library-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.icon-library-item-icon {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
height: 80px;
border: 1px solid #d3d3d3;
border-radius: 0.5rem;
}
+1
View File
@@ -22,3 +22,4 @@ export * from './Columns';
export * from './ComponentStatus';
export * from './LayoutComponents';
export * from './Banner';
export * from './IconLibrary';
@@ -0,0 +1 @@
@import './IconLibrary/styles.css';
Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

+2 -2
View File
@@ -38,11 +38,11 @@
},
"dependencies": {
"@base_ui/react": "^1.0.0-alpha.3",
"@remixicon/react": "^4.5.0",
"@vanilla-extract/css": "^1.16.0",
"@vanilla-extract/dynamic": "^2.1.2",
"@vanilla-extract/recipes": "^0.5.5",
"@vanilla-extract/sprinkles": "^1.6.3",
"lucide-react": "^0.460.0"
"@vanilla-extract/sprinkles": "^1.6.3"
},
"devDependencies": {
"@backstage/cli": "workspace:^",
+235 -1458
View File
File diff suppressed because it is too large Load Diff
+1 -13
View File
@@ -17,19 +17,7 @@
import { createElement } from 'react';
import { boxSprinkles } from './sprinkles.css';
import { base } from './box.css';
/**
* Properties for {@link Box}
*
* @public
*/
export type BoxProps = Parameters<typeof boxSprinkles>[0] &
Omit<
React.AllHTMLAttributes<HTMLElement>,
keyof Parameters<typeof boxSprinkles>[0]
> & {
as?: keyof JSX.IntrinsicElements;
};
import { BoxProps } from './types';
/** @public */
export const Box = (props: BoxProps) => {
@@ -20,8 +20,6 @@ import { Chip } from '../../../../docs/components';
import { listResponsiveValues } from '../../../utils/list-values';
import { responsiveProperties } from '../sprinkles.css';
console.log(responsiveProperties.styles);
export const SpacingTable = () => {
return (
<Table.Root>
+2 -2
View File
@@ -14,5 +14,5 @@
* limitations under the License.
*/
export { Box } from './Box';
export type { BoxProps } from './Box';
export { boxSprinkles } from './sprinkles.css';
export type * from './types';
export { breakpoints, space, themes } from './properties';
@@ -14,6 +14,7 @@
* limitations under the License.
*/
/** @public */
export const breakpoints = {
xs: {},
sm: { '@media': 'screen and (min-width: 640px)' },
@@ -23,6 +24,13 @@ export const breakpoints = {
'2xl': { '@media': 'screen and (min-width: 1536px)' },
};
/** @public */
export const themes = {
light: { selector: '[data-theme="light"] &' },
dark: { selector: '[data-theme="dark"] &' },
};
/** @public */
export const space = {
none: 0,
xxs: 'var(--canon-space-xxs)',
@@ -97,7 +97,6 @@ export const colorProperties = defineProperties({
},
});
/** @public */
export const boxSprinkles = createSprinkles(
responsiveProperties,
colorProperties,
+176
View File
@@ -0,0 +1,176 @@
/*
* 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 { breakpoints, space, themes } from './properties';
/** @public */
export type Breakpoint = keyof typeof breakpoints;
/** @public */
export type Space = keyof typeof space;
/** @public */
export type Theme = keyof typeof themes;
/** @public */
export type Display =
| 'flex'
| 'none'
| 'inline'
| 'block'
| Partial<Record<Breakpoint, 'flex' | 'none' | 'inline' | 'block'>>;
/** @public */
export type FlexDirection =
| 'row'
| 'column'
| Partial<Record<Breakpoint, 'row' | 'column'>>;
/** @public */
export type FlexWrap =
| 'wrap'
| 'nowrap'
| Partial<Record<Breakpoint, 'wrap' | 'nowrap'>>;
/** @public */
export type JustifyContent =
| 'stretch'
| 'flex-start'
| 'center'
| 'flex-end'
| 'space-around'
| 'space-between'
| Partial<
Record<
Breakpoint,
| 'stretch'
| 'flex-start'
| 'center'
| 'flex-end'
| 'space-around'
| 'space-between'
>
>;
/** @public */
export type AlignItems =
| 'stretch'
| 'flex-start'
| 'center'
| 'flex-end'
| Partial<
Record<Breakpoint, 'stretch' | 'flex-start' | 'center' | 'flex-end'>
>;
/** @public */
export type BorderRadius =
| 'none'
| 'small'
| 'medium'
| 'full'
| Partial<Record<Breakpoint, 'none' | 'small' | 'medium' | 'full'>>;
/** @public */
export type Gap = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingLeft = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingRight = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingTop = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingBottom = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type Padding = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingX = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type PaddingY = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginLeft = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginRight = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginTop = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginBottom = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type Margin = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginX = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type MarginY = Space | Partial<Record<Breakpoint, Space>>;
/** @public */
export type Background =
| 'background'
| 'elevation1'
| 'elevation2'
| 'transparent'
| Partial<
Record<Theme, 'background' | 'elevation1' | 'elevation2' | 'transparent'>
>;
/** @public */
export type Color =
| 'primary'
| 'secondary'
| 'error'
| Partial<Record<Theme, 'primary' | 'secondary' | 'error'>>;
/** @public */
export interface BoxProps {
as?: keyof JSX.IntrinsicElements;
background?: Background;
children?: React.ReactNode;
color?: Color;
display?: Display;
flexDirection?: FlexDirection;
flexWrap?: FlexWrap;
justifyContent?: JustifyContent;
alignItems?: AlignItems;
borderRadius?: BorderRadius;
gap?: Gap;
padding?: Padding;
paddingLeft?: PaddingLeft;
paddingRight?: PaddingRight;
paddingTop?: PaddingTop;
paddingBottom?: PaddingBottom;
paddingX?: PaddingX;
paddingY?: PaddingY;
margin?: Margin;
marginLeft?: MarginLeft;
marginRight?: MarginRight;
marginTop?: MarginTop;
marginBottom?: MarginBottom;
marginX?: MarginX;
marginY?: MarginY;
className?: string;
style?: React.CSSProperties;
}
@@ -71,9 +71,9 @@ export const WithIcons: Story = {
},
render: args => (
<div style={{ display: 'flex', gap: '10px' }}>
<Button {...args} iconStart="Cloud" />
<Button {...args} iconEnd="ArrowRight" />
<Button {...args} iconStart="Cloud" iconEnd="ArrowRight" />
<Button {...args} iconStart="cloud" />
<Button {...args} iconEnd="arrowRight" />
<Button {...args} iconStart="cloud" iconEnd="arrowRight" />
</div>
),
};
@@ -84,9 +84,9 @@ export const FullWidth: Story = {
},
render: args => (
<Box>
<Button {...args} iconStart="Cloud" />
<Button {...args} iconEnd="ArrowRight" />
<Button {...args} iconStart="Cloud" iconEnd="ArrowRight" />
<Button {...args} iconStart="cloud" />
<Button {...args} iconEnd="arrowRight" />
<Button {...args} iconStart="cloud" iconEnd="arrowRight" />
</Box>
),
};
@@ -16,9 +16,8 @@
import React from 'react';
import { button } from './button.css';
import { Box } from '../Box/Box';
import { Icon } from '../Icon/Icon';
import { IconNames } from '../Icon/context';
import type { IconNames } from '../Icon/types';
/**
* Properties for {@link Button}
@@ -45,16 +44,15 @@ export const Button = ({
...props
}: ButtonProps) => {
return (
<Box
<button
{...props}
as="button"
disabled={disabled}
className={button({ size, variant, disabled })}
>
{iconStart && <Icon name={iconStart} />}
{children}
{iconEnd && <Icon name={iconEnd} />}
</Box>
</button>
);
};
@@ -17,8 +17,8 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { Icon } from './Icon';
import { IconProvider } from './context';
import * as LucideIcons from 'lucide-react';
import { ThemeProvider } from '../../theme/context';
import { defaultIcons } from './icons';
const meta = {
title: 'Components/Icon',
@@ -26,15 +26,14 @@ const meta = {
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
name: {
control: 'select',
options: Object.keys(LucideIcons),
options: Object.keys(defaultIcons),
},
},
args: {
name: 'ArrowDown',
name: 'heart',
},
} satisfies Meta<typeof Icon>;
@@ -43,40 +42,19 @@ type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
name: 'ArrowDown',
},
};
export const CustomIcon: Story = {
args: {
name: 'CustomIcon',
name: 'heart',
},
};
export const WithCustomIcon: Story = {
args: {
name: 'ArrowDown',
name: 'arrowDown',
},
decorators: [
Story => (
<IconProvider overrides={{ ArrowDown: () => <div>Custom Icon</div> }}>
<ThemeProvider overrides={{ arrowDown: () => <div>Custom Icon</div> }}>
<Story />
</IconProvider>
),
],
};
export const WithCustomIconOverride: Story = {
args: {
name: 'CustomIcon',
},
decorators: [
Story => (
<IconProvider
overrides={{ CustomIcon: () => <div>Custom Super Icon</div> }}
>
<Story />
</IconProvider>
</ThemeProvider>
),
],
};
+6 -5
View File
@@ -15,18 +15,19 @@
*/
import React from 'react';
import { useIcons, IconNames } from './context';
import { useTheme } from '../../theme/context';
import type { IconNames } from './types';
/** @public */
export const Icon = ({ name }: { name: IconNames }) => {
const { icons } = useIcons();
const { icons } = useTheme();
const LucideIcon = icons[name];
const RemixIcon = icons[name];
if (!LucideIcon) {
if (!RemixIcon) {
console.error(`Icon "${name}" not found.`);
return <svg />; // Return default icon perhaps?
}
return <LucideIcon />;
return <RemixIcon />;
};
@@ -0,0 +1,41 @@
/*
* 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.
*/
// We can add custom icons to the list outside of Remix
import type { IconMap } from './types';
import {
RiHeartFill,
RiArrowDownFill,
RiCloudFill,
RiArrowLeftFill,
RiArrowRightFill,
RiArrowUpFill,
RiDeleteBin6Line,
RiAddLine,
} from '@remixicon/react';
// List of default icons
export const defaultIcons: IconMap = {
arrowDown: RiArrowDownFill,
arrowLeft: RiArrowLeftFill,
arrowRight: RiArrowRightFill,
arrowUp: RiArrowUpFill,
cloud: RiCloudFill,
heart: RiHeartFill,
plus: RiAddLine,
trash: RiDeleteBin6Line,
};
+1 -2
View File
@@ -15,5 +15,4 @@
*/
export * from './Icon';
export { IconProvider } from './context';
export type { IconNames } from './context';
export type * from './types';
@@ -14,10 +14,16 @@
* limitations under the License.
*/
import React from 'react';
/** @public */
export type IconNames =
| 'arrowDown'
| 'arrowLeft'
| 'arrowRight'
| 'arrowUp'
| 'cloud'
| 'heart'
| 'plus'
| 'trash';
export const CustomIcon = () => (
<svg viewBox="0 0 24 24" fill="red" width={24} height={24}>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" />
</svg>
);
/** @public */
export type IconMap = Partial<Record<IconNames, React.ComponentType>>;
@@ -15,8 +15,9 @@
*/
import React from 'react';
import { Box, BoxProps } from '../Box/Box';
import { Box } from '../Box/Box';
import { alignToFlexAlign } from '../../utils/align';
import type { BoxProps } from '../Box/types';
export const validInlineComponents = [
'div',
@@ -15,9 +15,9 @@
*/
import React from 'react';
import { Box, BoxProps } from '../Box/Box';
import { Box } from '../Box/Box';
import { alignToFlexAlign } from '../../utils/align';
import type { BoxProps } from '../Box/types';
const validStackComponents = [
'div',
'span',
@@ -15,39 +15,19 @@
*/
import React, { createContext, useContext, ReactNode } from 'react';
import { ArrowUp, ArrowDown, ArrowLeft, ArrowRight, Cloud } from 'lucide-react';
import { CustomIcon } from './custom-icon';
import { IconMap, IconNames } from '../components/Icon/types';
import { defaultIcons } from '../components/Icon/icons';
// List of icons available that can also be overridden.
/** @public */
export type IconNames =
| 'ArrowDown'
| 'ArrowLeft'
| 'ArrowRight'
| 'ArrowUp'
| 'Cloud'
| 'CustomIcon';
type IconMap = Partial<Record<IconNames, React.ComponentType>>;
interface IconContextProps {
interface ThemeContextProps {
icons: IconMap;
}
// Create a default icon map with only the necessary icons
const defaultIcons: IconMap = {
ArrowDown,
ArrowLeft,
ArrowRight,
ArrowUp,
Cloud,
CustomIcon,
};
const IconContext = createContext<IconContextProps>({ icons: defaultIcons });
const ThemeContext = createContext<ThemeContextProps>({
icons: defaultIcons,
});
/** @public */
export const IconProvider = ({
export const ThemeProvider = ({
children,
overrides,
}: {
@@ -58,11 +38,11 @@ export const IconProvider = ({
const combinedIcons = { ...defaultIcons, ...overrides };
return (
<IconContext.Provider value={{ icons: combinedIcons }}>
<ThemeContext.Provider value={{ icons: combinedIcons }}>
{children}
</IconContext.Provider>
</ThemeContext.Provider>
);
};
/** @public */
export const useIcons = () => useContext(IconContext);
export const useTheme = () => useContext(ThemeContext);
+4
View File
@@ -0,0 +1,4 @@
<svg width="640" height="640" viewBox="0 0 640 640" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M370.766 153.765C377.563 166.716 371.236 182.114 359.357 190.647C323.005 216.758 299.326 259.411 299.326 307.597C299.326 365.997 334.107 416.27 384.077 438.817C395.235 443.852 403.478 454.368 403.478 466.609V640H382.864C224.433 640 96 511.517 96 353.025L96 20.6143C96 9.22934 105.229 0 116.614 0V0C226.982 3.14552e-06 322.792 62.3523 370.766 153.765Z" fill="black"/>
<path d="M438.772 411.19C496.335 411.19 543 364.454 543 306.803C543 249.152 496.335 202.417 438.772 202.417C381.208 202.417 334.543 249.152 334.543 306.803C334.543 364.454 381.208 411.19 438.772 411.19Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 127 KiB

+1
View File
@@ -0,0 +1 @@
<svg width="89" height="27" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M77.414 9.71h3.036v2.992l-.264-.022c.279-.88.748-1.65 1.408-2.31.675-.66 1.533-.99 2.574-.99 1.086 0 1.9.352 2.442 1.056.558.689.836 1.598.836 2.728v7.502H84.41v-6.6c0-.66-.117-1.159-.352-1.496-.234-.338-.623-.506-1.166-.506-.601 0-1.122.271-1.562.814a4.321 4.321 0 0 0-.88 1.848v5.94h-3.036V9.71ZM69.868 21.04c-1.13 0-2.142-.257-3.036-.77a5.547 5.547 0 0 1-2.068-2.09c-.484-.895-.726-1.892-.726-2.992 0-1.115.242-2.112.726-2.992a5.503 5.503 0 0 1 2.068-2.112c.88-.514 1.892-.77 3.036-.77 1.144 0 2.156.256 3.036.77a5.347 5.347 0 0 1 2.046 2.112c.498.88.748 1.87.748 2.97 0 1.114-.25 2.12-.748 3.014a5.343 5.343 0 0 1-2.068 2.09c-.88.513-1.885.77-3.014.77Zm0-2.618c.557 0 1.048-.132 1.474-.396a2.79 2.79 0 0 0 .99-1.144c.234-.499.352-1.064.352-1.694 0-.63-.118-1.188-.352-1.672a2.764 2.764 0 0 0-.99-1.166c-.426-.279-.917-.418-1.474-.418-.558 0-1.05.14-1.474.418a2.764 2.764 0 0 0-.99 1.166c-.22.484-.33 1.041-.33 1.672 0 .63.11 1.195.33 1.694.234.484.564.865.99 1.144.425.264.916.396 1.474.396ZM52.385 9.71h3.036v2.992l-.264-.022c.279-.88.748-1.65 1.408-2.31.675-.66 1.533-.99 2.574-.99 1.085 0 1.9.352 2.442 1.056.557.689.836 1.598.836 2.728v7.502h-3.036v-6.6c0-.66-.117-1.159-.352-1.496-.235-.338-.623-.506-1.166-.506-.601 0-1.122.271-1.562.814a4.321 4.321 0 0 0-.88 1.848v5.94h-3.036V9.71ZM43.904 20.952c-1.026 0-1.87-.308-2.53-.924-.66-.616-.99-1.416-.99-2.398 0-1.115.418-2.01 1.254-2.684.85-.69 2.105-1.034 3.762-1.034h2.75l-.924.352v-.462c0-.572-.176-1.02-.528-1.342-.352-.338-.931-.506-1.738-.506-.69 0-1.386.154-2.09.462-.704.308-1.29.69-1.76 1.144v-2.882c.47-.352 1.1-.66 1.892-.924a7.942 7.942 0 0 1 2.486-.396c1.599 0 2.78.41 3.542 1.232.778.806 1.166 1.914 1.166 3.322v5.742c0 .176.008.352.022.528.03.161.066.322.11.484h-3.014v-3.3l.044 1.386a4.044 4.044 0 0 1-1.32 1.606c-.572.396-1.283.594-2.134.594Zm.858-2.156c.558 0 1.049-.206 1.474-.616.44-.426.77-.954.99-1.584v-.792h-1.562c-.762 0-1.334.146-1.716.44-.381.278-.572.674-.572 1.188 0 .41.125.74.374.99.264.25.602.374 1.012.374ZM34.66 21.04c-1.525 0-2.874-.345-4.047-1.034-1.174-.704-2.09-1.68-2.75-2.926-.646-1.247-.968-2.662-.968-4.246 0-1.584.322-2.992.968-4.224.66-1.232 1.576-2.193 2.75-2.882 1.173-.704 2.522-1.056 4.048-1.056.968 0 1.818.11 2.552.33.748.22 1.356.506 1.826.858v3.498c-.396-.484-.96-.895-1.694-1.232-.719-.338-1.51-.506-2.376-.506-.939 0-1.775.22-2.508.66-.719.44-1.284 1.056-1.694 1.848-.396.792-.594 1.694-.594 2.706 0 1.026.198 1.943.594 2.75.41.792.975 1.408 1.694 1.848.733.44 1.57.66 2.508.66.88 0 1.68-.162 2.398-.484.718-.323 1.276-.726 1.672-1.21v3.41a5.686 5.686 0 0 1-1.87.902c-.704.22-1.54.33-2.508.33ZM11.275 6.271c.276.526.019 1.152-.464 1.498a5.846 5.846 0 0 0 1.004 10.082c.454.205.789.632.789 1.13v6.206a.837.837 0 0 1-.838.837C5.33 26.024.112 20.804.112 14.366V.862C.112.399.487.024.95.024c4.483 0 8.376 2.533 10.325 6.247Z" fill="#000"/><path d="M14.037 16.729a4.237 4.237 0 0 0 4.234-4.24 4.237 4.237 0 0 0-4.234-4.242 4.237 4.237 0 0 0-4.234 4.241 4.237 4.237 0 0 0 4.234 4.24Z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

+10 -10
View File
@@ -3823,6 +3823,7 @@ __metadata:
"@backstage/cli": "workspace:^"
"@base_ui/react": ^1.0.0-alpha.3
"@chromatic-com/storybook": ^3.2.2
"@remixicon/react": ^4.5.0
"@storybook/addon-essentials": ^8.4.5
"@storybook/addon-interactions": ^8.4.5
"@storybook/addon-styling-webpack": ^1.0.1
@@ -3843,7 +3844,6 @@ __metadata:
"@vanilla-extract/webpack-plugin": ^2.3.14
eslint-plugin-storybook: ^0.11.1
globals: ^15.11.0
lucide-react: ^0.460.0
mini-css-extract-plugin: ^2.9.2
react: ^18.0.2
react-dom: ^18.0.2
@@ -15458,6 +15458,15 @@ __metadata:
languageName: node
linkType: hard
"@remixicon/react@npm:^4.5.0":
version: 4.5.0
resolution: "@remixicon/react@npm:4.5.0"
peerDependencies:
react: ">=18.2.0"
checksum: e37b61090954954601d35367a740b7be30c105a49f67eaa5a697db16d4668d71d9fd94b339da6d449a254736d5af3b567d3694021b79d3c82fe28afb818830bc
languageName: node
linkType: hard
"@repeaterjs/repeater@npm:^3.0.4":
version: 3.0.5
resolution: "@repeaterjs/repeater@npm:3.0.5"
@@ -35193,15 +35202,6 @@ __metadata:
languageName: node
linkType: hard
"lucide-react@npm:^0.460.0":
version: 0.460.0
resolution: "lucide-react@npm:0.460.0"
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc
checksum: 6106dc16dd7ce7928d6136e81c9e84e87e1b6b0910a0c78777a387c795c0512755e8bf4c602ab8f09518919999a494ed86ba7190863e8e7aec6c82665147ead3
languageName: node
linkType: hard
"lunr@npm:^2.3.9":
version: 2.3.9
resolution: "lunr@npm:2.3.9"