55c9a60a0e
Calendar and Gantt used text-sm while Board used text-xs, causing the tab container to change size when switching views. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
108 lines
3.6 KiB
Svelte
108 lines
3.6 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { joinBoard, leaveBoard, onBoardEvent, offBoardEvent } from '$lib/stores/socket.js';
|
|
import GanttChart from '$lib/components/GanttChart.svelte';
|
|
|
|
let { data } = $props();
|
|
|
|
let cards = $state(data.cards);
|
|
let dependencies = $state(data.dependencies);
|
|
|
|
onMount(() => {
|
|
joinBoard(data.board.id);
|
|
|
|
function onCardUpdated(payload: any) {
|
|
if (payload.card) {
|
|
const c = payload.card;
|
|
const existing = cards.findIndex((card: any) => card.id === c.id);
|
|
if (existing >= 0) {
|
|
if (c.startDate || c.dueDate) {
|
|
cards[existing] = { ...cards[existing], ...c };
|
|
} else {
|
|
cards = cards.filter((_: any, i: number) => i !== existing);
|
|
}
|
|
} else if (c.startDate || c.dueDate) {
|
|
cards = [...cards, c];
|
|
}
|
|
}
|
|
}
|
|
|
|
function onCardCreated(payload: any) {
|
|
if (payload.card && (payload.card.startDate || payload.card.dueDate)) {
|
|
cards = [...cards, payload.card];
|
|
}
|
|
}
|
|
|
|
function onCardDeleted(payload: any) {
|
|
cards = cards.filter((c: any) => c.id !== payload.cardId);
|
|
dependencies = dependencies.filter(
|
|
(d: any) => d.blockingCardId !== payload.cardId && d.blockedCardId !== payload.cardId
|
|
);
|
|
}
|
|
|
|
onBoardEvent('card:updated', onCardUpdated);
|
|
onBoardEvent('card:created', onCardCreated);
|
|
onBoardEvent('card:deleted', onCardDeleted);
|
|
|
|
return () => {
|
|
offBoardEvent('card:updated', onCardUpdated);
|
|
offBoardEvent('card:created', onCardCreated);
|
|
offBoardEvent('card:deleted', onCardDeleted);
|
|
leaveBoard(data.board.id);
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>{data.board.title} - Gantt</title>
|
|
</svelte:head>
|
|
|
|
<div class="flex flex-col h-[calc(100vh-3.5rem)]">
|
|
<!-- Header -->
|
|
<div class="flex items-center gap-3 px-4 py-3 bg-white/80 border-b border-gray-200 dark:bg-gray-900/80 dark:border-gray-700 flex-wrap">
|
|
<a href="/boards/{data.board.id}" class="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 transition" aria-label="Back to board">
|
|
<svg class="w-5 h-5" viewBox="0 0 20 20" fill="currentColor">
|
|
<path fill-rule="evenodd" d="M17 10a.75.75 0 01-.75.75H5.612l4.158 3.96a.75.75 0 11-1.04 1.08l-5.5-5.25a.75.75 0 010-1.08l5.5-5.25a.75.75 0 111.04 1.08L5.612 9.25H16.25A.75.75 0 0117 10z" clip-rule="evenodd" />
|
|
</svg>
|
|
</a>
|
|
<h1 class="text-lg font-bold text-gray-900 dark:text-gray-100">{data.board.title}</h1>
|
|
|
|
<div class="flex gap-1 bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5">
|
|
<a
|
|
href="/boards/{data.board.id}"
|
|
class="px-3 py-1 text-xs rounded-md text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
|
|
>
|
|
Board
|
|
</a>
|
|
<a
|
|
href="/boards/{data.board.id}/calendar"
|
|
class="px-3 py-1 text-xs rounded-md text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300"
|
|
>
|
|
Calendar
|
|
</a>
|
|
<span class="px-3 py-1 text-xs rounded-md bg-white dark:bg-gray-700 shadow-sm font-medium text-gray-900 dark:text-gray-100">
|
|
Gantt
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Gantt Chart -->
|
|
<div class="flex-1 overflow-hidden">
|
|
{#if cards.length === 0}
|
|
<div class="text-center py-12">
|
|
<p class="text-gray-400 dark:text-gray-500">No cards with dates to display.</p>
|
|
<p class="text-sm text-gray-400 dark:text-gray-500 mt-1">Set start dates or due dates on cards to see them here.</p>
|
|
<a href="/boards/{data.board.id}" class="text-sm text-[var(--color-primary)] hover:underline mt-2 inline-block">Back to board</a>
|
|
</div>
|
|
{:else}
|
|
<GanttChart
|
|
{cards}
|
|
columns={data.columns}
|
|
{dependencies}
|
|
boardId={data.board.id}
|
|
cardPrefix={data.board.cardPrefix}
|
|
/>
|
|
{/if}
|
|
</div>
|
|
</div>
|