@@ -9,7 +9,7 @@ import React, {
99} from "react" ;
1010import { Button } from "@/components/ui/button" ;
1111import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/card" ;
12- import { Calendar } from "lucide-react" ;
12+ import { Calendar , Clipboard } from "lucide-react" ;
1313import { createClient } from "@/lib/supabase/client" ;
1414import { useSupabaseUser } from "@/lib/supabase/hooks/useSupabaseUser" ;
1515import { Input } from "@/components/ui/input" ;
@@ -44,6 +44,7 @@ import { useTaskActions } from "@/hooks/useTaskActions";
4444import { CurrentTaskFooter } from "@/components/CurrentTaskFooter" ;
4545import { TaskContextType } from "@/contexts/TaskContext" ;
4646import { TaskProvider } from "@/contexts/TaskProvider" ;
47+ import { formatTasksAsMarkdown } from "@/lib/formatTasksAsMarkdown" ;
4748
4849const supabase = createClient ( ) ;
4950
@@ -293,6 +294,50 @@ const TaskList = () => {
293294 } ) ;
294295 } ;
295296
297+ // クリップボードにマークダウン形式でコピー
298+ const handleCopyToClipboard = async ( ) => {
299+ if ( tasks . length === 0 ) {
300+ toast ( {
301+ title : "コピー失敗" ,
302+ description : "コピーするタスクがありません" ,
303+ variant : "destructive" ,
304+ } ) ;
305+ return ;
306+ }
307+
308+ const markdown = formatTasksAsMarkdown ( tasks ) ;
309+
310+ try {
311+ // navigator.clipboardが利用可能かチェック
312+ if ( navigator . clipboard && navigator . clipboard . writeText ) {
313+ await navigator . clipboard . writeText ( markdown ) ;
314+ } else {
315+ // フォールバック: 古いブラウザ向け
316+ const textArea = document . createElement ( "textarea" ) ;
317+ textArea . value = markdown ;
318+ textArea . style . position = "fixed" ;
319+ textArea . style . left = "-999999px" ;
320+ textArea . style . top = "-999999px" ;
321+ document . body . appendChild ( textArea ) ;
322+ textArea . focus ( ) ;
323+ textArea . select ( ) ;
324+ document . execCommand ( "copy" ) ;
325+ textArea . remove ( ) ;
326+ }
327+ toast ( {
328+ title : "コピー完了" ,
329+ description : "タスクをマークダウン形式でコピーしました" ,
330+ } ) ;
331+ } catch ( error ) {
332+ console . error ( "Failed to copy to clipboard:" , error ) ;
333+ toast ( {
334+ title : "コピー失敗" ,
335+ description : "クリップボードへのコピーに失敗しました" ,
336+ variant : "destructive" ,
337+ } ) ;
338+ }
339+ } ;
340+
296341 // クイックタスク追加
297342 const handleAddTask = async ( ) => {
298343 if ( ! newTaskTitle . trim ( ) ) {
@@ -499,14 +544,21 @@ const TaskList = () => {
499544 < TaskProvider value = { taskContextValue } >
500545 < div className = "space-y-6 pb-20" >
501546 < div className = "flex items-center justify-between" >
502- < div >
547+ < div className = "flex items-center gap-2" >
548+ < Button
549+ onClick = { handleCopyToClipboard }
550+ variant = "outline"
551+ size = "sm"
552+ className = "flex items-center gap-1"
553+ aria-label = "タスクをマークダウン形式でクリップボードにコピー"
554+ title = "タスク一覧をマークダウンチェックボックス形式でコピーします"
555+ >
556+ < Clipboard className = "h-4 w-4" />
557+ マークダウンでコピー
558+ </ Button >
503559 { totalEstimatedMinutes > 0 && (
504- < p className = "text-sm text-muted-foreground mt-1" >
505- { totalEstimatedMinutes > 0 && (
506- < span className = "ml-2" >
507- 完了予定: { calculateEndTime ( totalEstimatedMinutes ) }
508- </ span >
509- ) }
560+ < p className = "text-sm text-muted-foreground" >
561+ 完了予定: { calculateEndTime ( totalEstimatedMinutes ) }
510562 </ p >
511563 ) }
512564 </ div >
0 commit comments