graphen 2.0.3 → 2.0.4
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.
- package/dist/css.js +1 -1
- package/dist/scripts.js +1 -1
- package/package.json +1 -1
- package/src/components/CoverEmpty/index.tsx +19 -0
- package/src/components/CoverEmpty/styles/_styles.scss +17 -0
- package/src/components/Icons/index.tsx +74 -0
- package/src/components/SegmentedControl/index.tsx +45 -0
- package/src/components/SegmentedControl/styles/_styles.scss +26 -0
- package/src/components/Stat/index.tsx +25 -0
- package/src/components/Stat/styles/_styles.scss +51 -0
- package/src/example/styles/_docs.scss +32 -0
- package/src/example.scss +3 -1
- package/src/example.tsx +119 -0
- package/src/index.ts +11 -2
- package/src/style.scss +3 -1
- package/src/components/Image/index.tsx +0 -26
- package/src/components/Image/styles/_styles.scss +0 -20
package/package.json
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
import { IconImg } from "../Icons";
|
|
4
|
+
|
|
5
|
+
type Props = {
|
|
6
|
+
className?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
function CoverEmpty({ className = "" }: Props) {
|
|
10
|
+
const classes = classNames("gc-cover-empty", className);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<span className={classes}>
|
|
14
|
+
<IconImg className="gc-cover-empty__icon" />
|
|
15
|
+
</span>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default CoverEmpty;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.gc-cover-empty {
|
|
2
|
+
display: grid;
|
|
3
|
+
place-items: center;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
color: $color-silver;
|
|
7
|
+
|
|
8
|
+
&__icon {
|
|
9
|
+
width: 38px;
|
|
10
|
+
height: 38px;
|
|
11
|
+
stroke: currentcolor;
|
|
12
|
+
fill: none;
|
|
13
|
+
stroke-width: 1.4;
|
|
14
|
+
stroke-linecap: round;
|
|
15
|
+
stroke-linejoin: round;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
type IconProps = {
|
|
4
|
+
className?: string;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export const IconSearch = ({ className }: IconProps) => (
|
|
8
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
9
|
+
<circle cx="11" cy="11" r="7" />
|
|
10
|
+
<path d="M21 21l-4.3-4.3" />
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export const IconEdit = ({ className }: IconProps) => (
|
|
15
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
16
|
+
<path d="M12 20h9" />
|
|
17
|
+
<path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z" />
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const IconTrash = ({ className }: IconProps) => (
|
|
22
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
23
|
+
<path d="M3 6h18" />
|
|
24
|
+
<path d="M8 6V4a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2" />
|
|
25
|
+
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
|
|
26
|
+
</svg>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export const IconPlus = ({ className }: IconProps) => (
|
|
30
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
31
|
+
<path d="M12 5v14M5 12h14" />
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const IconRefresh = ({ className }: IconProps) => (
|
|
36
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
37
|
+
<path d="M21 12a9 9 0 1 1-2.64-6.36" />
|
|
38
|
+
<path d="M21 3v6h-6" />
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const IconClock = ({ className }: IconProps) => (
|
|
43
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
44
|
+
<circle cx="12" cy="12" r="9" />
|
|
45
|
+
<path d="M12 7v5l3 2" />
|
|
46
|
+
</svg>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
export const IconImg = ({ className }: IconProps) => (
|
|
50
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
51
|
+
<rect x="3" y="3" width="18" height="18" rx="2" />
|
|
52
|
+
<circle cx="8.5" cy="8.5" r="1.5" />
|
|
53
|
+
<path d="M21 15l-5-5L5 21" />
|
|
54
|
+
</svg>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
export const IconMail = ({ className }: IconProps) => (
|
|
58
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
59
|
+
<rect x="3" y="5" width="18" height="14" rx="2" />
|
|
60
|
+
<path d="M3 7l9 6 9-6" />
|
|
61
|
+
</svg>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export const IconCheck = ({ className }: IconProps) => (
|
|
65
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
66
|
+
<path d="M20 6L9 17l-5-5" />
|
|
67
|
+
</svg>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
export const IconChevron = ({ className }: IconProps) => (
|
|
71
|
+
<svg className={className} viewBox="0 0 24 24">
|
|
72
|
+
<path d="M6 9l6 6 6-6" />
|
|
73
|
+
</svg>
|
|
74
|
+
);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
|
|
4
|
+
export type SegmentedControlOption<TValue extends string = string> = {
|
|
5
|
+
value: TValue;
|
|
6
|
+
label: React.ReactNode;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type Props<TValue extends string = string> = {
|
|
10
|
+
options: ReadonlyArray<SegmentedControlOption<TValue>>;
|
|
11
|
+
value: TValue;
|
|
12
|
+
onChange: (value: TValue) => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function SegmentedControl<TValue extends string = string>({
|
|
17
|
+
options,
|
|
18
|
+
value,
|
|
19
|
+
onChange,
|
|
20
|
+
className = "",
|
|
21
|
+
}: Props<TValue>) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
className={classNames("gc-segmented-control", className)}
|
|
25
|
+
role="tablist"
|
|
26
|
+
>
|
|
27
|
+
{options.map((option) => (
|
|
28
|
+
<button
|
|
29
|
+
key={option.value}
|
|
30
|
+
type="button"
|
|
31
|
+
role="tab"
|
|
32
|
+
aria-selected={value === option.value}
|
|
33
|
+
className={classNames("gc-segmented-control__option", {
|
|
34
|
+
"gc-segmented-control__option--on": value === option.value,
|
|
35
|
+
})}
|
|
36
|
+
onClick={() => onChange(option.value)}
|
|
37
|
+
>
|
|
38
|
+
{option.label}
|
|
39
|
+
</button>
|
|
40
|
+
))}
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default SegmentedControl;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
.gc-segmented-control {
|
|
2
|
+
display: inline-flex;
|
|
3
|
+
background: $gb-color-component;
|
|
4
|
+
border: 1px solid $gb-color-component-dark;
|
|
5
|
+
border-radius: 999px;
|
|
6
|
+
padding: 3px;
|
|
7
|
+
|
|
8
|
+
&__option {
|
|
9
|
+
border: 0;
|
|
10
|
+
background: none;
|
|
11
|
+
padding: 7px 16px;
|
|
12
|
+
border-radius: 999px;
|
|
13
|
+
font-size: 13.5px;
|
|
14
|
+
font-weight: 600;
|
|
15
|
+
color: $color-boulder;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
|
|
18
|
+
&--on {
|
|
19
|
+
background: $color-white;
|
|
20
|
+
color: $gb-color-primary;
|
|
21
|
+
box-shadow:
|
|
22
|
+
0 1px 2px rgb(33 43 54 / 5%),
|
|
23
|
+
0 1px 1px rgb(33 43 54 / 3%);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import classNames from "classnames";
|
|
3
|
+
|
|
4
|
+
export type StatModifier = "gray" | "blue" | "green" | "amber" | "red";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
modifier?: StatModifier;
|
|
8
|
+
label: React.ReactNode;
|
|
9
|
+
value: React.ReactNode;
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function Stat({ modifier = "gray", label, value, className = "" }: Props) {
|
|
14
|
+
return (
|
|
15
|
+
<div className={classNames("gc-stat", `gc-stat--${modifier}`, className)}>
|
|
16
|
+
<div className="gc-stat__key">
|
|
17
|
+
<span className="gc-stat__dot" />
|
|
18
|
+
{label}
|
|
19
|
+
</div>
|
|
20
|
+
<div className="gc-stat__value">{value}</div>
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default Stat;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
.gc-stat {
|
|
2
|
+
background: $color-white;
|
|
3
|
+
border: 1px solid $gb-color-component-dark;
|
|
4
|
+
border-radius: $radius-large;
|
|
5
|
+
padding: 16px 18px;
|
|
6
|
+
box-shadow:
|
|
7
|
+
0 1px 2px rgb(33 43 54 / 5%),
|
|
8
|
+
0 1px 1px rgb(33 43 54 / 3%);
|
|
9
|
+
|
|
10
|
+
&__key {
|
|
11
|
+
font-family: $gb-font-mono;
|
|
12
|
+
font-size: 11px;
|
|
13
|
+
text-transform: uppercase;
|
|
14
|
+
letter-spacing: 0.04em;
|
|
15
|
+
color: $color-boulder;
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: 7px;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
&__dot {
|
|
22
|
+
width: 7px;
|
|
23
|
+
height: 7px;
|
|
24
|
+
border-radius: 50%;
|
|
25
|
+
background: $color-silver;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&__value {
|
|
29
|
+
font-size: 27px;
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
color: $color-mine-shaft;
|
|
32
|
+
margin-top: 8px;
|
|
33
|
+
letter-spacing: -0.02em;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
&--blue &__dot {
|
|
37
|
+
background: $gb-color-primary;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&--green &__dot {
|
|
41
|
+
background: $gb-color-success;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&--amber &__dot {
|
|
45
|
+
background: #c77b12;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
&--red &__dot {
|
|
49
|
+
background: $gb-color-danger;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -573,6 +573,38 @@ body.docs-body {
|
|
|
573
573
|
svg { width: 18px; height: 18px; color: var(--text); }
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
+
.docs-iconset-cell__svg {
|
|
577
|
+
width: 18px;
|
|
578
|
+
height: 18px;
|
|
579
|
+
fill: none;
|
|
580
|
+
stroke: currentcolor;
|
|
581
|
+
stroke-width: 1.7;
|
|
582
|
+
stroke-linecap: round;
|
|
583
|
+
stroke-linejoin: round;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.docs-subsection-title {
|
|
587
|
+
margin: 28px 0 6px;
|
|
588
|
+
font-size: 15px;
|
|
589
|
+
font-weight: 600;
|
|
590
|
+
color: var(--text);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
.docs-stat-grid {
|
|
594
|
+
display: grid;
|
|
595
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
596
|
+
gap: 12px;
|
|
597
|
+
width: 100%;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.docs-cover-empty-stage {
|
|
601
|
+
width: 160px;
|
|
602
|
+
height: 120px;
|
|
603
|
+
border: 1px solid var(--border);
|
|
604
|
+
border-radius: var(--radius-lg);
|
|
605
|
+
overflow: hidden;
|
|
606
|
+
}
|
|
607
|
+
|
|
576
608
|
.docs-type-row {
|
|
577
609
|
display: grid;
|
|
578
610
|
grid-template-columns: 80px 80px 1fr;
|
package/src/example.scss
CHANGED
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
@import "components/Flex/styles/styles";
|
|
21
21
|
@import "components/FlexItem/styles/styles";
|
|
22
22
|
@import "components/Input/styles/styles";
|
|
23
|
-
@import "components/Image/styles/styles";
|
|
24
23
|
@import "components/Joystick/styles/styles";
|
|
25
24
|
@import "components/Led/styles/mixins";
|
|
26
25
|
@import "components/Led/styles/styles";
|
|
@@ -47,6 +46,9 @@
|
|
|
47
46
|
@import "components/Badge/styles/styles";
|
|
48
47
|
@import "components/Dropdown/styles/styles";
|
|
49
48
|
@import "components/Skeleton/styles/styles";
|
|
49
|
+
@import "components/CoverEmpty/styles/styles";
|
|
50
|
+
@import "components/SegmentedControl/styles/styles";
|
|
51
|
+
@import "components/Stat/styles/styles";
|
|
50
52
|
@import "example/styles/splash";
|
|
51
53
|
@import "example/styles/styles";
|
|
52
54
|
@import "example/styles/docs";
|
package/src/example.tsx
CHANGED
|
@@ -5,12 +5,16 @@ import {
|
|
|
5
5
|
Badge,
|
|
6
6
|
Button,
|
|
7
7
|
Card,
|
|
8
|
+
CoverEmpty,
|
|
8
9
|
Dialog,
|
|
9
10
|
Dropdown,
|
|
11
|
+
Icons,
|
|
10
12
|
Input,
|
|
11
13
|
Link,
|
|
12
14
|
Logo,
|
|
15
|
+
SegmentedControl,
|
|
13
16
|
Separator,
|
|
17
|
+
Stat,
|
|
14
18
|
constants,
|
|
15
19
|
} from "./index";
|
|
16
20
|
|
|
@@ -124,6 +128,29 @@ const ICONS: ReadonlyArray<readonly [string, string]> = [
|
|
|
124
128
|
["plus", "M12 5v14M5 12h14"],
|
|
125
129
|
];
|
|
126
130
|
|
|
131
|
+
const ICON_SET: ReadonlyArray<
|
|
132
|
+
readonly [string, (props: { className?: string }) => React.ReactElement]
|
|
133
|
+
> = [
|
|
134
|
+
["IconSearch", Icons.IconSearch],
|
|
135
|
+
["IconEdit", Icons.IconEdit],
|
|
136
|
+
["IconTrash", Icons.IconTrash],
|
|
137
|
+
["IconPlus", Icons.IconPlus],
|
|
138
|
+
["IconRefresh", Icons.IconRefresh],
|
|
139
|
+
["IconClock", Icons.IconClock],
|
|
140
|
+
["IconImg", Icons.IconImg],
|
|
141
|
+
["IconMail", Icons.IconMail],
|
|
142
|
+
["IconCheck", Icons.IconCheck],
|
|
143
|
+
["IconChevron", Icons.IconChevron],
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
const SEGMENTED_OPTIONS = [
|
|
147
|
+
{ value: "all", label: "All" },
|
|
148
|
+
{ value: "active", label: "Active" },
|
|
149
|
+
{ value: "archived", label: "Archived" },
|
|
150
|
+
] as const;
|
|
151
|
+
|
|
152
|
+
type SegmentedValue = (typeof SEGMENTED_OPTIONS)[number]["value"];
|
|
153
|
+
|
|
127
154
|
const NAV = [
|
|
128
155
|
{
|
|
129
156
|
title: "Getting started",
|
|
@@ -155,6 +182,9 @@ const NAV = [
|
|
|
155
182
|
{ id: "card", label: "Card" },
|
|
156
183
|
{ id: "badge", label: "Badge" },
|
|
157
184
|
{ id: "navigation", label: "Navigation" },
|
|
185
|
+
{ id: "segmented-control", label: "Segmented control" },
|
|
186
|
+
{ id: "stat", label: "Stat" },
|
|
187
|
+
{ id: "cover-empty", label: "Cover empty" },
|
|
158
188
|
],
|
|
159
189
|
},
|
|
160
190
|
];
|
|
@@ -176,6 +206,9 @@ const TOC = [
|
|
|
176
206
|
["card", "Card"],
|
|
177
207
|
["badge", "Badge"],
|
|
178
208
|
["navigation", "Navigation"],
|
|
209
|
+
["segmented-control", "Segmented control"],
|
|
210
|
+
["stat", "Stat"],
|
|
211
|
+
["cover-empty", "Cover empty"],
|
|
179
212
|
] as const;
|
|
180
213
|
|
|
181
214
|
type IconProps = {
|
|
@@ -368,6 +401,7 @@ function App() {
|
|
|
368
401
|
const [installCopied, setInstallCopied] = useState(false);
|
|
369
402
|
const [dropdownValue, setDropdownValue] = useState("red");
|
|
370
403
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
|
404
|
+
const [segmentedValue, setSegmentedValue] = useState<SegmentedValue>("all");
|
|
371
405
|
|
|
372
406
|
useEffect(() => {
|
|
373
407
|
document.documentElement.setAttribute("data-theme", theme);
|
|
@@ -663,6 +697,20 @@ function App() {
|
|
|
663
697
|
<IconCell key={name} name={name} d={d} />
|
|
664
698
|
))}
|
|
665
699
|
</div>
|
|
700
|
+
<h3 className="docs-subsection-title">Icon set</h3>
|
|
701
|
+
<p className="docs-section-desc">
|
|
702
|
+
Ready-to-use React icon components exported from{" "}
|
|
703
|
+
<code>Icons</code>. They inherit <code>currentColor</code>; size
|
|
704
|
+
and stroke are set by the consumer via a class name.
|
|
705
|
+
</p>
|
|
706
|
+
<div className="docs-icon-grid">
|
|
707
|
+
{ICON_SET.map(([name, IconComponent]) => (
|
|
708
|
+
<div className="docs-icon-cell docs-iconset-cell" key={name}>
|
|
709
|
+
<IconComponent className="docs-iconset-cell__svg" />
|
|
710
|
+
<span>{name}</span>
|
|
711
|
+
</div>
|
|
712
|
+
))}
|
|
713
|
+
</div>
|
|
666
714
|
</section>
|
|
667
715
|
|
|
668
716
|
<section className="docs-section" id="logo">
|
|
@@ -1025,6 +1073,77 @@ function App() {
|
|
|
1025
1073
|
</Demo>
|
|
1026
1074
|
</section>
|
|
1027
1075
|
|
|
1076
|
+
<section className="docs-section" id="segmented-control">
|
|
1077
|
+
<div className="docs-section-eyebrow">Components / 12</div>
|
|
1078
|
+
<h2 className="docs-section-title">Segmented control</h2>
|
|
1079
|
+
<p className="docs-section-desc">
|
|
1080
|
+
A pill-shaped toggle for switching between a few mutually
|
|
1081
|
+
exclusive views. Prefer it over a dropdown when there are two to
|
|
1082
|
+
four options that benefit from being visible at once.
|
|
1083
|
+
</p>
|
|
1084
|
+
<Demo
|
|
1085
|
+
stageClass="center"
|
|
1086
|
+
code={`<SegmentedControl
|
|
1087
|
+
options={[
|
|
1088
|
+
{ value: "all", label: "All" },
|
|
1089
|
+
{ value: "active", label: "Active" },
|
|
1090
|
+
{ value: "archived", label: "Archived" },
|
|
1091
|
+
]}
|
|
1092
|
+
value="${segmentedValue}"
|
|
1093
|
+
onChange={setSegmentedValue}
|
|
1094
|
+
/>`}
|
|
1095
|
+
>
|
|
1096
|
+
<SegmentedControl<SegmentedValue>
|
|
1097
|
+
options={SEGMENTED_OPTIONS}
|
|
1098
|
+
value={segmentedValue}
|
|
1099
|
+
onChange={setSegmentedValue}
|
|
1100
|
+
/>
|
|
1101
|
+
</Demo>
|
|
1102
|
+
</section>
|
|
1103
|
+
|
|
1104
|
+
<section className="docs-section" id="stat">
|
|
1105
|
+
<div className="docs-section-eyebrow">Components / 13</div>
|
|
1106
|
+
<h2 className="docs-section-title">Stat</h2>
|
|
1107
|
+
<p className="docs-section-desc">
|
|
1108
|
+
A single key figure with a labelled, color-coded dot. Group a few
|
|
1109
|
+
of them to summarise the state of a page. The dot color is set via
|
|
1110
|
+
the <code>modifier</code> prop.
|
|
1111
|
+
</p>
|
|
1112
|
+
<Demo
|
|
1113
|
+
stageClass="column"
|
|
1114
|
+
code={`<Stat modifier="blue" label="Posts" value="128" />
|
|
1115
|
+
<Stat modifier="green" label="Published" value="94" />
|
|
1116
|
+
<Stat modifier="amber" label="Drafts" value="26" />
|
|
1117
|
+
<Stat modifier="red" label="Flagged" value="8" />`}
|
|
1118
|
+
>
|
|
1119
|
+
<div className="docs-stat-grid">
|
|
1120
|
+
<Stat modifier="blue" label="Posts" value="128" />
|
|
1121
|
+
<Stat modifier="green" label="Published" value="94" />
|
|
1122
|
+
<Stat modifier="amber" label="Drafts" value="26" />
|
|
1123
|
+
<Stat modifier="red" label="Flagged" value="8" />
|
|
1124
|
+
</div>
|
|
1125
|
+
</Demo>
|
|
1126
|
+
</section>
|
|
1127
|
+
|
|
1128
|
+
<section className="docs-section" id="cover-empty">
|
|
1129
|
+
<div className="docs-section-eyebrow">Components / 14</div>
|
|
1130
|
+
<h2 className="docs-section-title">Cover empty</h2>
|
|
1131
|
+
<p className="docs-section-desc">
|
|
1132
|
+
A neutral placeholder for a missing image or empty media slot. It
|
|
1133
|
+
fills its container, so give the parent a fixed size.
|
|
1134
|
+
</p>
|
|
1135
|
+
<Demo
|
|
1136
|
+
stageClass="center"
|
|
1137
|
+
code={`<div style={{ width: 160, height: 120 }}>
|
|
1138
|
+
<CoverEmpty />
|
|
1139
|
+
</div>`}
|
|
1140
|
+
>
|
|
1141
|
+
<div className="docs-cover-empty-stage">
|
|
1142
|
+
<CoverEmpty />
|
|
1143
|
+
</div>
|
|
1144
|
+
</Demo>
|
|
1145
|
+
</section>
|
|
1146
|
+
|
|
1028
1147
|
<footer className="docs-footer">
|
|
1029
1148
|
<div>graphen · {VERSION} · MIT</div>
|
|
1030
1149
|
<div>Built by the CODA_ team</div>
|
package/src/index.ts
CHANGED
|
@@ -4,8 +4,8 @@ import Button from "src/components/Button";
|
|
|
4
4
|
import Card from "src/components/Card";
|
|
5
5
|
import Dialog from "src/components/Dialog";
|
|
6
6
|
import Icon from "src/components/Icon";
|
|
7
|
+
import * as Icons from "src/components/Icons";
|
|
7
8
|
import Input from "src/components/Input";
|
|
8
|
-
import Image from "src/components/Image";
|
|
9
9
|
import Joystick from "src/components/Joystick";
|
|
10
10
|
import Link from "src/components/Link";
|
|
11
11
|
import Loader from "src/components/Loader";
|
|
@@ -23,6 +23,9 @@ import PanelFooter from "src/components/PanelFooter";
|
|
|
23
23
|
import PanelTitle from "src/components/PanelTitle";
|
|
24
24
|
import Switch from "src/components/Switch";
|
|
25
25
|
import Skeleton from "src/components/Skeleton";
|
|
26
|
+
import CoverEmpty from "src/components/CoverEmpty";
|
|
27
|
+
import SegmentedControl from "src/components/SegmentedControl";
|
|
28
|
+
import Stat from "src/components/Stat";
|
|
26
29
|
import * as constants from "src/variables/constants";
|
|
27
30
|
|
|
28
31
|
export {
|
|
@@ -32,6 +35,7 @@ export {
|
|
|
32
35
|
Card,
|
|
33
36
|
Dialog,
|
|
34
37
|
Icon,
|
|
38
|
+
Icons,
|
|
35
39
|
Input,
|
|
36
40
|
Joystick,
|
|
37
41
|
Link,
|
|
@@ -41,7 +45,6 @@ export {
|
|
|
41
45
|
Tooltip,
|
|
42
46
|
Validation,
|
|
43
47
|
Logo,
|
|
44
|
-
Image,
|
|
45
48
|
Dropdown,
|
|
46
49
|
Flex,
|
|
47
50
|
FlexItem,
|
|
@@ -51,5 +54,11 @@ export {
|
|
|
51
54
|
PanelTitle,
|
|
52
55
|
Switch,
|
|
53
56
|
Skeleton,
|
|
57
|
+
CoverEmpty,
|
|
58
|
+
SegmentedControl,
|
|
59
|
+
Stat,
|
|
54
60
|
constants,
|
|
55
61
|
};
|
|
62
|
+
|
|
63
|
+
export type { SegmentedControlOption } from "src/components/SegmentedControl";
|
|
64
|
+
export type { StatModifier } from "src/components/Stat";
|
package/src/style.scss
CHANGED
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
@import "components/Flex/styles/styles";
|
|
21
21
|
@import "components/FlexItem/styles/styles";
|
|
22
22
|
@import "components/Input/styles/styles";
|
|
23
|
-
@import "components/Image/styles/styles";
|
|
24
23
|
@import "components/Joystick/styles/styles";
|
|
25
24
|
@import "components/Led/styles/mixins";
|
|
26
25
|
@import "components/Led/styles/styles";
|
|
@@ -47,3 +46,6 @@
|
|
|
47
46
|
@import "components/Badge/styles/styles";
|
|
48
47
|
@import "components/Dropdown/styles/styles";
|
|
49
48
|
@import "components/Skeleton/styles/styles";
|
|
49
|
+
@import "components/CoverEmpty/styles/styles";
|
|
50
|
+
@import "components/SegmentedControl/styles/styles";
|
|
51
|
+
@import "components/Stat/styles/styles";
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import classNames from "classnames";
|
|
3
|
-
|
|
4
|
-
type Props = {
|
|
5
|
-
src: string;
|
|
6
|
-
className?: string;
|
|
7
|
-
height?: number;
|
|
8
|
-
width?: number;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
function Image({ className = "", height = 200, width = 200, src }: Props) {
|
|
12
|
-
const classes = classNames("gc-image", className);
|
|
13
|
-
|
|
14
|
-
return (
|
|
15
|
-
<object
|
|
16
|
-
className={classes}
|
|
17
|
-
data={src}
|
|
18
|
-
type="image/jpg"
|
|
19
|
-
style={{ height, width }}
|
|
20
|
-
>
|
|
21
|
-
<div className="gc-image__fallback" />
|
|
22
|
-
</object>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default Image;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
.gc-image {
|
|
2
|
-
position: relative;
|
|
3
|
-
display: inline-block;
|
|
4
|
-
border: 1px solid $gb-color-component-dark;
|
|
5
|
-
padding: $radius-medium;
|
|
6
|
-
vertical-align: middle;
|
|
7
|
-
|
|
8
|
-
&__fallback {
|
|
9
|
-
background-color: $gb-color-component-light;
|
|
10
|
-
display: flex;
|
|
11
|
-
justify-content: center;
|
|
12
|
-
flex-direction: column;
|
|
13
|
-
height: 100%;
|
|
14
|
-
|
|
15
|
-
&::before {
|
|
16
|
-
content: "No image loaded";
|
|
17
|
-
text-align: center;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|