tinywidgets 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.eslintrc.json +91 -0
  2. package/.prettierrc +5 -0
  3. package/bun.lockb +0 -0
  4. package/index.css.ts +1 -0
  5. package/index.ts +11 -0
  6. package/media.ts +1 -0
  7. package/package.json +27 -2
  8. package/src/Avatar/index.css.ts +17 -0
  9. package/src/Avatar/index.tsx +28 -0
  10. package/src/Axis/index.css.ts +19 -0
  11. package/src/Axis/index.tsx +38 -0
  12. package/src/Button/index.css.ts +57 -0
  13. package/src/Button/index.tsx +65 -0
  14. package/src/Card/index.css.ts +9 -0
  15. package/src/Card/index.tsx +15 -0
  16. package/src/Collapsible/index.css.ts +34 -0
  17. package/src/Collapsible/index.tsx +69 -0
  18. package/src/Detail/index.css.ts +19 -0
  19. package/src/Detail/index.tsx +28 -0
  20. package/src/Hr/index.css.ts +10 -0
  21. package/src/Hr/index.tsx +10 -0
  22. package/src/Metric/index.css.ts +18 -0
  23. package/src/Metric/index.tsx +28 -0
  24. package/src/Summary/index.css.ts +17 -0
  25. package/src/Summary/index.tsx +34 -0
  26. package/src/Tag/index.css.ts +27 -0
  27. package/src/Tag/index.tsx +28 -0
  28. package/src/Ui/Layout/Header/DarkButton/index.tsx +20 -0
  29. package/src/Ui/Layout/Header/SideNav/index.css.ts +23 -0
  30. package/src/Ui/Layout/Header/SideNav/index.tsx +16 -0
  31. package/src/Ui/Layout/Header/SideNavButton/index.css.ts +4 -0
  32. package/src/Ui/Layout/Header/SideNavButton/index.tsx +17 -0
  33. package/src/Ui/Layout/Header/Title/index.css.ts +10 -0
  34. package/src/Ui/Layout/Header/Title/index.tsx +10 -0
  35. package/src/Ui/Layout/Header/TopNav/index.css.ts +9 -0
  36. package/src/Ui/Layout/Header/TopNav/index.tsx +19 -0
  37. package/src/Ui/Layout/Header/index.css.ts +18 -0
  38. package/src/Ui/Layout/Header/index.tsx +33 -0
  39. package/src/Ui/Layout/Main/Article/index.css.ts +13 -0
  40. package/src/Ui/Layout/Main/Article/index.tsx +10 -0
  41. package/src/Ui/Layout/Main/Footer/index.css.ts +12 -0
  42. package/src/Ui/Layout/Main/Footer/index.tsx +10 -0
  43. package/src/Ui/Layout/Main/index.css.ts +16 -0
  44. package/src/Ui/Layout/Main/index.tsx +26 -0
  45. package/src/Ui/Layout/index.css.ts +9 -0
  46. package/src/Ui/Layout/index.tsx +52 -0
  47. package/src/Ui/LocalStore.tsx +55 -0
  48. package/src/Ui/SessionStore.tsx +60 -0
  49. package/src/Ui/index.tsx +26 -0
  50. package/src/index.css.ts +125 -0
  51. package/src/index.ts +12 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "plugins": ["@typescript-eslint", "react", "react-hooks", "react-refresh"],
4
+ "extends": [
5
+ "eslint:recommended",
6
+ "plugin:react/all",
7
+ "plugin:react-hooks/recommended",
8
+ "plugin:@typescript-eslint/eslint-recommended",
9
+ "plugin:@typescript-eslint/recommended",
10
+ "prettier"
11
+ ],
12
+ "env": {"browser": true, "es6": true, "node": true},
13
+ "globals": {"page": true, "browser": true, "context": true},
14
+ "parserOptions": {
15
+ "ecmaVersion": 7,
16
+ "ecmaFeatures": {
17
+ "experimentalObjectRestSpread": true,
18
+ "globalReturn": true,
19
+ "jsx": true
20
+ },
21
+ "sourceType": "module"
22
+ },
23
+ "settings": {"react": {"version": "18.3.0"}},
24
+ "rules": {
25
+ "@typescript-eslint/no-explicit-any": 0,
26
+ "@typescript-eslint/no-var-requires": 0,
27
+ "@typescript-eslint/no-unused-vars": [
28
+ 2,
29
+ {"argsIgnorePattern": "^_.*", "varsIgnorePattern": "^_.*"}
30
+ ],
31
+ "max-len": [2, {"code": 80, "ignorePattern": "^(im|ex)ports?\\W.*"}],
32
+ "no-var": 2,
33
+ "no-console": 2,
34
+ "object-curly-spacing": [2, "never"],
35
+ "comma-dangle": [
36
+ 2,
37
+ {
38
+ "arrays": "always-multiline",
39
+ "objects": "always-multiline",
40
+ "imports": "always-multiline",
41
+ "exports": "always-multiline",
42
+ "functions": "always-multiline"
43
+ }
44
+ ],
45
+ "indent": 0,
46
+ "no-empty": [2, {"allowEmptyCatch": true}],
47
+ "linebreak-style": [2, "unix"],
48
+ "space-infix-ops": 2,
49
+ "quotes": [2, "single", {"allowTemplateLiterals": true}],
50
+ "semi": [2, "always"],
51
+ "sort-keys": 0,
52
+ "sort-imports": 2,
53
+ "no-multiple-empty-lines": [2, {"max": 1}],
54
+ "react/function-component-definition": [
55
+ 2,
56
+ {
57
+ "namedComponents": "arrow-function",
58
+ "unnamedComponents": "arrow-function"
59
+ }
60
+ ],
61
+ "react/no-multi-comp": [2, {"ignoreStateless": true}],
62
+ "react/no-find-dom-node": 0,
63
+ "react/no-set-state": 0,
64
+ "react/no-unsafe": 2,
65
+ "jsx-quotes": [2, "prefer-double"],
66
+ "react-hooks/exhaustive-deps": 2,
67
+ "react-hooks/rules-of-hooks": 2,
68
+ "react/destructuring-assignment": 0,
69
+ "react/display-name": 0,
70
+ "react/jsx-boolean-value": 0,
71
+ "react/jsx-filename-extension": 0,
72
+ "react/jsx-first-prop-new-line": [2, "multiline"],
73
+ "react/jsx-handler-names": [
74
+ 2,
75
+ {"eventHandlerPrefix": "_handle", "eventHandlerPropPrefix": "on"}
76
+ ],
77
+ "react/jsx-indent": 0,
78
+ "react/jsx-indent-props": [2, 2],
79
+ "react/jsx-max-depth": [2, {"max": 5}],
80
+ "react/jsx-max-props-per-line": [2, {"maximum": 1, "when": "multiline"}],
81
+ "react/jsx-newline": 0,
82
+ "react/jsx-no-literals": 0,
83
+ "react/jsx-one-expression-per-line": 0,
84
+ "react/jsx-props-no-spreading": 0,
85
+ "react/jsx-sort-props": 0,
86
+ "react/require-default-props": 0,
87
+ "react/sort-comp": 0,
88
+ "react/forbid-component-props": 0,
89
+ "react/button-has-type": 0
90
+ }
91
+ }
package/.prettierrc ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "bracketSpacing": false,
3
+ "singleQuote": true,
4
+ "trailingComma": "all"
5
+ }
package/bun.lockb ADDED
Binary file
package/index.css.ts ADDED
@@ -0,0 +1 @@
1
+ export {accent, accentContrast, theme} from './src/index.css.ts';
package/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export {Avatar} from './src/Avatar/index.tsx';
2
+ export {Axis} from './src/Axis/index.tsx';
3
+ export {Button} from './src/Button/index.tsx';
4
+ export {Card} from './src/Card/index.tsx';
5
+ export {Collapsible} from './src/Collapsible/index.tsx';
6
+ export {Detail} from './src/Detail/index.tsx';
7
+ export {Hr} from './src/Hr/index.tsx';
8
+ export {Metric} from './src/Metric/index.tsx';
9
+ export {Summary} from './src/Summary/index.tsx';
10
+ export {Tag} from './src/Tag/index.tsx';
11
+ export {Ui} from './src/Ui/index.tsx';
package/media.ts ADDED
@@ -0,0 +1 @@
1
+ export {large} from './src/index.ts';
package/package.json CHANGED
@@ -1,8 +1,33 @@
1
1
  {
2
2
  "name": "tinywidgets",
3
- "version": "0.0.0",
3
+ "version": "0.0.2",
4
4
  "author": "jamesgpearce",
5
5
  "repository": "github:tinyplex/tinywidgets",
6
+ "module": "index.ts",
7
+ "devDependencies": {
8
+ "@types/react": "^18.3.3",
9
+ "@types/react-dom": "^18.3.0",
10
+ "@typescript-eslint/eslint-plugin": "^7.16.1",
11
+ "@typescript-eslint/parser": "^7.16.1",
12
+ "eslint": "^8.57.0",
13
+ "eslint-config-prettier": "^9.1.0",
14
+ "eslint-plugin-react": "^7.34.4",
15
+ "eslint-plugin-react-hooks": "^4.6.2",
16
+ "prettier": "^3.3.3",
17
+ "typescript": "^5.5.3",
18
+ "@vanilla-extract/css": "^1.15.5",
19
+ "react": "^18.3.1",
20
+ "react-dom": "^18.3.1",
21
+ "tinybase": "^5.1.0"
22
+ },
23
+ "exports": {
24
+ ".": "./index.ts",
25
+ "./media": "./media.ts",
26
+ "./css": "./index.css.ts"
27
+ },
28
+ "description": "reserved",
6
29
  "license": "MIT",
7
- "description": "reserved"
30
+ "dependencies": {
31
+ "lucide-react": "^0.438.0"
32
+ }
8
33
  }
@@ -0,0 +1,17 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {theme} from '../index.css';
3
+
4
+ export const avatar = style({
5
+ display: 'inline-block',
6
+ width: '2rem',
7
+ height: '2rem',
8
+ boxShadow: theme.shadow,
9
+ borderRadius: '50%',
10
+ border: `1px solid ${theme.border}`,
11
+ flexShrink: 0,
12
+ selectors: {
13
+ '&:hover': {
14
+ backgroundColor: theme.backgroundHover,
15
+ },
16
+ },
17
+ });
@@ -0,0 +1,28 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {classNames} from '../index.ts';
5
+ import {avatar} from './index.css.ts';
6
+
7
+ const {createElement} = React;
8
+
9
+ export const Avatar = ({
10
+ src,
11
+ title,
12
+ onClick,
13
+ className,
14
+ }: {
15
+ src: string;
16
+ title?: string;
17
+ onClick?: () => void;
18
+ className?: string;
19
+ }) => {
20
+ return (
21
+ <img
22
+ src={src}
23
+ title={title}
24
+ onClick={onClick}
25
+ className={classNames(avatar, className)}
26
+ />
27
+ );
28
+ };
@@ -0,0 +1,19 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {dimensions} from '../index.css';
3
+
4
+ export const axis = style({
5
+ display: 'flex',
6
+ alignItems: 'center',
7
+ });
8
+
9
+ export const justifyStyle = style({
10
+ justifyContent: 'space-between',
11
+ });
12
+
13
+ export const verticalStyle = style({
14
+ flexDirection: 'column',
15
+ });
16
+
17
+ export const gapStyle = style({
18
+ gap: dimensions.padding,
19
+ });
@@ -0,0 +1,38 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {classNames} from '../';
5
+ import {axis, gapStyle, justifyStyle, verticalStyle} from './index.css';
6
+
7
+ const {createElement} = React;
8
+
9
+ export const Axis = ({
10
+ justify = true,
11
+ gap = true,
12
+ vertical,
13
+ children,
14
+ className,
15
+ title,
16
+ }: {
17
+ justify?: boolean;
18
+ gap?: boolean;
19
+ vertical?: boolean;
20
+ children: React.ReactNode;
21
+ className?: string;
22
+ title?: string;
23
+ }) => {
24
+ return (
25
+ <div
26
+ className={classNames(
27
+ axis,
28
+ justify && justifyStyle,
29
+ vertical && verticalStyle,
30
+ gap && gapStyle,
31
+ className,
32
+ )}
33
+ title={title}
34
+ >
35
+ {children}
36
+ </div>
37
+ );
38
+ };
@@ -0,0 +1,57 @@
1
+ import {style, styleVariants} from '@vanilla-extract/css';
2
+ import {axisLike, borderLike, radiusLike, theme} from '../index.css';
3
+
4
+ const ghostLike = {
5
+ backgroundColor: 'transparent',
6
+ border: 0,
7
+ };
8
+
9
+ export const button = style([
10
+ axisLike,
11
+ radiusLike,
12
+ {
13
+ textAlign: 'left',
14
+ cursor: 'pointer',
15
+ padding: '0.5rem 1rem',
16
+ outlineOffset: '-2px',
17
+ backgroundColor: theme.background,
18
+ color: 'inherit',
19
+ overflow: 'hidden',
20
+ whiteSpace: 'nowrap',
21
+ transition: 'background-color 0.2s,border-color 0.2s',
22
+ flexShrink: 0,
23
+ selectors: {
24
+ '&:hover': {
25
+ backgroundColor: theme.backgroundHover,
26
+ },
27
+ },
28
+ },
29
+ ]);
30
+
31
+ export const buttonVariant = styleVariants({
32
+ default: borderLike,
33
+ accent: {
34
+ ...borderLike,
35
+ backgroundColor: theme.accent,
36
+ color: theme.accentContrast,
37
+ border: 0,
38
+ selectors: {
39
+ '&:hover': {
40
+ backgroundColor: theme.accentHover,
41
+ },
42
+ },
43
+ },
44
+ ghost: ghostLike,
45
+ item: {...ghostLike, width: '100%'},
46
+ icon: {...ghostLike, padding: '0.25rem'},
47
+ });
48
+
49
+ export const highlight = style({
50
+ backgroundColor: theme.backgroundHover,
51
+ });
52
+
53
+ export const labelStyle = style({
54
+ flex: 1,
55
+ overflow: 'hidden',
56
+ textOverflow: 'ellipsis',
57
+ });
@@ -0,0 +1,65 @@
1
+ /** @jsx createElement */
2
+ /** @jsxFrag Fragment */
3
+
4
+ import React from 'react';
5
+ import {iconSize} from '../index.css.ts';
6
+ import {classNames} from '../index.ts';
7
+ import {button, buttonVariant, highlight, labelStyle} from './index.css.ts';
8
+
9
+ const {createElement, useCallback, forwardRef} = React;
10
+
11
+ export const Button = forwardRef(
12
+ (
13
+ {
14
+ icon: Icon,
15
+ label,
16
+ labelRight,
17
+ iconRight: IconRight,
18
+ onClick,
19
+ variant = 'default',
20
+ className,
21
+ href,
22
+ title,
23
+ current,
24
+ }: {
25
+ icon?: React.ComponentType<{className?: string}>;
26
+ label?: React.ReactNode;
27
+ labelRight?: React.ReactNode;
28
+ iconRight?: React.ComponentType<{className?: string}>;
29
+ onClick?: () => void;
30
+ variant?: keyof typeof buttonVariant;
31
+ className?: string;
32
+ href?: string;
33
+ title?: string;
34
+ current?: boolean;
35
+ },
36
+ ref: React.Ref<HTMLButtonElement>,
37
+ ) => {
38
+ const icon = Icon ? <Icon className={iconSize} /> : null;
39
+ const iconRight = IconRight ? <IconRight className={iconSize} /> : null;
40
+
41
+ const hrefClick = useCallback(
42
+ () => (href ? open(href, '_blank', 'noreferrer') : null),
43
+ [href],
44
+ );
45
+
46
+ return (
47
+ <button
48
+ className={classNames(
49
+ button,
50
+ buttonVariant[variant],
51
+ current && highlight,
52
+ className,
53
+ )}
54
+ onClick={onClick ?? hrefClick}
55
+ title={title}
56
+ ref={ref}
57
+ >
58
+ {icon}
59
+ {label ? <span className={labelStyle}>{label}</span> : null}
60
+ {labelRight}
61
+ {iconRight}
62
+ </button>
63
+ );
64
+ },
65
+ );
@@ -0,0 +1,9 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {borderLike, paddingLike, radiusLike} from '../index.css';
3
+
4
+ export const card = style([
5
+ borderLike,
6
+ radiusLike,
7
+ paddingLike,
8
+ {height: 'fit-content'},
9
+ ]);
@@ -0,0 +1,15 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {classNames} from '../';
5
+ import {card} from './index.css';
6
+
7
+ const {createElement} = React;
8
+
9
+ export const Card = ({
10
+ children,
11
+ className,
12
+ }: {
13
+ children: React.ReactNode;
14
+ className?: string;
15
+ }) => <div className={classNames(card, className)}>{children}</div>;
@@ -0,0 +1,34 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {borderLike, dimensions, paddingLike, radiusLike} from '../index.css';
3
+
4
+ export const collapsible = style([
5
+ borderLike,
6
+ radiusLike,
7
+ {
8
+ display: 'grid',
9
+ gridTemplateRows: 'max-content minmax(0, 0fr)',
10
+ transition: '.2s grid-template-rows ease-in-out',
11
+ overflow: 'hidden',
12
+ marginBottom: dimensions.padding,
13
+ selectors: {
14
+ '&:last-child': {
15
+ marginBottom: 0,
16
+ },
17
+ },
18
+ },
19
+ ]);
20
+
21
+ export const collapsibleOpen = style({
22
+ gridTemplateRows: 'max-content minmax(0, 1fr)',
23
+ });
24
+
25
+ export const button = style({
26
+ margin: '-1px',
27
+ });
28
+
29
+ export const buttonOpen = style({
30
+ borderBottomLeftRadius: 0,
31
+ borderBottomRightRadius: 0,
32
+ });
33
+
34
+ export const content = style([paddingLike, {overflow: 'hidden'}]);
@@ -0,0 +1,69 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {ChevronDown, ChevronRight} from 'lucide-react';
5
+ import {Button} from '../Button/index.tsx';
6
+ import {classNames} from '../index.ts';
7
+ import {
8
+ useCollapsibleOpen,
9
+ useSetCollapsibleOpen,
10
+ } from '../Ui/SessionStore.tsx';
11
+ import {
12
+ button,
13
+ buttonOpen,
14
+ collapsible,
15
+ collapsibleOpen,
16
+ content,
17
+ } from './index.css.ts';
18
+
19
+ const {createElement, useState, useCallback, useRef} = React;
20
+
21
+ export const Collapsible = ({
22
+ id = '',
23
+ icon: Icon,
24
+ label = <div />,
25
+ labelRight = <div />,
26
+ className,
27
+ children,
28
+ }: {
29
+ id?: string;
30
+ icon?: React.ComponentType<{className?: string}>;
31
+ label?: React.ReactNode;
32
+ labelRight?: React.ReactNode;
33
+ className?: string;
34
+ children: React.ReactNode;
35
+ }) => {
36
+ // State is in session Store if id is present, otherwise here in component.
37
+ const storedIsOpen = useCollapsibleOpen(id) ?? false;
38
+ const setStoredIsOpen = useSetCollapsibleOpen(id);
39
+ const [stateIsOpen, setStateIsOpen] = useState(false);
40
+
41
+ const isOpen = id ? storedIsOpen : stateIsOpen;
42
+ const setIsOpen = id ? setStoredIsOpen : setStateIsOpen;
43
+
44
+ const [render, setRender] = useState(isOpen);
45
+ const timer = useRef<Timer>();
46
+
47
+ const toggle = useCallback(() => {
48
+ setIsOpen(!isOpen);
49
+ clearTimeout(timer.current);
50
+ timer.current = setTimeout(() => setRender(!isOpen), isOpen ? 200 : 0);
51
+ }, [id, isOpen]);
52
+
53
+ return (
54
+ <div className={classNames(collapsible, isOpen && collapsibleOpen)}>
55
+ <Button
56
+ onClick={toggle}
57
+ icon={Icon}
58
+ label={label}
59
+ labelRight={labelRight}
60
+ iconRight={isOpen ? ChevronDown : ChevronRight}
61
+ className={classNames(button, render && buttonOpen)}
62
+ current={render}
63
+ />
64
+ {render ? (
65
+ <div className={classNames(content, className)}>{children}</div>
66
+ ) : null}
67
+ </div>
68
+ );
69
+ };
@@ -0,0 +1,19 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {theme} from '../index.css';
3
+
4
+ export const detailTable = style({
5
+ width: '100%',
6
+ borderCollapse: 'collapse',
7
+ margin: '-.5rem 0',
8
+ });
9
+
10
+ export const detailRow = style({
11
+ borderBottom: `1px solid ${theme.border}`,
12
+ selectors: {'&:last-child': {borderBottom: 'none'}},
13
+ });
14
+
15
+ export const detailCell = style({
16
+ padding: '0.5rem 1rem',
17
+ verticalAlign: 'top',
18
+ selectors: {'&:is(th)': {textAlign: 'right'}},
19
+ });
@@ -0,0 +1,28 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {classNames} from '../';
5
+ import {detailCell, detailRow, detailTable} from './index.css';
6
+
7
+ const {createElement} = React;
8
+
9
+ export const Detail = ({
10
+ data,
11
+ className,
12
+ }: {
13
+ data: Record<string, React.ReactNode>;
14
+ className?: string;
15
+ }) => {
16
+ return (
17
+ <table className={classNames(detailTable, className)}>
18
+ <tbody>
19
+ {Object.entries(data).map(([key, value]) => (
20
+ <tr key={key} className={detailRow}>
21
+ <th className={detailCell}>{key}:</th>
22
+ <td className={detailCell}>{value}</td>
23
+ </tr>
24
+ ))}
25
+ </tbody>
26
+ </table>
27
+ );
28
+ };
@@ -0,0 +1,10 @@
1
+ import {style} from '@vanilla-extract/css';
2
+ import {dimensions, theme} from '../index.css';
3
+
4
+ export const hr = style({
5
+ border: 'none',
6
+ borderBottom: `solid 1px ${theme.border}`,
7
+ margin: `${dimensions.padding} 0`,
8
+ height: '1px',
9
+ width: '100%',
10
+ });
@@ -0,0 +1,10 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {hr} from './index.css';
5
+
6
+ const {createElement} = React;
7
+
8
+ export const Hr = () => {
9
+ return <hr className={hr} />;
10
+ };
@@ -0,0 +1,18 @@
1
+ import {style} from '@vanilla-extract/css';
2
+
3
+ export const metric = style({
4
+ display: 'flex',
5
+ flexDirection: 'column',
6
+ gap: '0.5rem',
7
+ });
8
+
9
+ export const metricLabel = style({
10
+ display: 'flex',
11
+ alignItems: 'center',
12
+ gap: '0.5rem',
13
+ });
14
+
15
+ export const metricNumber = style({
16
+ fontSize: '1.5rem',
17
+ fontWeight: 'bold',
18
+ });
@@ -0,0 +1,28 @@
1
+ /** @jsx createElement */
2
+
3
+ import React from 'react';
4
+ import {classNames} from '../';
5
+ import {iconSize} from '../index.css';
6
+ import {metric, metricLabel, metricNumber} from './index.css';
7
+
8
+ const {createElement} = React;
9
+
10
+ export const Metric = ({
11
+ icon: Icon,
12
+ label,
13
+ number,
14
+ className,
15
+ }: {
16
+ icon?: React.ComponentType<{className?: string}>;
17
+ label: React.ReactNode;
18
+ number: React.ReactNode;
19
+ className?: string;
20
+ }) => (
21
+ <div className={classNames(metric, className)}>
22
+ <div className={metricLabel}>
23
+ {Icon ? <Icon className={iconSize} /> : null}
24
+ {label}
25
+ </div>
26
+ <div className={metricNumber}>{number}</div>
27
+ </div>
28
+ );
@@ -0,0 +1,17 @@
1
+ import {style} from '@vanilla-extract/css';
2
+
3
+ export const summary = style({
4
+ display: 'flex',
5
+ flexDirection: 'row',
6
+ gap: '1rem',
7
+ });
8
+
9
+ export const summaryImage = style({
10
+ flex: '0 0 6rem',
11
+ width: '6rem',
12
+ height: '6rem',
13
+ });
14
+
15
+ export const summaryContent = style({
16
+ flex: 1,
17
+ });