codacus commited on
Commit
41da9c8
·
unverified ·
2 Parent(s): ccde238 02f4de4

Merge branch 'coleam00:main' into main

Browse files
app/components/sidebar/Menu.client.tsx CHANGED
@@ -8,6 +8,7 @@ import { cubicEasingFn } from '~/utils/easings';
8
  import { logger } from '~/utils/logger';
9
  import { HistoryItem } from './HistoryItem';
10
  import { binDates } from './date-binning';
 
11
 
12
  const menuVariants = {
13
  closed: {
@@ -39,6 +40,11 @@ export function Menu() {
39
  const [open, setOpen] = useState(false);
40
  const [dialogContent, setDialogContent] = useState<DialogContent>(null);
41
 
 
 
 
 
 
42
  const loadEntries = useCallback(() => {
43
  if (db) {
44
  getAll(db)
@@ -115,11 +121,11 @@ export function Menu() {
115
  initial="closed"
116
  animate={open ? 'open' : 'closed'}
117
  variants={menuVariants}
118
- className="flex flex-col side-menu fixed top-0 w-[350px] h-full bg-bolt-elements-background-depth-2 border-r rounded-r-3xl border-bolt-elements-borderColor z-sidebar shadow-xl shadow-bolt-elements-sidebar-dropdownShadow text-sm"
119
  >
120
  <div className="flex items-center h-[var(--header-height)]">{/* Placeholder */}</div>
121
  <div className="flex-1 flex flex-col h-full w-full overflow-hidden">
122
- <div className="p-4">
123
  <a
124
  href="/"
125
  className="flex gap-2 items-center bg-bolt-elements-sidebar-buttonBackgroundDefault text-bolt-elements-sidebar-buttonText hover:bg-bolt-elements-sidebar-buttonBackgroundHover rounded-md p-2 transition-theme"
@@ -128,11 +134,26 @@ export function Menu() {
128
  Start new chat
129
  </a>
130
  </div>
 
 
 
 
 
 
 
 
 
 
 
131
  <div className="text-bolt-elements-textPrimary font-medium pl-6 pr-5 my-2">Your Chats</div>
132
  <div className="flex-1 overflow-auto pl-4 pr-5 pb-5">
133
- {list.length === 0 && <div className="pl-2 text-bolt-elements-textTertiary">No previous conversations</div>}
 
 
 
 
134
  <DialogRoot open={dialogContent !== null}>
135
- {binDates(list).map(({ category, items }) => (
136
  <div key={category} className="mt-4 first:mt-0 space-y-1">
137
  <div className="text-bolt-elements-textTertiary sticky top-0 z-1 bg-bolt-elements-background-depth-2 pl-2 pt-2 pb-1">
138
  {category}
 
8
  import { logger } from '~/utils/logger';
9
  import { HistoryItem } from './HistoryItem';
10
  import { binDates } from './date-binning';
11
+ import { useSearchFilter } from '~/lib/hooks/useSearchFilter';
12
 
13
  const menuVariants = {
14
  closed: {
 
40
  const [open, setOpen] = useState(false);
41
  const [dialogContent, setDialogContent] = useState<DialogContent>(null);
42
 
43
+ const { filteredItems: filteredList, handleSearchChange } = useSearchFilter({
44
+ items: list,
45
+ searchFields: ['description'],
46
+ });
47
+
48
  const loadEntries = useCallback(() => {
49
  if (db) {
50
  getAll(db)
 
121
  initial="closed"
122
  animate={open ? 'open' : 'closed'}
123
  variants={menuVariants}
124
+ className="flex selection-accent flex-col side-menu fixed top-0 w-[350px] h-full bg-bolt-elements-background-depth-2 border-r rounded-r-3xl border-bolt-elements-borderColor z-sidebar shadow-xl shadow-bolt-elements-sidebar-dropdownShadow text-sm"
125
  >
126
  <div className="flex items-center h-[var(--header-height)]">{/* Placeholder */}</div>
127
  <div className="flex-1 flex flex-col h-full w-full overflow-hidden">
128
+ <div className="p-4 select-none">
129
  <a
130
  href="/"
131
  className="flex gap-2 items-center bg-bolt-elements-sidebar-buttonBackgroundDefault text-bolt-elements-sidebar-buttonText hover:bg-bolt-elements-sidebar-buttonBackgroundHover rounded-md p-2 transition-theme"
 
134
  Start new chat
135
  </a>
136
  </div>
137
+ <div className="pl-4 pr-4 my-2">
138
+ <div className="relative w-full">
139
+ <input
140
+ className="w-full bg-white dark:bg-bolt-elements-background-depth-4 relative px-2 py-1.5 rounded-md focus:outline-none placeholder-bolt-elements-textTertiary text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary border border-bolt-elements-borderColor"
141
+ type="search"
142
+ placeholder="Search"
143
+ onChange={handleSearchChange}
144
+ aria-label="Search chats"
145
+ />
146
+ </div>
147
+ </div>
148
  <div className="text-bolt-elements-textPrimary font-medium pl-6 pr-5 my-2">Your Chats</div>
149
  <div className="flex-1 overflow-auto pl-4 pr-5 pb-5">
150
+ {filteredList.length === 0 && (
151
+ <div className="pl-2 text-bolt-elements-textTertiary">
152
+ {list.length === 0 ? 'No previous conversations' : 'No matches found'}
153
+ </div>
154
+ )}
155
  <DialogRoot open={dialogContent !== null}>
156
+ {binDates(filteredList).map(({ category, items }) => (
157
  <div key={category} className="mt-4 first:mt-0 space-y-1">
158
  <div className="text-bolt-elements-textTertiary sticky top-0 z-1 bg-bolt-elements-background-depth-2 pl-2 pt-2 pb-1">
159
  {category}
app/lib/hooks/useSearchFilter.ts ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useState, useMemo, useCallback } from 'react';
2
+ import { debounce } from '~/utils/debounce';
3
+ import type { ChatHistoryItem } from '~/lib/persistence';
4
+
5
+ interface UseSearchFilterOptions {
6
+ items: ChatHistoryItem[];
7
+ searchFields?: (keyof ChatHistoryItem)[];
8
+ debounceMs?: number;
9
+ }
10
+
11
+ export function useSearchFilter({
12
+ items = [],
13
+ searchFields = ['description'],
14
+ debounceMs = 300,
15
+ }: UseSearchFilterOptions) {
16
+ const [searchQuery, setSearchQuery] = useState('');
17
+
18
+ const debouncedSetSearch = useCallback(debounce(setSearchQuery, debounceMs), []);
19
+
20
+ const handleSearchChange = useCallback(
21
+ (event: React.ChangeEvent<HTMLInputElement>) => {
22
+ debouncedSetSearch(event.target.value);
23
+ },
24
+ [debouncedSetSearch],
25
+ );
26
+
27
+ const filteredItems = useMemo(() => {
28
+ if (!searchQuery.trim()) {
29
+ return items;
30
+ }
31
+
32
+ const query = searchQuery.toLowerCase();
33
+
34
+ return items.filter((item) =>
35
+ searchFields.some((field) => {
36
+ const value = item[field];
37
+
38
+ if (typeof value === 'string') {
39
+ return value.toLowerCase().includes(query);
40
+ }
41
+
42
+ return false;
43
+ }),
44
+ );
45
+ }, [items, searchQuery, searchFields]);
46
+
47
+ return {
48
+ searchQuery,
49
+ filteredItems,
50
+ handleSearchChange,
51
+ };
52
+ }
app/utils/constants.ts CHANGED
@@ -283,9 +283,9 @@ const getOllamaBaseUrl = () => {
283
  };
284
 
285
  async function getOllamaModels(): Promise<ModelInfo[]> {
286
- if (typeof window === 'undefined') {
287
- return [];
288
- }
289
 
290
  try {
291
  const baseUrl = getOllamaBaseUrl();
 
283
  };
284
 
285
  async function getOllamaModels(): Promise<ModelInfo[]> {
286
+ //if (typeof window === 'undefined') {
287
+ //return [];
288
+ //}
289
 
290
  try {
291
  const baseUrl = getOllamaBaseUrl();