From 8a5a109cdf14b6503b6bd07aa667788924a12fe6 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Sun, 23 Nov 2025 12:22:34 +0000
Subject: feat(mobile): Add highlights page to mobile app (#2156)

* feat: Add highlights page to mobile app

This commit adds a new highlights page to the mobile app where users can
view all their highlights with the following features:

- HighlightCard component: Displays individual highlights with colored borders,
  text, optional notes, timestamps, and a link to the source bookmark
- HighlightList component: Renders a scrollable list of highlights with
  pull-to-refresh and infinite scroll pagination
- UpdatingHighlightList component: Handles data fetching using tRPC infinite
  queries with automatic cache invalidation
- New /dashboard/highlights route with large header title
- Added navigation link in Settings tab under "App Settings"

All components follow the existing mobile app patterns and integrate with
the existing highlights API.

* make it a tab

---------

Co-authored-by: Claude <noreply@anthropic.com>
---
 apps/mobile/app/dashboard/(tabs)/highlights.tsx | 56 +++++++++++++++++++++++++
 1 file changed, 56 insertions(+)
 create mode 100644 apps/mobile/app/dashboard/(tabs)/highlights.tsx

(limited to 'apps/mobile/app/dashboard/(tabs)/highlights.tsx')

diff --git a/apps/mobile/app/dashboard/(tabs)/highlights.tsx b/apps/mobile/app/dashboard/(tabs)/highlights.tsx
new file mode 100644
index 00000000..7879081b
--- /dev/null
+++ b/apps/mobile/app/dashboard/(tabs)/highlights.tsx
@@ -0,0 +1,56 @@
+import { View } from "react-native";
+import FullPageError from "@/components/FullPageError";
+import HighlightList from "@/components/highlights/HighlightList";
+import CustomSafeAreaView from "@/components/ui/CustomSafeAreaView";
+import FullPageSpinner from "@/components/ui/FullPageSpinner";
+import PageTitle from "@/components/ui/PageTitle";
+
+import { api } from "@karakeep/shared-react/trpc";
+
+export default function Highlights() {
+  const apiUtils = api.useUtils();
+  const {
+    data,
+    isPending,
+    isPlaceholderData,
+    error,
+    fetchNextPage,
+    isFetchingNextPage,
+    refetch,
+  } = api.highlights.getAll.useInfiniteQuery(
+    {},
+    {
+      initialCursor: null,
+      getNextPageParam: (lastPage) => lastPage.nextCursor,
+    },
+  );
+
+  if (error) {
+    return <FullPageError error={error.message} onRetry={() => refetch()} />;
+  }
+
+  if (isPending || !data) {
+    return <FullPageSpinner />;
+  }
+
+  const onRefresh = () => {
+    apiUtils.highlights.getAll.invalidate();
+  };
+
+  return (
+    <CustomSafeAreaView>
+      <HighlightList
+        highlights={data.pages.flatMap((p) => p.highlights)}
+        header={
+          <View className="flex flex-row justify-between">
+            <PageTitle title="Highlights" />
+          </View>
+        }
+        onRefresh={onRefresh}
+        fetchNextPage={fetchNextPage}
+        isFetchingNextPage={isFetchingNextPage}
+        isRefreshing={isPending || isPlaceholderData}
+      />
+    </CustomSafeAreaView>
+  );
+}
-- 
cgit v1.2.3-70-g09d2

