diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-11-23 10:15:23 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-23 10:15:23 +0000 |
| commit | 48ab8a194974e026104bb2566cf8abd693ba51c1 (patch) | |
| tree | 012ee677cbaf9d0f323a890a752df497d88536f1 | |
| parent | ed6a3bfac52437c0b86767d7a17dc1ae48d8ccb2 (diff) | |
| download | karakeep-48ab8a194974e026104bb2566cf8abd693ba51c1.tar.zst | |
feat(mobile): Add smart list creation in mobile app (#2153)
* feat: Add smart list creation and display in mobile app
This commit adds support for creating and displaying smart lists in the mobile application:
- Enhanced list creation screen to support both manual and smart list types
- Added type selector with manual/smart toggle buttons
- Implemented conditional search query input for smart lists
- Added query validation to ensure smart lists have valid queries
- Improved error handling to display validation errors from the backend
- Added visual indicators (sparkle icon) for smart lists in the lists tab
- Implemented smart list query display in list detail view with sparkle badge
- Enhanced UI with contextual help text for smart list queries
The implementation follows the web app pattern while adapting the UI for mobile best practices.
* fixes
---------
Co-authored-by: Claude <noreply@anthropic.com>
| -rw-r--r-- | apps/mobile/app/dashboard/(tabs)/lists.tsx | 2 | ||||
| -rw-r--r-- | apps/mobile/app/dashboard/lists/new.tsx | 71 |
2 files changed, 69 insertions, 4 deletions
diff --git a/apps/mobile/app/dashboard/(tabs)/lists.tsx b/apps/mobile/app/dashboard/(tabs)/lists.tsx index a2301c36..e40be1a5 100644 --- a/apps/mobile/app/dashboard/(tabs)/lists.tsx +++ b/apps/mobile/app/dashboard/(tabs)/lists.tsx @@ -161,7 +161,7 @@ export default function Lists() { )} <Link asChild key={l.item.id} href={l.item.href} className="flex-1"> - <Pressable className="flex flex-row justify-between"> + <Pressable className="flex flex-row items-center justify-between"> <Text> {l.item.logo} {l.item.name} </Text> diff --git a/apps/mobile/app/dashboard/lists/new.tsx b/apps/mobile/app/dashboard/lists/new.tsx index 55315e70..af51ed15 100644 --- a/apps/mobile/app/dashboard/lists/new.tsx +++ b/apps/mobile/app/dashboard/lists/new.tsx @@ -9,35 +9,81 @@ import { useToast } from "@/components/ui/Toast"; import { useCreateBookmarkList } from "@karakeep/shared-react/hooks/lists"; +type ListType = "manual" | "smart"; + const NewListPage = () => { const dismiss = () => { router.back(); }; const { toast } = useToast(); const [text, setText] = useState(""); + const [listType, setListType] = useState<ListType>("manual"); + const [query, setQuery] = useState(""); const { mutate, isPending } = useCreateBookmarkList({ onSuccess: () => { dismiss(); }, - onError: () => { + onError: (error) => { + // Extract error message from the error object + let errorMessage = "Something went wrong"; + if (error.data?.zodError) { + errorMessage = Object.values(error.data.zodError.fieldErrors) + .flat() + .join("\n"); + } else if (error.message) { + errorMessage = error.message; + } toast({ - message: "Something went wrong", + message: errorMessage, variant: "destructive", }); }, }); const onSubmit = () => { + // Validate smart list has a query + if (listType === "smart" && !query.trim()) { + toast({ + message: "Smart lists must have a search query", + variant: "destructive", + }); + return; + } + mutate({ name: text, icon: "🚀", + type: listType, + query: listType === "smart" ? query : undefined, }); }; return ( <CustomSafeAreaView> - <View className="gap-2 px-4"> + <View className="gap-3 px-4"> + {/* List Type Selector */} + <View className="gap-2"> + <Text className="text-sm text-muted-foreground">List Type</Text> + <View className="flex flex-row gap-2"> + <Button + variant={listType === "manual" ? "primary" : "secondary"} + onPress={() => setListType("manual")} + className="flex-1" + > + <Text>Manual</Text> + </Button> + <Button + variant={listType === "smart" ? "primary" : "secondary"} + onPress={() => setListType("smart")} + className="flex-1" + > + <Text>Smart</Text> + </Button> + </View> + </View> + + {/* List Name */} <View className="flex flex-row items-center gap-1"> <Text className="shrink p-2">🚀</Text> <Input @@ -48,6 +94,25 @@ const NewListPage = () => { autoCapitalize={"none"} /> </View> + + {/* Smart List Query Input */} + {listType === "smart" && ( + <View className="gap-2"> + <Text className="text-sm text-muted-foreground">Search Query</Text> + <Input + className="bg-card" + onChangeText={setQuery} + value={query} + placeholder="e.g., #important OR list:work" + autoCapitalize={"none"} + /> + <Text className="text-xs italic text-muted-foreground"> + Smart lists automatically show bookmarks matching your search + query + </Text> + </View> + )} + <Button disabled={isPending} onPress={onSubmit}> <Text>Save</Text> </Button> |
