From ea1d0023bfee55358ebb1a96f3d06e783a219c0d Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Sun, 1 Jun 2025 20:46:41 +0100
Subject: feat: Add support for public lists (#1511)

* WIP: public lists

* Drop viewing modes

* Add the public endpoint for assets

* regen the openapi spec

* proper handling for different asset types

* Add num bookmarks and a no bookmark banner

* Correctly set page title

* Add a not-found page

* merge the RSS and public list endpoints

* Add e2e tests for the public endpoints

* Redesign the share list modal

* Make NEXTAUTH_SECRET not required

* propery render text bookmarks

* rebase migration

* fix public token tests

* Add more tests
---
 .../components/dashboard/lists/PublicListLink.tsx  | 67 ++++++++++++++++++++++
 1 file changed, 67 insertions(+)
 create mode 100644 apps/web/components/dashboard/lists/PublicListLink.tsx

(limited to 'apps/web/components/dashboard/lists/PublicListLink.tsx')

diff --git a/apps/web/components/dashboard/lists/PublicListLink.tsx b/apps/web/components/dashboard/lists/PublicListLink.tsx
new file mode 100644
index 00000000..9cd1f795
--- /dev/null
+++ b/apps/web/components/dashboard/lists/PublicListLink.tsx
@@ -0,0 +1,67 @@
+"use client";
+
+import { CopyBtnV2 } from "@/components/ui/copy-button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import { Switch } from "@/components/ui/switch";
+import { useClientConfig } from "@/lib/clientConfig";
+import { useTranslation } from "react-i18next";
+
+import { useEditBookmarkList } from "@karakeep/shared-react/hooks/lists";
+import { ZBookmarkList } from "@karakeep/shared/types/lists";
+
+export default function PublicListLink({ list }: { list: ZBookmarkList }) {
+  const { t } = useTranslation();
+  const clientConfig = useClientConfig();
+
+  const { mutate: editList, isPending: isLoading } = useEditBookmarkList();
+
+  const publicListUrl = `${clientConfig.publicUrl}/public/lists/${list.id}`;
+  const isPublic = list.public;
+
+  return (
+    <>
+      {/* Public List Toggle */}
+      <div className="flex items-center justify-between">
+        <div className="space-y-1">
+          <Label htmlFor="public-toggle" className="text-sm font-medium">
+            {t("lists.public_list.title")}
+          </Label>
+          <p className="text-xs text-muted-foreground">
+            {t("lists.public_list.description")}
+          </p>
+        </div>
+        <Switch
+          id="public-toggle"
+          checked={isPublic}
+          disabled={isLoading || !!clientConfig.demoMode}
+          onCheckedChange={(checked) => {
+            editList({
+              listId: list.id,
+              public: checked,
+            });
+          }}
+        />
+      </div>
+
+      {/* Share URL - only show when public */}
+      {isPublic && (
+        <>
+          <div className="space-y-3">
+            <Label className="text-sm font-medium">
+              {t("lists.public_list.share_link")}
+            </Label>
+            <div className="flex items-center space-x-2">
+              <Input
+                value={publicListUrl}
+                readOnly
+                className="flex-1 text-sm"
+              />
+              <CopyBtnV2 getStringToCopy={() => publicListUrl} />
+            </div>
+          </div>
+        </>
+      )}
+    </>
+  );
+}
-- 
cgit v1.2.3-70-g09d2

