diff --git a/apps/mobile/App.tsx b/apps/mobile/App.tsx index d600682a..e7ab58a6 100644 --- a/apps/mobile/App.tsx +++ b/apps/mobile/App.tsx @@ -7,8 +7,8 @@ import { useState } from 'react' import { Code, Heading, - Image, Label, + Messages, Paragraph, Shape, Sidebar, @@ -38,13 +38,6 @@ export default function App() { - @@ -74,12 +68,15 @@ export default function App() { This is a code line 0x213abc190 ... 121ah4a9e + Theme selected - {theme} setTheme(theme === 'dark' ? 'light' : 'dark')} > Toogle theme + + diff --git a/apps/vite/package.json b/apps/vite/package.json index 7574872f..ce5345f2 100644 --- a/apps/vite/package.json +++ b/apps/vite/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@status-im/components": "*", + "@status-im/icons": "*", "@tamagui/core": "1.0.15", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/apps/vite/src/app.tsx b/apps/vite/src/app.tsx index 7beb72e9..7257d424 100644 --- a/apps/vite/src/app.tsx +++ b/apps/vite/src/app.tsx @@ -5,6 +5,7 @@ import { Code, Heading, Label, + Messages, Paragraph, Shape, Sidebar, @@ -12,11 +13,13 @@ import { import { Stack, TamaguiProvider } from '@tamagui/core' import tamaguiConfig from '../tamagui.config' +import { Topbar } from './components/topbar' type ThemeVars = 'light' | 'dark' function App() { const [theme, setTheme] = useState('light') + const [showMembers, setShowMembers] = useState(false) return ( @@ -30,14 +33,13 @@ function App() {
- - Topbar - -
+ setShowMembers(show => !show)} + /> +
+ + Composer
+ + {showMembers &&
members
}
) diff --git a/apps/vite/src/components/circle.tsx b/apps/vite/src/components/circle.tsx deleted file mode 100644 index 73779503..00000000 --- a/apps/vite/src/components/circle.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { Stack, styled } from '@tamagui/core' - -export const Circle = styled(Stack, { - // access your tokens and theme values easily with $ props - - backgroundColor: 'red', - borderRadius: '100%', - width: 100, - height: 100 - // borderRadius: '$4', - // // media and pseudo styles - this would take 15+ lines of brittle JS in RN - - // $gtSm: { - // pressStyle: { - // borderRadius: '$6' - // } - // }, - // variants: { - // // define variants - - // // these will flatten, even when nesting multiple styled() calls - - // pin: { - // top: { - // position: 'absolute', - - // top: 0 - // } - // }, - // size: { - // // functional variants give incredible power and save bundle size - - // '...size': (size, { tokens }) => { - // return { - // width: tokens.size[size] ?? size, - - // height: tokens.size[size] ?? size - // } - // } - // } - // } as const -}) diff --git a/apps/vite/src/components/topbar.tsx b/apps/vite/src/components/topbar.tsx new file mode 100644 index 00000000..c3bf872b --- /dev/null +++ b/apps/vite/src/components/topbar.tsx @@ -0,0 +1,42 @@ +import { Divider, IconButton, Paragraph } from '@status-im/components' +import { LockedIcon, MembersIcon, OptionsIcon } from '@status-im/icons' +import { Stack } from '@tamagui/core' + +type Props = { + membersVisisble: boolean + onMembersPress: () => void +} + +export const Topbar = (props: Props) => { + const { membersVisisble, onMembersPress } = props + + return ( + + + + # random + + + + + Share random funny stuff with the community. Play nice. + + + + + } + selected={membersVisisble} + onPress={onMembersPress} + /> + } /> + + + ) +} diff --git a/apps/vite/styles/app.css b/apps/vite/styles/app.css index 50e912be..afc3facd 100644 --- a/apps/vite/styles/app.css +++ b/apps/vite/styles/app.css @@ -8,15 +8,18 @@ body, #app { height: 100%; display: grid; - grid-template-columns: 352px 1fr; + grid-template-columns: 352px 1fr auto; } #main { display: grid; grid-template-rows: 56px 1fr 100px; + height: 100vh; } #main, +#sidebar, +#members, #main > div { border: 1px solid rgba(0, 0, 0, 0.1); } @@ -25,3 +28,13 @@ body, overflow: auto; height: 100vh; } + +#content { + overflow: auto; + padding: 8px; +} + +#members { + width: 352px; + color: #000; +} diff --git a/packages/components/package.json b/packages/components/package.json index b34be96b..ecb2295d 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -29,6 +29,7 @@ "@tamagui/react-native-media-driver": "1.0.15", "@tamagui/shorthands": "1.0.15", "@tamagui/theme-base": "1.0.15", + "@status-im/icons": "*", "tamagui": "1.0.15" }, "devDependencies": { diff --git a/packages/components/src/avatar/avatar.tsx b/packages/components/src/avatar/avatar.tsx index 10c3c817..0e831353 100644 --- a/packages/components/src/avatar/avatar.tsx +++ b/packages/components/src/avatar/avatar.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react' -import { Stack, styled, Text } from '@tamagui/core' +import { Stack, styled, Text, Unspaced } from '@tamagui/core' import { Image } from '../image' @@ -66,6 +66,66 @@ const Base = styled(Stack, { } as const, }) +const Indicator = styled(Stack, { + name: 'Indicator', + + position: 'absolute', + width: 8, + height: 8, + bottom: 0, + right: 0, + zIndex: 2, + // borderWidth: 2, + // borderColor: 'rgba(255,255,0,1.0)', + + variants: { + size: { + 56: { + width: 10, + height: 10, + borderRadius: 10 / 2, + }, + // FIXME: use catch all variant + 52: { + width: 8, + height: 8, + borderRadius: 8 / 2, + }, + 48: { + width: 8, + height: 8, + borderRadius: 8 / 2, + }, + 32: { + width: 8, + height: 8, + borderRadius: 8 / 2, + }, + 20: { + width: 8, + height: 8, + borderRadius: 8 / 2, + }, + }, + + state: { + online: { + backgroundColor: '$success-50', + }, + offline: { + backgroundColor: '$neutral-40', + }, + }, + + shape: { + circle: {}, + rounded: { + borderRadius: 16, + }, + }, + } as const, +}) + const Fallback = styled(Text, { name: 'AvatarFallback', }) @@ -83,7 +143,7 @@ interface Props { type ImageLoadingStatus = 'idle' | 'loading' | 'loaded' | 'error' const Avatar = (props: Props) => { - const { src, size, shape = 'circle', withOutline } = props + const { src, size, shape = 'circle', withOutline, indicator } = props const [status, setStatus] = useState('idle') @@ -93,13 +153,21 @@ const Avatar = (props: Props) => { return ( - setStatus('loaded')} - onError={() => setStatus('error')} - /> + {indicator && ( + + + + )} + + setStatus('loaded')} + onError={() => setStatus('error')} + /> + + {status === 'error' && ( type Props = { @@ -46,9 +47,12 @@ const Button = (props: Props) => { return ( - {children} + + {children} + ) } export { Button } +export type { Props as ButtonProps } diff --git a/packages/components/src/chat-message/chat-message.stories.tsx b/packages/components/src/chat-message/chat-message.stories.tsx new file mode 100644 index 00000000..d815f0ca --- /dev/null +++ b/packages/components/src/chat-message/chat-message.stories.tsx @@ -0,0 +1,50 @@ +import { ChatMessage } from './chat-message' + +import type { Meta, StoryObj } from '@storybook/react' + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta: Meta = { + component: ChatMessage, + argTypes: {}, + parameters: { + design: { + type: 'figma', + url: 'https://www.figma.com/file/IBmFKgGL1B4GzqD8LQTw6n/Design-System-for-Web?node-id=611%3A36006&t=Gyy71OAckl3b2TWj-4', + }, + }, +} + +type Story = StoryObj + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Simple: Story = { + args: { + text: 'This is a simple message.', + }, +} + +export const SimpleLongText: Story = { + args: { + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + }, +} + +export const SimpleWithReactions: Story = { + name: 'Simple with reactions', + args: { + text: 'This is a simple message.', + reactions: ['thumb'], + }, +} + +export const Image: Story = { + args: { + images: [ + { + url: 'https://images.unsplash.com/photo-1673831792265-68b44126c999?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=866&q=80', + }, + ], + }, +} + +export default meta diff --git a/packages/components/src/chat-message/chat-message.tsx b/packages/components/src/chat-message/chat-message.tsx new file mode 100644 index 00000000..2d18a763 --- /dev/null +++ b/packages/components/src/chat-message/chat-message.tsx @@ -0,0 +1,87 @@ +import React from 'react' + +import { Stack, Unspaced, XStack, YStack } from 'tamagui' + +import { Avatar } from '../avatar' +import { Image } from '../image' +import { Paragraph } from '../typography' +import { Actions } from './components/actions' +import { Reactions } from './components/reactions' + +interface Props { + text?: React.ReactNode + images?: Array<{ url: string }> + reactions?: [] +} + +const ChatMessage = (props: Props) => { + const { text, images, reactions } = props + + const [hovered, setHovered] = React.useState(false) + + return ( + setHovered(true)} + onHoverOut={() => setHovered(false)} + > + {hovered && ( + + + + )} + + + + + + + Alisher Yakupov + + + zQ3...9d4Gs0 + + + 09:30 + + + + {text && ( + + {text} + + )} + + {images?.map(image => ( + + + + ))} + + {reactions && } + + + ) +} + +export { ChatMessage } diff --git a/packages/components/src/chat-message/components/actions.tsx b/packages/components/src/chat-message/components/actions.tsx new file mode 100644 index 00000000..bc3e1d2d --- /dev/null +++ b/packages/components/src/chat-message/components/actions.tsx @@ -0,0 +1,15 @@ +import { Stack } from 'tamagui' + +import { Paragraph } from '../../typography' + +interface Props { + onClick: VoidFunction +} + +export const Actions = (_props: Props) => { + return ( + + actions + + ) +} diff --git a/packages/components/src/chat-message/components/reactions.tsx b/packages/components/src/chat-message/components/reactions.tsx new file mode 100644 index 00000000..66af3659 --- /dev/null +++ b/packages/components/src/chat-message/components/reactions.tsx @@ -0,0 +1,31 @@ +import { Pressable } from 'react-native' +import { Stack, XStack, YStack } from 'tamagui' + +interface Props {} + +const ReactionButton = ({ type }) => { + return ( + + {type} + + ) +} + +export const Reactions = (props: Props) => { + const {} = props + + return ( + + + + + + + + ) +} diff --git a/packages/components/src/chat-message/index.tsx b/packages/components/src/chat-message/index.tsx new file mode 100644 index 00000000..1eff084f --- /dev/null +++ b/packages/components/src/chat-message/index.tsx @@ -0,0 +1,26 @@ +import { ChatMessage } from './chat-message' + +export * from './chat-message' + +export const Messages = () => { + return ( + <> + + + + + + + + + + + + ) +} diff --git a/packages/components/src/divider/divider.tsx b/packages/components/src/divider/divider.tsx new file mode 100644 index 00000000..897d4dd9 --- /dev/null +++ b/packages/components/src/divider/divider.tsx @@ -0,0 +1,32 @@ +import { Stack, styled } from '@tamagui/core' + +export const Divider = styled(Stack, { + name: 'Divider', + backgroundColor: '$neutral-10', + flexShrink: 0, + // borderWidth: 0, + flex: 1, + height: '100%', + // maxHeight: 0, + width: 1, + marginHorizontal: 12, + // y: -0.5, + + variants: { + // vertical: { + // true: { + // y: 0, + // x: -0.5, + // height: isWeb ? 'initial' : 'auto', + // // maxHeight auto WILL BE passed to style attribute, but for some reason not used? + // // almost seems like a react or browser bug, but for now `initial` works + // // also, it doesn't happen for `height`, but for consistency using the same values + // maxHeight: isWeb ? 'initial' : 'auto', + // width: 0, + // maxWidth: 0, + // borderBottomWidth: 0, + // borderRightWidth: 1, + // }, + // }, + } as const, +}) diff --git a/packages/components/src/divider/index.tsx b/packages/components/src/divider/index.tsx new file mode 100644 index 00000000..53d72785 --- /dev/null +++ b/packages/components/src/divider/index.tsx @@ -0,0 +1 @@ +export * from './divider' diff --git a/packages/components/src/global.ts b/packages/components/src/global.ts deleted file mode 100644 index 68d9aaca..00000000 --- a/packages/components/src/global.ts +++ /dev/null @@ -1,11 +0,0 @@ -// eslint-disable-next-line eslint-comments/disable-enable-pair -/* eslint-disable @typescript-eslint/no-empty-interface */ -import { config } from './tamagui.config' - -export type Conf = typeof config - -declare module '@tamagui/core' { - interface TamaguiCustomConfig extends Conf {} -} - -export default config diff --git a/packages/components/src/icon-button/icon-button.stories.tsx b/packages/components/src/icon-button/icon-button.stories.tsx new file mode 100644 index 00000000..cd5ee552 --- /dev/null +++ b/packages/components/src/icon-button/icon-button.stories.tsx @@ -0,0 +1,22 @@ +import { OptionsIcon } from '@status-im/icons' + +import { IconButton } from './icon-button' + +import type { Meta, StoryObj } from '@storybook/react' + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta: Meta = { + component: IconButton, + argTypes: {}, +} + +type Story = StoryObj + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const Default: Story = { + args: { + icon: , + }, +} + +export default meta diff --git a/packages/components/src/icon-button/icon-button.tsx b/packages/components/src/icon-button/icon-button.tsx new file mode 100644 index 00000000..82e8531a --- /dev/null +++ b/packages/components/src/icon-button/icon-button.tsx @@ -0,0 +1,72 @@ +import { Stack, styled, Text } from '@tamagui/core' + +// import { Pressable } from 'react-native' +import type React from 'react' + +const Base = styled(Stack, { + name: 'IconButton', + accessibilityRole: 'button', + + cursor: 'pointer', + userSelect: 'none', + borderRadius: 10, + display: 'inline-flex', + alignItems: 'center', + justifyContent: 'center', + + width: 31, + height: 31, + borderWidth: 1, + backgroundColor: '$neutral-10', + borderColor: '$neutral-10', + + hoverStyle: { + backgroundColor: '$neutral-20', + }, + + variants: { + selected: { + true: { + backgroundColor: '$neutral-30', + borderColor: '$neutral-30', + }, + }, + } as const, +}) + +const Icon = styled(Text, { + color: '$neutral-50', + width: 20, + height: 20, + + hoverStyle: { + color: '$neutral-100', + }, + + variants: { + selected: { + true: { + color: '$neutral-100', + }, + }, + } as const, +}) + +interface Props { + icon: React.ReactElement + onPress?: () => void + selected?: boolean +} + +const IconButton = (props: Props) => { + const { icon, selected, onPress } = props + + return ( + + {icon} + + ) +} + +export { IconButton } +export type { Props as IconButtonProps } diff --git a/packages/components/src/icon-button/index.tsx b/packages/components/src/icon-button/index.tsx new file mode 100644 index 00000000..6f6c2f53 --- /dev/null +++ b/packages/components/src/icon-button/index.tsx @@ -0,0 +1 @@ +export { type IconButtonProps, IconButton } from './icon-button' diff --git a/packages/components/src/icons/icons.stories.tsx b/packages/components/src/icons/icons.stories.tsx new file mode 100644 index 00000000..f864d1d5 --- /dev/null +++ b/packages/components/src/icons/icons.stories.tsx @@ -0,0 +1,48 @@ +import * as icons from '@status-im/icons' + +import { Text } from '../typography' + +import type { IconProps } from '@status-im/icons' +import type { Meta, StoryObj } from '@storybook/react' +import type React from 'react' + +// More on how to set up stories at: https://storybook.js.org/docs/7.0/react/writing-stories/introduction +const meta: Meta = { + title: 'icons', + // component: Button, + argTypes: {}, +} + +type Story = StoryObj + +function unpascal(str: string) { + return str.replace(/([A-Z])/g, ' $1').trim() +} + +// More on writing stories with args: https://storybook.js.org/docs/7.0/react/writing-stories/args +export const All: Story = { + args: {}, + render: () => { + return ( +
+ {Object.keys(icons).map(name => { + // @ts-ignore + // eslint-disable-next-line import/namespace + const Icon = icons[name] as React.FunctionComponent + + return ( +
+ + {unpascal(name)} +
+ ) + })} +
+ ) + }, +} + +export default meta diff --git a/packages/components/src/image/image.tsx b/packages/components/src/image/image.tsx index 4e33c3f5..30280d32 100644 --- a/packages/components/src/image/image.tsx +++ b/packages/components/src/image/image.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef } from 'react' +import { forwardRef } from 'react' import { isWeb, setupReactNative, styled } from '@tamagui/core' import { Image as RNImage } from 'react-native' @@ -16,32 +16,48 @@ setupReactNative({ const Base = styled(RNImage, { name: 'Image', position: 'relative', - source: { uri: '' }, zIndex: 1, + source: { + uri: '', + }, }) type InputProps = GetProps +// type W = InputProps['width'] + interface Props { src: string - width: number - height: number + width: number | 'full' + height?: number + aspectRatio?: number // onLoad?: InputProps['onLoad'] // onError?: InputProps['onError'] } const Image = (props: Props, ref: Ref) => { - const { src } = props + const { src, aspectRatio, ...rest } = props - const source = - typeof src === 'string' - ? { - uri: src, - ...(isWeb && { width: props.width, height: props.height }), - } - : src + const width = props.width === 'full' ? '100%' : props.width + const height = aspectRatio ? undefined : props.height - return + const source = { + uri: src, + ...(isWeb && { width, height }), + } + + return ( + + ) } // focusableInputHOC(Image) diff --git a/packages/components/src/index.tsx b/packages/components/src/index.tsx index 4a0a52da..d76bae03 100644 --- a/packages/components/src/index.tsx +++ b/packages/components/src/index.tsx @@ -1,4 +1,7 @@ export * from './button' +export * from './chat-message' +export * from './divider' +export * from './icon-button' export * from './image' export * from './input' export * from './shape' diff --git a/packages/components/src/sidebar/sidebar.tsx b/packages/components/src/sidebar/sidebar.tsx index 899ad794..1a3005d4 100644 --- a/packages/components/src/sidebar/sidebar.tsx +++ b/packages/components/src/sidebar/sidebar.tsx @@ -5,6 +5,7 @@ import { Stack } from '@tamagui/core' import { Accordion } from '../accordion/accordion' import { AccordionItem } from '../accordion/accordionItem' import { Avatar } from '../avatar' +import { Button } from '../button' // import { Button } from '../button' import { Basketball, Collaboration, Fire, Peach, Play, Unicorn } from '../emoji' import { Group } from '../icon' @@ -198,7 +199,7 @@ const COMMUNITIES_EXPAND_CONTROL = COMMUNITIES.reduce( {} as Record[] ) -const _Sidebar = (props: Props) => { +const Sidebar = (props: Props) => { const { name, description, membersCount } = props const [isExpanded, setIsExpanded] = useState({ ...COMMUNITIES_EXPAND_CONTROL, @@ -218,8 +219,8 @@ const _Sidebar = (props: Props) => { { borderTopRightRadius={20} zIndex={10} > - + { {membersCount} + + {COMMUNITIES.map(community => ( { ) } -export const Sidebar = _Sidebar +export { Sidebar } diff --git a/packages/components/src/tamagui.config.ts b/packages/components/src/tamagui.config.ts index 345c6e19..84cc475d 100644 --- a/packages/components/src/tamagui.config.ts +++ b/packages/components/src/tamagui.config.ts @@ -7,6 +7,13 @@ import { animations } from './animations' import { themes } from './themes' import { tokens } from './tokens' +export type Conf = typeof config + +declare module '@tamagui/core' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface TamaguiCustomConfig extends Conf {} +} + const interFont = createInterFont({ size: { 6: 11, diff --git a/packages/components/src/typography/typography.stories.tsx b/packages/components/src/typography/typography.stories.tsx new file mode 100644 index 00000000..f645fced --- /dev/null +++ b/packages/components/src/typography/typography.stories.tsx @@ -0,0 +1,60 @@ +import { Stack } from '@tamagui/core' + +import { Code, Heading, Paragraph } from '.' + +import type { Meta, StoryObj } from '@storybook/react' + +const meta: Meta = { + title: 'typography', + argTypes: {}, +} + +export const HeadingStory: StoryObj = { + name: 'Heading', + args: { + children: 'The quick brown fox jumped over the lazy dog.', + }, + render: args => ( + + + + + + + + + ), +} + +export const TextStory: StoryObj = { + name: 'Text', + args: { + children: 'The quick brown fox jumped over the lazy dog.', + }, + render: args => ( + + + + + + + + + ), +} + +export const CodeStory: StoryObj = { + name: 'Code', + args: { + children: '// How to create variables:', + }, + render: () => ( + + + The quick brown fox jumped over the lazy dog. + + + ), +} + +export default meta diff --git a/packages/components/src/typography/typography.tsx b/packages/components/src/typography/typography.tsx index 23d929e6..21c5b0dc 100644 --- a/packages/components/src/typography/typography.tsx +++ b/packages/components/src/typography/typography.tsx @@ -60,6 +60,11 @@ export const Paragraph = styled(SizableText, { lineHeight: 18, letterSpacing: '-0.003em', }, + 11: { + fontSize: 11, + lineHeight: 18, + letterSpacing: '-0.003em', + }, }, uppercase: { true: { diff --git a/packages/icons/package.json b/packages/icons/package.json new file mode 100644 index 00000000..ff22cfbd --- /dev/null +++ b/packages/icons/package.json @@ -0,0 +1,28 @@ +{ + "name": "@status-im/icons", + "version": "0.0.1", + "types": "src/index.tsx", + "main": "src/index.tsx", + "private": true, + "files": [ + "types", + "dist" + ], + "scripts": { + "dev": "vite build --watch --mode development", + "build": "vite build", + "postbuild": "yarn typegen", + "#test": "vitest", + "typecheck": "tsc", + "typegen": "tsc --noEmit false --emitDeclarationOnly || true", + "lint": "eslint src", + "format": "prettier --write src", + "clean": "rm -rf dist node_modules .turbo" + }, + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x" + }, + "devDependencies": { + "vite": "^4.0.4" + } +} diff --git a/packages/icons/src/index.tsx b/packages/icons/src/index.tsx new file mode 100644 index 00000000..6bed9823 --- /dev/null +++ b/packages/icons/src/index.tsx @@ -0,0 +1,4 @@ +export { LockedIcon } from './lock-icon' +export { MembersIcon } from './members-icon' +export { OptionsIcon } from './options-icon' +export type { IconProps } from './types' diff --git a/packages/icons/src/lock-icon.tsx b/packages/icons/src/lock-icon.tsx new file mode 100644 index 00000000..bae74102 --- /dev/null +++ b/packages/icons/src/lock-icon.tsx @@ -0,0 +1,24 @@ +import type { IconProps } from './types' + +export function LockedIcon(props: IconProps) { + const { color = 'currentColor', size = 20, ...rest } = props + + // FIXME: not need to differentiate sizes in the designs + return ( + + + + ) +} diff --git a/packages/icons/src/members-icon.tsx b/packages/icons/src/members-icon.tsx new file mode 100644 index 00000000..83f3a9f5 --- /dev/null +++ b/packages/icons/src/members-icon.tsx @@ -0,0 +1,29 @@ +import type { IconProps } from './types' + +export function MembersIcon(props: IconProps) { + const { color = 'currentColor', size = 20, ...rest } = props + + return ( + + + + + ) +} diff --git a/packages/icons/src/options-icon.tsx b/packages/icons/src/options-icon.tsx new file mode 100644 index 00000000..99a030c2 --- /dev/null +++ b/packages/icons/src/options-icon.tsx @@ -0,0 +1,20 @@ +import type { IconProps } from './types' + +export function OptionsIcon(props: IconProps) { + const { color = 'currentColor', size = 20, ...rest } = props + + return ( + + + + + + ) +} diff --git a/packages/icons/src/types.ts b/packages/icons/src/types.ts new file mode 100644 index 00000000..bff24855 --- /dev/null +++ b/packages/icons/src/types.ts @@ -0,0 +1,9 @@ +import type { SVGAttributes } from 'react' + +export interface IconProps extends SVGAttributes { + children?: never + width?: never + height?: never + color?: string + size?: number +} diff --git a/packages/icons/tsconfig.json b/packages/icons/tsconfig.json new file mode 100644 index 00000000..bbbb84f2 --- /dev/null +++ b/packages/icons/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src"], + "compilerOptions": { + "outDir": "./dist", + "declarationDir": "dist/types", + "resolveJsonModule": true + } +} diff --git a/packages/icons/vite.config.ts b/packages/icons/vite.config.ts new file mode 100644 index 00000000..8595de6d --- /dev/null +++ b/packages/icons/vite.config.ts @@ -0,0 +1,39 @@ +/// + +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' + +import { peerDependencies } from './package.json' + +const external = [ + // ...Object.keys(dependencies || {}), + ...Object.keys(peerDependencies || {}), +].map(name => new RegExp(`^${name}(/.*)?`)) + +export default defineConfig(({ mode }) => { + return { + build: { + target: 'es2020', + lib: { + entry: './src/index.tsx', + fileName: 'index', + formats: ['es'], + }, + sourcemap: true, + emptyOutDir: mode === 'production', + rollupOptions: { + external, + }, + }, + + plugins: [react()], + + // plugins: [ + // react(), + // ], + + test: { + environment: 'happy-dom', + }, + } +})