|
1 | | -// The pages at the top of the sidebar: the search (spec 8.8), the |
2 | | -// question box (spec 23.6) and every routine (spec 20.9). |
3 | | - |
4 | | -import { AlarmClock, MessageCircleQuestion, Search } from "lucide-react"; |
5 | | -import { useT } from "../../i18n"; |
6 | | -import { useApp } from "../../store/context"; |
7 | | -import { openQuestions } from "../../store/questions"; |
8 | | -import { CountBadge } from "../../ui/Badge"; |
| 1 | +// What the sidebar's rows share. The pages that used to sit at its top |
| 2 | +// (search, questions, routines) are on the rail now (shell/Rail.tsx). |
9 | 3 |
|
10 | 4 | /** A row of the sidebar, as the conversations are. */ |
11 | 5 | export const row = |
12 | 6 | "relative flex w-full items-center rounded-lg text-left transition-colors duration-150 hover:bg-sunken"; |
13 | | - |
14 | | -/** The search (spec 8.8). */ |
15 | | -export function SearchEntry() { |
16 | | - const t = useT(); |
17 | | - const open = useApp((state) => state.page === "search"); |
18 | | - const openPage = useApp((state) => state.openPage); |
19 | | - return ( |
20 | | - <div className="shrink-0 px-2"> |
21 | | - <button |
22 | | - type="button" |
23 | | - aria-current={open ? "page" : undefined} |
24 | | - title={t.search.open} |
25 | | - onClick={() => openPage("search")} |
26 | | - className={`${row} gap-2.5 px-2.5 py-1.5 text-sm ${open ? "bg-sunken text-ink" : "text-ink-soft"}`} |
27 | | - > |
28 | | - <Search aria-hidden size={16} className="text-muted" /> |
29 | | - <span className="min-w-0 flex-1 truncate font-medium">{t.search.label}</span> |
30 | | - <kbd className="font-sans text-[11px] text-muted">Ctrl K</kbd> |
31 | | - </button> |
32 | | - </div> |
33 | | - ); |
34 | | -} |
35 | | - |
36 | | -/** The question box (spec 23.6), with how many questions wait. */ |
37 | | -export function QuestionsEntry() { |
38 | | - const t = useT(); |
39 | | - const words = t.questions.box; |
40 | | - const count = useApp((state) => openQuestions(state).length); |
41 | | - const open = useApp((state) => state.page === "questions"); |
42 | | - const openPage = useApp((state) => state.openPage); |
43 | | - return ( |
44 | | - <div className="shrink-0 px-2"> |
45 | | - <button |
46 | | - type="button" |
47 | | - aria-current={open ? "page" : undefined} |
48 | | - title={words.open(count)} |
49 | | - onClick={() => openPage("questions")} |
50 | | - className={`${row} gap-2.5 px-2.5 py-1.5 text-sm ${open ? "bg-sunken text-ink" : "text-ink-soft"}`} |
51 | | - > |
52 | | - <MessageCircleQuestion |
53 | | - aria-hidden |
54 | | - size={16} |
55 | | - className={count > 0 ? "text-warn" : "text-muted"} |
56 | | - /> |
57 | | - <span className="min-w-0 flex-1 truncate font-medium">{words.label}</span> |
58 | | - {count > 0 && <CountBadge tone="warn" count={count} label={words.open(count)} />} |
59 | | - </button> |
60 | | - </div> |
61 | | - ); |
62 | | -} |
63 | | - |
64 | | -/** Every routine of every bot (spec 20.9), shown once there is one. */ |
65 | | -export function RoutinesEntry() { |
66 | | - const t = useT(); |
67 | | - const any = useApp((state) => Object.keys(state.routines).length > 0); |
68 | | - const open = useApp((state) => state.page === "routines"); |
69 | | - const openPage = useApp((state) => state.openPage); |
70 | | - if (!any && !open) { |
71 | | - return null; |
72 | | - } |
73 | | - return ( |
74 | | - <div className="shrink-0 px-2"> |
75 | | - <button |
76 | | - type="button" |
77 | | - aria-current={open ? "page" : undefined} |
78 | | - onClick={() => openPage("routines")} |
79 | | - className={`${row} gap-2.5 px-2.5 py-1.5 text-sm ${open ? "bg-sunken text-ink" : "text-ink-soft"}`} |
80 | | - > |
81 | | - <AlarmClock aria-hidden size={16} className="text-muted" /> |
82 | | - <span className="min-w-0 flex-1 truncate font-medium">{t.routines.page.title}</span> |
83 | | - </button> |
84 | | - </div> |
85 | | - ); |
86 | | -} |
0 commit comments