Skip to content

Commit 9ca8281

Browse files
gjmooneyelifsu-simula
authored andcommitted
Create shared components (geojupyter#749)
* Create some shared components * Add tabs; Add CSS * Button CSS * Use newer button * Add components for date picker * Add pagination component * Iterate on paginator * Tiny tweaks * Use the correct package.json * lint * Woops * Use jupyter css vars * Add sr-only class * Lint * Clean up
1 parent 14f9530 commit 9ca8281

File tree

15 files changed

+1844
-75
lines changed

15 files changed

+1844
-75
lines changed

packages/base/package.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,22 +64,31 @@
6464
"@lumino/widgets": "^2.0.0",
6565
"@mapbox/vector-tile": "^2.0.3",
6666
"@naisutech/react-tree": "^3.0.1",
67+
"@radix-ui/react-popover": "^1.1.14",
68+
"@radix-ui/react-slot": "^1.2.3",
69+
"@radix-ui/react-tabs": "^1.1.12",
70+
"@radix-ui/react-toggle-group": "^1.1.10",
6771
"@rjsf/core": "^4.2.0",
6872
"@rjsf/validator-ajv8": "^5.23.1",
6973
"ajv": "^8.14.0",
74+
"class-variance-authority": "^0.7.1",
75+
"clsx": "^2.1.1",
7076
"colormap": "^2.3.2",
7177
"d3-color": "^3.1.0",
7278
"date-fns": "^4.1.0",
7379
"gdal3.js": "^2.8.1",
7480
"geojson-vt": "^4.0.2",
7581
"geotiff": "^2.1.3",
82+
"lucide-react": "^0.513.0",
7683
"ol": "^10.1.0",
7784
"ol-pmtiles": "^0.5.0",
85+
"ol-stac": "^1.0.0-rc.10",
7886
"pbf": "^4.0.1",
7987
"pmtiles": "^3.0.7",
8088
"proj4": "^2.14.0",
8189
"proj4-list": "^1.0.4",
8290
"react": "^18.0.1",
91+
"react-day-picker": "8.10.1",
8392
"shpjs": "^6.1.0",
8493
"styled-components": "^5.3.6",
8594
"three": "^0.135.0",
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Slot } from '@radix-ui/react-slot';
2+
import * as React from 'react';
3+
4+
interface IButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
5+
asChild?: boolean;
6+
variant?: 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' | 'icon';
7+
size?: 'sm' | 'lg' | 'icon';
8+
}
9+
10+
const Button = React.forwardRef<HTMLButtonElement, IButtonProps>(
11+
({ variant, className, size, asChild = false, ...props }, ref) => {
12+
const Comp = asChild ? Slot : 'button';
13+
return (
14+
<Comp
15+
data-size={size}
16+
data-variant={variant}
17+
className={`Button ${className ? className : ''}`}
18+
ref={ref}
19+
{...props}
20+
/>
21+
);
22+
},
23+
);
24+
Button.displayName = 'Button';
25+
26+
export { Button };
27+
export type { IButtonProps as ButtonProps };
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { ChevronLeft, ChevronRight } from 'lucide-react';
2+
import * as React from 'react';
3+
import { DayPicker } from 'react-day-picker';
4+
import 'react-day-picker/dist/style.css';
5+
6+
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
7+
8+
function Calendar({ showOutsideDays = true, ...props }: CalendarProps) {
9+
return (
10+
<DayPicker
11+
showOutsideDays={showOutsideDays}
12+
weekStartsOn={1}
13+
components={{
14+
IconLeft: ({ ...props }) => <ChevronLeft color="currentColor" />,
15+
IconRight: ({ ...props }) => <ChevronRight color="currentColor" />,
16+
}}
17+
modifiersStyles={{
18+
selected: {
19+
backgroundColor: 'var(--jp-layout-color2)',
20+
color: 'var(--jp-ui-font-color0)',
21+
borderRadius: '0.275rem',
22+
},
23+
}}
24+
styles={{
25+
root: {
26+
width: 'max-content',
27+
margin: 0,
28+
color: 'var(--jp-ui-font-color0)',
29+
background: 'var(--jp-layout-color0)',
30+
border: '1px solid var(--jp-border-color0)',
31+
borderRadius: 'var(--jp-border-radius)',
32+
padding: '0.5rem',
33+
position: 'relative',
34+
},
35+
table: {
36+
paddingTop: '1rem',
37+
},
38+
head_cell: {
39+
color: 'var(--jp-ui-font-color0)',
40+
fontSize: '0.8rem',
41+
fontWeight: 400,
42+
},
43+
day: {
44+
backgroundColor: 'var(--jp-layout-color0)',
45+
display: 'flex',
46+
justifyContent: 'center',
47+
border: 'none',
48+
padding: '0.5rem',
49+
margin: 'auto',
50+
fontSize: '0.8rem',
51+
},
52+
caption: {
53+
display: 'flex',
54+
alignItems: 'center',
55+
justifyContent: 'center',
56+
},
57+
nav_button_previous: {
58+
color: 'var(--jp-ui-font-color0)',
59+
background: 'transparent',
60+
border: '0.5px solid var(--jp-border-color0)',
61+
position: 'absolute',
62+
top: '0.5rem',
63+
left: '0.5rem',
64+
borderRadius: 'var(--jp-border-radius)',
65+
padding: '0.175rem',
66+
width: 'max-content',
67+
height: 'max-content',
68+
},
69+
nav_button_next: {
70+
color: 'var(--jp-ui-font-color0)',
71+
background: 'transparent',
72+
border: '0.5px solid var(--jp-border-color0)',
73+
position: 'absolute',
74+
top: '0.5rem',
75+
right: '0.5rem',
76+
borderRadius: 'var(--jp-border-radius)',
77+
padding: '0.175rem',
78+
width: 'max-content',
79+
height: 'max-content',
80+
},
81+
}}
82+
{...props}
83+
/>
84+
);
85+
}
86+
Calendar.displayName = 'Calendar';
87+
88+
export default Calendar;
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
2+
import * as React from 'react';
3+
4+
import { Button, ButtonProps } from './Button';
5+
6+
const Pagination = ({ ...props }: React.ComponentProps<'nav'>) => (
7+
<nav
8+
role="navigation"
9+
aria-label="pagination"
10+
className={'Pagination'}
11+
{...props}
12+
/>
13+
);
14+
Pagination.displayName = 'Pagination';
15+
16+
const PaginationContent = React.forwardRef<
17+
HTMLUListElement,
18+
React.ComponentProps<'ul'>
19+
>(({ ...props }, ref) => (
20+
<ul ref={ref} className={'PaginationContent'} {...props} />
21+
));
22+
PaginationContent.displayName = 'PaginationContent';
23+
24+
const PaginationItem = React.forwardRef<
25+
HTMLLIElement,
26+
React.ComponentProps<'li'>
27+
>(({ ...props }, ref) => <li ref={ref} className="" {...props} />);
28+
PaginationItem.displayName = 'PaginationItem';
29+
30+
type PaginationLinkProps = {
31+
isActive?: boolean;
32+
} & Pick<ButtonProps, 'size'> &
33+
React.ComponentProps<'button'>;
34+
35+
const PaginationLink = ({
36+
isActive,
37+
size = 'icon',
38+
...props
39+
}: PaginationLinkProps) => (
40+
<Button
41+
aria-current={isActive ? 'page' : undefined}
42+
data-variant={isActive ? 'outline' : 'ghost'}
43+
data-size={size}
44+
className={'PaginationLink'}
45+
{...props}
46+
/>
47+
);
48+
PaginationLink.displayName = 'PaginationLink';
49+
50+
// size is 'default' from both next and previous
51+
const PaginationPrevious = ({
52+
...props
53+
}: React.ComponentProps<typeof PaginationLink>) => (
54+
<PaginationLink
55+
aria-label="Go to previous page"
56+
className={'PaginationPrevious'}
57+
{...props}
58+
>
59+
<ChevronLeft
60+
style={{
61+
height: '1rem',
62+
width: '1rem',
63+
flexShrink: 0,
64+
}}
65+
/>
66+
<span>Prev</span>
67+
</PaginationLink>
68+
);
69+
PaginationPrevious.displayName = 'PaginationPrevious';
70+
71+
const PaginationNext = ({
72+
...props
73+
}: React.ComponentProps<typeof PaginationLink>) => (
74+
<PaginationLink
75+
aria-label="Go to next page"
76+
className={'PaginationNext'}
77+
{...props}
78+
>
79+
<span>Next</span>
80+
<ChevronRight
81+
style={{
82+
height: '1rem',
83+
width: '1rem',
84+
flexShrink: 0,
85+
}}
86+
/>
87+
</PaginationLink>
88+
);
89+
PaginationNext.displayName = 'PaginationNext';
90+
91+
const PaginationEllipsis = ({ ...props }: React.ComponentProps<'span'>) => (
92+
<span aria-hidden className={'PaginationEllipsis'} {...props}>
93+
<MoreHorizontal
94+
style={{
95+
height: '1rem',
96+
width: '1rem',
97+
}}
98+
/>
99+
<span className="sr-only">More pages</span>
100+
</span>
101+
);
102+
PaginationEllipsis.displayName = 'PaginationEllipsis';
103+
104+
export {
105+
Pagination,
106+
PaginationContent,
107+
PaginationEllipsis,
108+
PaginationItem,
109+
PaginationLink,
110+
PaginationNext,
111+
PaginationPrevious,
112+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as PopoverPrimitive from '@radix-ui/react-popover';
2+
import * as React from 'react';
3+
4+
import { cn } from './utils';
5+
6+
function Popover({
7+
...props
8+
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
9+
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
10+
}
11+
12+
function PopoverTrigger({
13+
...props
14+
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
15+
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
16+
}
17+
18+
function PopoverContent({
19+
className,
20+
align = 'center',
21+
sideOffset = 4,
22+
...props
23+
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
24+
return (
25+
<PopoverPrimitive.Portal>
26+
<PopoverPrimitive.Content
27+
data-slot="popover-content"
28+
align={align}
29+
sideOffset={sideOffset}
30+
className={cn('PopoverContent', className)}
31+
{...props}
32+
/>
33+
</PopoverPrimitive.Portal>
34+
);
35+
}
36+
37+
function PopoverAnchor({
38+
...props
39+
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
40+
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
41+
}
42+
43+
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import * as TabsPrimitive from '@radix-ui/react-tabs';
2+
import * as React from 'react';
3+
4+
import { cn } from './utils';
5+
6+
function Tabs({
7+
className,
8+
...props
9+
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
10+
return (
11+
<TabsPrimitive.Root
12+
data-slot="tabs"
13+
className={cn('TabsList', className)}
14+
{...props}
15+
/>
16+
);
17+
}
18+
19+
function TabsList({
20+
className,
21+
...props
22+
}: React.ComponentProps<typeof TabsPrimitive.List>) {
23+
return (
24+
<TabsPrimitive.List
25+
data-slot="tabs-list"
26+
className={cn('TabsList', className)}
27+
{...props}
28+
/>
29+
);
30+
}
31+
32+
function TabsTrigger({
33+
className,
34+
...props
35+
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
36+
return (
37+
<TabsPrimitive.Trigger
38+
data-slot="tabs-trigger"
39+
className={cn('TabsTrigger', className)}
40+
{...props}
41+
/>
42+
);
43+
}
44+
45+
function TabsContent({
46+
className,
47+
...props
48+
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
49+
return (
50+
<TabsPrimitive.Content
51+
data-slot="tabs-content"
52+
className={cn('TabsContent', className)}
53+
{...props}
54+
/>
55+
);
56+
}
57+
58+
export { Tabs, TabsContent, TabsList, TabsTrigger };

0 commit comments

Comments
 (0)