From 9695bba2e993b48ae333da622fa459dbaacb9349 Mon Sep 17 00:00:00 2001
From: Mohamed Bassem <me@mbassem.com>
Date: Sat, 31 May 2025 18:46:04 +0100
Subject: feat: Generate RSS feeds from lists (#1507)

* refactor: Move bookmark utils from shared-react to shared

* Expose RSS feeds for lists

* Add e2e tests

* Slightly improve the look of the share dialog

* allow specifying a limit in the rss endpoint
---
 .../components/dashboard/lists/ShareListModal.tsx  | 68 ++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 apps/web/components/dashboard/lists/ShareListModal.tsx

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

diff --git a/apps/web/components/dashboard/lists/ShareListModal.tsx b/apps/web/components/dashboard/lists/ShareListModal.tsx
new file mode 100644
index 00000000..5c7b060e
--- /dev/null
+++ b/apps/web/components/dashboard/lists/ShareListModal.tsx
@@ -0,0 +1,68 @@
+import { useState } from "react";
+import { Button } from "@/components/ui/button";
+import {
+  Dialog,
+  DialogClose,
+  DialogContent,
+  DialogFooter,
+  DialogHeader,
+  DialogTitle,
+  DialogTrigger,
+} from "@/components/ui/dialog";
+import { useTranslation } from "@/lib/i18n/client";
+import { DialogDescription } from "@radix-ui/react-dialog";
+
+import { ZBookmarkList } from "@karakeep/shared/types/lists";
+
+import RssLink from "./RssLink";
+
+export function ShareListModal({
+  open: userOpen,
+  setOpen: userSetOpen,
+  list,
+  children,
+}: {
+  open?: boolean;
+  setOpen?: (v: boolean) => void;
+  list: ZBookmarkList;
+  children?: React.ReactNode;
+}) {
+  const { t } = useTranslation();
+  if (
+    (userOpen !== undefined && !userSetOpen) ||
+    (userOpen === undefined && userSetOpen)
+  ) {
+    throw new Error("You must provide both open and setOpen or neither");
+  }
+  const [customOpen, customSetOpen] = useState(false);
+  const [open, setOpen] = [
+    userOpen ?? customOpen,
+    userSetOpen ?? customSetOpen,
+  ];
+
+  return (
+    <Dialog
+      open={open}
+      onOpenChange={(s) => {
+        setOpen(s);
+      }}
+    >
+      {children && <DialogTrigger asChild>{children}</DialogTrigger>}
+      <DialogContent className="max-w-xl">
+        <DialogHeader>
+          <DialogTitle>{t("lists.share_list")}</DialogTitle>
+        </DialogHeader>
+        <DialogDescription className="mt-4 flex flex-col gap-2">
+          <RssLink listId={list.id} />
+        </DialogDescription>
+        <DialogFooter className="sm:justify-end">
+          <DialogClose asChild>
+            <Button type="button" variant="secondary">
+              {t("actions.close")}
+            </Button>
+          </DialogClose>
+        </DialogFooter>
+      </DialogContent>
+    </Dialog>
+  );
+}
-- 
cgit v1.2.3-70-g09d2

