Skip to content

Commit 3013303

Browse files
committed
docs(example): add item detail panel demonstrating useItem hook
Adds an ItemDetails component to the example app, showing how to use the useItem hook to fetch and display STAC item details. Improves documentation for consumers of stac-react.
1 parent a04443b commit 3013303

File tree

3 files changed

+91
-11
lines changed

3 files changed

+91
-11
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useItem } from 'stac-react';
2+
3+
import { H2 } from '../../components/headers';
4+
import Panel from '../../layout/Panel';
5+
import { Button } from '../../components/buttons';
6+
7+
function ItemDetails({ item, onClose }) {
8+
const itemUrl = item.links.find((r) => r.rel === 'self')?.href;
9+
const { item: newItem, state, error, reload } = useItem(itemUrl);
10+
11+
const isLoading = state === 'LOADING';
12+
13+
return (
14+
<Panel className="grid grid-rows-[1fr_min-content] p-4 h-[calc(100vh_-_90px)] overflow-y-scroll w-full overflow-hidden">
15+
<div className="w-full overflow-hidden">
16+
<div className="flex flex-wrap items-start gap-2">
17+
<H2 className="whitespace-normal break-words flex-1">Selected Item</H2>
18+
<Button
19+
type="button"
20+
onClick={onClose}
21+
aria-label="Close selected item panel"
22+
title="Close"
23+
className="p-2 rounded hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-gray-300"
24+
>
25+
<svg
26+
xmlns="http://www.w3.org/2000/svg"
27+
className="w-5 h-5"
28+
viewBox="0 0 24 24"
29+
fill="none"
30+
stroke="currentColor"
31+
>
32+
<path
33+
strokeWidth="2"
34+
strokeLinecap="round"
35+
strokeLinejoin="round"
36+
d="M6 18L18 6M6 6l12 12"
37+
/>
38+
</svg>
39+
</Button>
40+
</div>
41+
{isLoading && <p className="whitespace-normal break-words">Loading...</p>}
42+
{error && <p className="whitespace-normal break-words">{error}</p>}
43+
{newItem && (
44+
<pre className="bg-gray-100 p-2 rounded w-full whitespace-pre-wrap break-words overflow-x-auto text-xs">
45+
{JSON.stringify(newItem, null, 2)}
46+
</pre>
47+
)}
48+
</div>
49+
<div className="grid grid-cols-2 gap-4">
50+
<Button type="button" onClick={reload}>
51+
Reload
52+
</Button>
53+
</div>
54+
</Panel>
55+
);
56+
}
57+
export default ItemDetails;

example/src/pages/Main/ItemList.jsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,21 @@ PaginationButton.propTypes = {
1919
children: T.node.isRequired,
2020
};
2121

22-
function ItemList({ items, isLoading, error, nextPage, previousPage }) {
22+
function ItemList({ items, isLoading, error, nextPage, previousPage, onSelect }) {
2323
return (
2424
<Panel className="grid grid-rows-[1fr_min-content] p-4">
2525
<div className="overflow-x-clip">
2626
<H2>Item List</H2>
2727
{isLoading && <p>Loading...</p>}
2828
{error && <p>{error}</p>}
2929
{items && (
30-
<ul>
31-
{items.features.map(({ id }) => (
32-
<li key={id}>{id}</li>
30+
<ul className="space-y-2">
31+
{items.features.map((item) => (
32+
<li key={item.id}>
33+
<button onClick={onSelect(item)} className="text-pretty">
34+
{item.id}
35+
</button>
36+
</li>
3337
))}
3438
</ul>
3539
)}
@@ -52,6 +56,7 @@ ItemList.propTypes = {
5256
error: T.string,
5357
previousPage: T.func,
5458
nextPage: T.func,
59+
onSelect: T.func,
5560
};
5661

5762
export default ItemList;

example/src/pages/Main/index.jsx

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useStacSearch, useCollections, useStacApi, StacApiProvider } from 'stac
55
import ItemList from './ItemList';
66
import Map from './Map';
77
import QueryBuilder from './QueryBuilder';
8+
import ItemDetails from './ItemDetails';
89

910
// eslint-disable-next-line no-unused-vars
1011
const options = {
@@ -43,6 +44,18 @@ function Main() {
4344
[setBbox]
4445
);
4546

47+
const [selectedItem, setSelectedItem] = useState(null);
48+
49+
const onSelect = useCallback(
50+
(item) => () => {
51+
setSelectedItem(item);
52+
},
53+
[]
54+
);
55+
const onClose = useCallback(() => {
56+
setSelectedItem(null);
57+
}, []);
58+
4659
return (
4760
<div className="grid grid-cols-4 gap-4 m-4">
4861
<QueryBuilder
@@ -56,13 +69,18 @@ function Main() {
5669
dateRangeTo={dateRangeTo}
5770
setDateRangeTo={setDateRangeTo}
5871
/>
59-
<ItemList
60-
items={results}
61-
isLoading={state === 'LOADING'}
62-
error={error && 'Error loading results'}
63-
nextPage={nextPage}
64-
previousPage={previousPage}
65-
/>
72+
{selectedItem ? (
73+
<ItemDetails item={selectedItem} onClose={onClose} />
74+
) : (
75+
<ItemList
76+
items={results}
77+
isLoading={state === 'LOADING'}
78+
error={error && 'Error loading results'}
79+
nextPage={nextPage}
80+
previousPage={previousPage}
81+
onSelect={onSelect}
82+
/>
83+
)}
6684
<Map
6785
className="col-span-2"
6886
isBboxDrawEnabled={isBboxDrawEnabled}

0 commit comments

Comments
 (0)