@@ -32,8 +37,8 @@ export default function Media({ link }: { link: string }) {
render={}
/>
- Link embeds can expose your ip address. You can configure trusted
- domains in the settings.
+ Link embeds can get your IP-Address! You can configure trusted domains
+ in the settings.
diff --git a/packages/chat/src/components/mediaSaveButton.tsx b/packages/chat/src/components/mediaSaveButton.tsx
new file mode 100644
index 0000000..5179aac
--- /dev/null
+++ b/packages/chat/src/components/mediaSaveButton.tsx
@@ -0,0 +1,63 @@
+import { Button, cn } from "@tensamin/ui";
+import { useStorage } from "@tensamin/storage/context";
+import { Save } from "lucide-react";
+import { useEffect, useState } from "react";
+
+export default function MediaSaveButton({
+ ariaLabel,
+ className,
+ defaultSaved = false,
+ onSavedMediaChange,
+ url,
+}: {
+ ariaLabel?: string;
+ className?: string;
+ defaultSaved?: boolean;
+ onSavedMediaChange?: (savedMedia: string[]) => void;
+ url: string;
+}) {
+ const { load, save } = useStorage();
+ const [savedMedia, setSavedMedia] = useState
(null);
+ const isSaved = savedMedia ? savedMedia.includes(url) : defaultSaved;
+
+ useEffect(() => {
+ void load("chat_picker_saved_media").then(setSavedMedia);
+ }, [load]);
+
+ async function handleClick(event: React.MouseEvent) {
+ event.stopPropagation();
+
+ const currentSavedMedia =
+ savedMedia ?? (await load("chat_picker_saved_media"));
+ const nextSavedMedia = currentSavedMedia.includes(url)
+ ? currentSavedMedia.filter((item) => item !== url)
+ : [url, ...currentSavedMedia];
+
+ setSavedMedia(nextSavedMedia);
+ onSavedMediaChange?.(nextSavedMedia);
+ void save("chat_picker_saved_media", nextSavedMedia);
+ }
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/shared/src/data.ts b/packages/shared/src/data.ts
index ade2562..aa14339 100644
--- a/packages/shared/src/data.ts
+++ b/packages/shared/src/data.ts
@@ -261,6 +261,12 @@ export interface Storage extends SettingsStorageDefaults {
call_mute_range_start: number;
call_mute_range_end: number;
chat_trusted_domains: string[];
+ chat_picker_saved_media: string[];
+ chat_picker_last_tab: "gif" | "meme" | "saved";
+ chat_picker_size: {
+ width: number;
+ height: number;
+ } | null;
}
export const storageDefaults: Storage = {
@@ -297,7 +303,33 @@ export const storageDefaults: Storage = {
ttp_server_cert: "",
call_mute_range_start: -55,
call_mute_range_end: -45,
- chat_trusted_domains: ["tenor.com", "c.tenor.com"],
+ chat_trusted_domains: [
+ // Other platforms
+ "cdn.discordapp.com",
+
+ // Tenor
+ "tenor.com",
+ "c.tenor.com",
+
+ // Klipy
+ "static.klipy.com",
+ "static1.klipy.com",
+ "static2.klipy.com",
+
+ // Giphy
+ "giphy.com",
+ "www.giphy.com",
+ "media.giphy.com",
+ "i.giphy.com",
+ "media0.giphy.com",
+ "media1.giphy.com",
+ "media2.giphy.com",
+ "media3.giphy.com",
+ "media4.giphy.com",
+ ],
+ chat_picker_saved_media: [],
+ chat_picker_last_tab: "gif",
+ chat_picker_size: null,
};
// User Status