Plugin

CopyFileContents

Adds a button to text file attachments to copy their contents

Utility
index.tsx
Download

Source

src/plugins/copyFileContents/index.tsx
1/*
2 * FiveCord — a Discord client mod
3 * Copyright (c) 2025 FiveCord
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
7import "./style.css";
8
9import ErrorBoundary from "@components/ErrorBoundary";
10import { CopyIcon, NoEntrySignIcon } from "@components/Icons";
11import { Devs } from "@utils/constants";
12import { copyWithToast } from "@utils/discord";
13import definePlugin from "@utils/types";
14import { Tooltip, useState } from "@webpack/common";
15
16const CheckMarkIcon = () => {
17 return <svg width="18" height="18" viewBox="0 0 24 24">
18 <path fill="currentColor" d="M21.7 5.3a1 1 0 0 1 0 1.4l-12 12a1 1 0 0 1-1.4 0l-6-6a1 1 0 1 1 1.4-1.4L9 16.58l11.3-11.3a1 1 0 0 1 1.4 0Z"></path>
19 </svg>;
20};
21
22export default definePlugin({
23 name: "CopyFileContents",
24 description: "Adds a button to text file attachments to copy their contents",
25 tags: ["Utility"],
26 authors: [Devs.Obsidian, Devs.Nuckyz],
27 patches: [
28 {
29 find: "#{intl::PREVIEW_BYTES_LEFT}",
30 replacement: [
31 // Inline preview
32 {
33 match: /fileContents:(\i),bytesLeft:(\i)\}\):null,/,
34 replace: "$&$self.addCopyButton({fileContents:$1,bytesLeft:$2}),"
35 },
36 // Modal
37 {
38 match: /align:"\i"\}\),(?=\(0,\i\.jsx\)\(\i,\{wordWrap:\i,setWordWrap:\i)/,
39 replace: "$&$self.addCopyButton(arguments[0]),"
40 }
41 ]
42 }
43 ],
44
45 addCopyButton: ErrorBoundary.wrap(({ fileContents, bytesLeft }: { fileContents: string, bytesLeft: number; }) => {
46 const [recentlyCopied, setRecentlyCopied] = useState(false);
47
48 return (
49 <Tooltip text={recentlyCopied ? "Copied!" : bytesLeft > 0 ? "File too large to copy" : "Copy File Contents"}>
50 {tooltipProps => (
51 <div
52 {...tooltipProps}
53 className="vc-cfc-button"
54 role="button"
55 onClick={() => {
56 if (!recentlyCopied && bytesLeft <= 0) {
57 copyWithToast(fileContents);
58 setRecentlyCopied(true);
59 setTimeout(() => setRecentlyCopied(false), 2000);
60 }
61 }}
62 >
63 {recentlyCopied
64 ? <CheckMarkIcon />
65 : bytesLeft > 0
66 ? <NoEntrySignIcon width={18} height={18} color="var(--channel-icon)" />
67 : <CopyIcon width={18} height={18} />
68 }
69 </div>
70 )}
71 </Tooltip>
72 );
73 }, { noop: true }),
74});
75