File size: 3,352 Bytes
87a665c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<script lang="ts">
	import { getContext } from 'svelte';
	import { slide } from 'svelte/transition';
	import TaskListIcon from '$lib/components/icons/TaskList.svelte';
	import ChevronDown from '$lib/components/icons/ChevronDown.svelte';
	import ChevronUp from '$lib/components/icons/ChevronUp.svelte';

	const i18n = getContext('i18n');

	export let tasks: Array<{ id: string; content: string; status: string }> = [];

	let collapsed = false;

	$: completedCount = tasks.filter((t) => t.status === 'completed').length;
	$: totalCount = tasks.length;
	$: hasActive = tasks.some((t) => t.status === 'pending' || t.status === 'in_progress');
</script>

{#if tasks.length > 0 && hasActive}
	<div
		class="my-2 rounded-2xl border border-gray-50 dark:border-gray-850 bg-white dark:bg-gray-900"
		transition:slide={{ duration: 200 }}
	>
		<!-- Header -->
		<div class="flex items-center justify-between px-3.5 py-2">
			<div class="flex items-center gap-1.5 text-xs text-gray-600 dark:text-gray-400">
				<TaskListIcon className="w-3.5 h-3.5" />
				<span>
					{completedCount}
					{$i18n.t('out of')}
					{totalCount}
					{$i18n.t('tasks completed')}
				</span>
			</div>

			<button
				class="p-1 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors"
				on:click={() => (collapsed = !collapsed)}
				aria-label={collapsed ? 'Expand' : 'Collapse'}
			>
				{#if collapsed}
					<ChevronUp className="w-2.5 h-2.5" />
				{:else}
					<ChevronDown className="w-2.5 h-2.5" />
				{/if}
			</button>
		</div>

		<!-- Task list -->
		{#if !collapsed}
			<div class="px-3.5 pb-2.5 space-y-0.5" transition:slide={{ duration: 150 }}>
				{#each tasks as task, idx (task.id)}
					<div class="flex items-start gap-2 py-0.5 text-xs">
						<span class="flex-shrink-0 mt-0.5 text-gray-400 dark:text-gray-500">
							{#if task.status === 'completed'}
								<svg
									class="w-3.5 h-3.5"
									viewBox="0 0 24 24"
									fill="none"
									stroke="currentColor"
									stroke-width="2.5"
								>
									<path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round" />
								</svg>
							{:else if task.status === 'in_progress'}
								<svg
									class="w-3.5 h-3.5 animate-spin"
									viewBox="0 0 24 24"
									fill="none"
									stroke="currentColor"
									stroke-width="2.5"
								>
									<path d="M12 3a9 9 0 1 0 9 9" stroke-linecap="round" />
								</svg>
							{:else if task.status === 'cancelled'}
								<svg
									class="w-3.5 h-3.5"
									viewBox="0 0 24 24"
									fill="none"
									stroke="currentColor"
									stroke-width="2"
								>
									<circle cx="12" cy="12" r="9" stroke-dasharray="4 3" />
								</svg>
							{:else}
								<svg
									class="w-3.5 h-3.5"
									viewBox="0 0 24 24"
									fill="none"
									stroke="currentColor"
									stroke-width="2"
								>
									<circle cx="12" cy="12" r="9" />
								</svg>
							{/if}
						</span>
						<span
							class="line-clamp-2 {task.status === 'completed'
								? 'line-through text-gray-400 dark:text-gray-500'
								: task.status === 'cancelled'
									? 'line-through text-gray-400 dark:text-gray-600'
									: 'text-gray-700 dark:text-gray-300'}"
						>
							{idx + 1}. {task.content}
						</span>
					</div>
				{/each}
			</div>
		{/if}
	</div>
{/if}