public
anord
read
Ledger
Why work hard when you can work easier?
Languages
Repository composition by tracked source files.
TypeScript
86%
CSS
10%
SQL
3%
Shell
1%
HTML
0%
Trace
apps/web/src/components/SearchPage.tsx
Trace helps you understand code history line by line. See who changed each line, when it changed, and which commit introduced it.
Author
Date
Commit
Line
Code
1
import { useState } from "react";
2
import { Link } from "react-router-dom";
3
import type { PageSummary } from "@ledger/shared";
4
import { EmptyState } from "./EmptyState";
5
import { Icon } from "./Icon";
6
import { PageHeader } from "./PageHeader";
7
import { SearchBar } from "./SearchBar";
9
type Space = {
10
id: string;
11
name: string;
12
key: string;
13
visibility: string;
14
};
16
export function SearchPage({
17
spaces,
18
results,
19
isLoading,
20
onSearch
21
}: {
22
spaces: Space[];
23
results: PageSummary[];
24
isLoading: boolean;
25
onSearch: (query: string) => Promise<void>;
26
}) {
27
const [query, setQuery] = useState("");
29
async function handleSearch(nextQuery: string) {
30
setQuery(nextQuery);
31
await onSearch(nextQuery);
32
}
34
return (
35
<div className="stack-page">
36
<PageHeader
37
eyebrow="Search"
38
title="Find answers quickly"
39
description="Search across every page you're allowed to read. Results respect the same visibility and group rules as the rest of Ledger."
40
/>
42
<section className="content-section content-section-search">
43
<SearchBar
44
initialQuery={query}
45
onSearch={handleSearch}
46
placeholder="Search pages, policies, onboarding docs, and runbooks"
47
/>
48
</section>
50
<section className="content-section">
51
<div className="section-head">
52
<div>
53
<p className="eyebrow">Results</p>
54
<h3>{query ? `Results for "${query}"` : "Search results"}</h3>
55
</div>
56
</div>
58
{isLoading ? <p className="muted">Searching documentation...</p> : null}
60
{!isLoading && query && results.length === 0 ? (
61
<EmptyState
62
title="No results found"
63
description="Try a broader term, a collection name, or a more specific process keyword."
64
/>
65
) : null}
67
{!isLoading && !query ? (
68
<EmptyState
69
title="Start with a search"
70
description="Search titles and document content. Use Cmd/Ctrl + K anywhere in the app for quick search."
71
/>
72
) : null}
74
{!isLoading && results.length > 0 ? (
75
<div className="document-feed">
76
{results.map((page) => (
77
<Link key={page.id} to={`/page/${page.slug}`} className="document-feed__item">
78
<div className="document-feed__icon">
79
<Icon name="document" className="icon icon-sm" />
80
</div>
81
<div className="document-feed__body">
82
<strong className="document-feed__title">{page.title}</strong>
83
<p className="document-feed__meta">
84
{spaces.find((space) => space.id === page.spaceId)?.name ?? "Collection"} - {page.visibility}
85
</p>
86
<p className="document-feed__excerpt">{page.excerpt ?? "Open this page to read more."}</p>
87
</div>
88
</Link>
89
))}
90
</div>
91
) : null}
92
</section>
93
</div>
94
);
95
}