diff --git a/packages/canon/package.json b/packages/canon/package.json index 95fb5f0373..cf818a230d 100644 --- a/packages/canon/package.json +++ b/packages/canon/package.json @@ -40,7 +40,8 @@ "@vanilla-extract/css": "^1.16.0", "@vanilla-extract/dynamic": "^2.1.2", "@vanilla-extract/recipes": "^0.5.5", - "@vanilla-extract/sprinkles": "^1.6.3" + "@vanilla-extract/sprinkles": "^1.6.3", + "lucide-react": "^0.460.0" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/canon/src/components/icon/context.tsx b/packages/canon/src/components/icon/context.tsx new file mode 100644 index 0000000000..9246642bab --- /dev/null +++ b/packages/canon/src/components/icon/context.tsx @@ -0,0 +1,40 @@ +import React, { createContext, useContext, ReactNode } from 'react'; +import { MoveUp, MoveDown } from 'lucide-react'; +import { CustomIcon } from './custom-icon'; + +// List of icons available that can also be overridden. +export type IconNames = 'MoveDown' | 'MoveUp' | 'CustomIcon'; + +type IconMap = Partial>; + +interface IconContextProps { + icons: IconMap; +} + +// Create a default icon map with only the necessary icons +const defaultIcons: IconMap = { + MoveUp, + MoveDown, + CustomIcon, +}; + +const IconContext = createContext({ icons: defaultIcons }); + +export const IconProvider = ({ + children, + overrides, +}: { + children: ReactNode; + overrides: IconMap; +}) => { + // Merge provided overrides with default icons + const combinedIcons = { ...defaultIcons, ...overrides }; + + return ( + + {children} + + ); +}; + +export const useIcons = () => useContext(IconContext); diff --git a/packages/canon/src/components/icon/custom-icon.tsx b/packages/canon/src/components/icon/custom-icon.tsx new file mode 100644 index 0000000000..2b190b6ade --- /dev/null +++ b/packages/canon/src/components/icon/custom-icon.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export const CustomIcon = () => ( + + + +); diff --git a/packages/canon/src/components/icon/icon.stories.tsx b/packages/canon/src/components/icon/icon.stories.tsx new file mode 100644 index 0000000000..e04b6caaf7 --- /dev/null +++ b/packages/canon/src/components/icon/icon.stories.tsx @@ -0,0 +1,66 @@ +import React from 'react'; +import { Meta, StoryObj } from '@storybook/react'; +import { Icon } from './icon'; +import { IconProvider } from './context'; +import * as LucideIcons from 'lucide-react'; + +const meta = { + title: 'Components/Icon', + component: Icon, + parameters: { + layout: 'centered', + }, + tags: ['autodocs'], + argTypes: { + name: { + control: 'select', + options: Object.keys(LucideIcons), + }, + }, + args: { + name: 'MoveDown', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + name: 'MoveDown', + }, +}; + +export const CustomIcon: Story = { + args: { + name: 'CustomIcon', + }, +}; + +export const WithCustomIcon: Story = { + args: { + name: 'MoveDown', + }, + decorators: [ + Story => ( +
Custom Icon
}}> + +
+ ), + ], +}; + +export const WithCustomIconOverride: Story = { + args: { + name: 'CustomIcon', + }, + decorators: [ + Story => ( +
Custom Super Icon
}} + > + +
+ ), + ], +}; diff --git a/packages/canon/src/components/icon/icon.tsx b/packages/canon/src/components/icon/icon.tsx new file mode 100644 index 0000000000..2a6ca449ca --- /dev/null +++ b/packages/canon/src/components/icon/icon.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { useIcons, IconNames } from './context'; + +export const Icon = ({ name }: { name: IconNames }) => { + const { icons } = useIcons(); + + const LucideIcon = icons[name]; + + if (!LucideIcon) { + console.error(`Icon "${name}" not found.`); + return ; // Return default icon perhaps? + } + + return ; +}; diff --git a/packages/canon/src/components/icon/index.tsx b/packages/canon/src/components/icon/index.tsx new file mode 100644 index 0000000000..7ae853ecbf --- /dev/null +++ b/packages/canon/src/components/icon/index.tsx @@ -0,0 +1,2 @@ +export * from './icon'; +export * from './context'; diff --git a/packages/canon/src/docs/Theme.mdx b/packages/canon/src/docs/Theme.mdx index ad25eb924e..05407c9f3c 100644 --- a/packages/canon/src/docs/Theme.mdx +++ b/packages/canon/src/docs/Theme.mdx @@ -42,8 +42,7 @@ import * as Table from '../storybook/table'; --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'; + --canon-font-mono: 'Monospace', monospace; /* ... other values */ } @@ -58,8 +57,7 @@ import * as Table from '../storybook/table'; --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'; + --canon-font-mono: 'Monospace', monospace; /* ... other values */ } `} @@ -68,6 +66,11 @@ import * as Table from '../storybook/table'; /> Colors + + We provide a set of generic colours tokens that we use across Canon. By + changing these colours you can easily change the look and feel of your + application to match your brand. + @@ -88,13 +91,73 @@ import * as Table from '../storybook/table'; The background color for the theme. + + + --canon-surface-1 + + The first surface color for the theme. + + + + --canon-surface-2 + + The second surface color for the theme. + + + + --canon-outline + + The outline color for the theme. + + + + --canon-outline-focus + + The outline focus color for the theme. + + + + --canon-text-primary + + The primary text color for the theme. + + + + --canon-text-secondary + + The secondary text color for the theme. + Typography - Our theming is system is still a work in progress. We will be adding more - features and documentation over time. + We have two fonts that we use across Canon. The first one is the sans-serif + font that we use for the body of the application. The second one is the + monospace font that we use for code blocks and tables. + + + + Prop + Description + + + + + + --canon-font-sans + + The sans-serif font for the theme. + + + + --canon-font-mono + + The monospace font for the theme. + + + + diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts index 6c879078e1..00637cb154 100644 --- a/packages/canon/src/index.ts +++ b/packages/canon/src/index.ts @@ -15,5 +15,6 @@ */ // Components -export { Button } from './components/button/button'; -export { Box } from './components/box/box'; +export * from './components/button/button'; +export * from './components/box/box'; +export * from './components/icon'; diff --git a/packages/canon/src/storybook/text/text.css.ts b/packages/canon/src/storybook/text/text.css.ts index fb6f648655..405f89a0de 100644 --- a/packages/canon/src/storybook/text/text.css.ts +++ b/packages/canon/src/storybook/text/text.css.ts @@ -17,7 +17,7 @@ import { globalStyle, style } from '@vanilla-extract/css'; export const textStyles = style({ fontFamily: '"Geist", sans-serif', - fontSize: '18px', + fontSize: '16px', lineHeight: '28px', margin: '0', fontWeight: '300', @@ -26,7 +26,7 @@ export const textStyles = style({ globalStyle(`${textStyles} p`, { fontFamily: '"Geist", sans-serif', - fontSize: '18px', + fontSize: '16px', lineHeight: '28px', margin: '0', fontWeight: '300', diff --git a/packages/canon/src/storybook/title/title.css.ts b/packages/canon/src/storybook/title/title.css.ts index 7c49825206..b8d9ad2796 100644 --- a/packages/canon/src/storybook/title/title.css.ts +++ b/packages/canon/src/storybook/title/title.css.ts @@ -25,8 +25,8 @@ export const titleStyles = recipe({ variants: { type: { h1: { - fontSize: '40px', - lineHeight: '48px', + fontSize: '36px', + lineHeight: '44px', marginBottom: '32px', marginTop: '0px', }, diff --git a/yarn.lock b/yarn.lock index f18b26cae8..8257257f38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4131,6 +4131,7 @@ __metadata: eslint-plugin-react-refresh: ^0.4.13 eslint-plugin-storybook: ^0.11.0 globals: ^15.11.0 + lucide-react: ^0.460.0 mini-css-extract-plugin: ^2.9.2 storybook: ^8.4.4 typescript: ~5.6.2 @@ -35994,6 +35995,15 @@ __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"