diff --git a/apps/common/features/package.json b/apps/common/features/package.json
index 2ca07cfce..64051045c 100644
--- a/apps/common/features/package.json
+++ b/apps/common/features/package.json
@@ -29,9 +29,11 @@
"dayjs": "^1.11.13",
"js-cookie": "^3.0.5",
"next": "15.3.0",
+ "next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0",
"react-dnd": "^16.0.1",
"react-hook-form": "^7.54.2",
+ "sonner": "^2.0.1",
"tailwindcss-animate": "^1.0.7",
"tus-js-client": "^4.3.1",
"zod": "^3.24.2",
diff --git a/apps/common/features/src/app/providers/app-provider.tsx b/apps/common/features/src/app/providers/app-provider.tsx
index 721f04bb6..97713c41e 100644
--- a/apps/common/features/src/app/providers/app-provider.tsx
+++ b/apps/common/features/src/app/providers/app-provider.tsx
@@ -5,10 +5,11 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
import { AuthWrapper } from "@/entities/auth";
import { MenuWrapper } from "@/entities/menu";
-import { StoreProvider, PromptProvider } from "@/shared/providers";
+import { Toaster } from "@/shared/ui/sonner";
import { AlertDialog } from "@/shared/ui/alert-dialog";
import { PromptDialog } from "@/shared/ui/prompt-dialog";
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
+import { StoreProvider, PromptProvider } from "@/shared/providers";
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
const queryClient = new QueryClient();
@@ -22,6 +23,7 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
+
diff --git a/apps/common/features/src/shared/ui/sonner.tsx b/apps/common/features/src/shared/ui/sonner.tsx
new file mode 100644
index 000000000..f96a98d91
--- /dev/null
+++ b/apps/common/features/src/shared/ui/sonner.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import { useTheme } from "next-themes";
+import { Toaster as Sonner, type ToasterProps } from "sonner";
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme();
+
+ return (
+
+ );
+};
+
+export { Toaster };
diff --git a/apps/common/features/src/widgets/post/ui/post-action.tsx b/apps/common/features/src/widgets/post/ui/post-action.tsx
index afc614bc1..4ca431f7a 100644
--- a/apps/common/features/src/widgets/post/ui/post-action.tsx
+++ b/apps/common/features/src/widgets/post/ui/post-action.tsx
@@ -1,5 +1,7 @@
+import { toast } from "sonner";
+import { useEffect } from "react";
import { useRouter, usePathname } from "next/navigation";
-import { useConfirm } from "@frontend-opensource/use-react-hooks";
+import { useClipboard, useConfirm } from "@frontend-opensource/use-react-hooks";
import { Button } from "@common/components";
import { AuthorityButton } from "@/entities/menu-authority";
import { useMenuStore, useUserStore } from "@/shared/lib";
@@ -13,6 +15,7 @@ type PostActionProps = {
function PostAction({ registerId, children, handleDelete }: PostActionProps) {
const router = useRouter();
const pathname = usePathname();
+ const { copyText, copied } = useClipboard();
const { confirm } = useConfirm();
const bbsInfo = useMenuStore((state) => state.bbsInfo);
const userInfo = useUserStore((state) => state.userInfo);
@@ -37,10 +40,22 @@ function PostAction({ registerId, children, handleDelete }: PostActionProps) {
return true;
};
+ useEffect(() => {
+ if (copied) toast.success("URL이 클립보드에 복사되었습니다.");
+ }, [copied]);
+
return (
<>
{children}
+