Replace bulk select button with hover checkboxes, remove board background override
- Cards now show a checkbox on hover (top-right) for bulk selection, removing the need for a separate "Select" toggle button - Removed BoardBackgroundPicker from board header since per-board backgrounds were overriding tenant branding - Removed inline background style from board area so branding page backgrounds apply correctly Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,6 @@
|
|||||||
import CardModal from '$lib/components/CardModal.svelte';
|
import CardModal from '$lib/components/CardModal.svelte';
|
||||||
import ActivityFeed from '$lib/components/ActivityFeed.svelte';
|
import ActivityFeed from '$lib/components/ActivityFeed.svelte';
|
||||||
import BoardFilters from '$lib/components/BoardFilters.svelte';
|
import BoardFilters from '$lib/components/BoardFilters.svelte';
|
||||||
import BoardBackgroundPicker from '$lib/components/BoardBackgroundPicker.svelte';
|
|
||||||
import BulkToolbar from '$lib/components/BulkToolbar.svelte';
|
import BulkToolbar from '$lib/components/BulkToolbar.svelte';
|
||||||
import ColumnSortMenu from '$lib/components/ColumnSortMenu.svelte';
|
import ColumnSortMenu from '$lib/components/ColumnSortMenu.svelte';
|
||||||
import Avatar from '$lib/components/Avatar.svelte';
|
import Avatar from '$lib/components/Avatar.svelte';
|
||||||
@@ -38,8 +37,8 @@
|
|||||||
let showArchivedCards = $state(false);
|
let showArchivedCards = $state(false);
|
||||||
let archivedCards = $state<any[]>([]);
|
let archivedCards = $state<any[]>([]);
|
||||||
let activeFilters = $state<FilterState>({ labelIds: [], assigneeIds: [], due: null });
|
let activeFilters = $state<FilterState>({ labelIds: [], assigneeIds: [], due: null });
|
||||||
let selectMode = $state(false);
|
|
||||||
let selectedCardIds = $state(new Set<string>());
|
let selectedCardIds = $state(new Set<string>());
|
||||||
|
let selectMode = $derived(selectedCardIds.size > 0);
|
||||||
let columnSorts = $state<Record<string, string | null>>({});
|
let columnSorts = $state<Record<string, string | null>>({});
|
||||||
|
|
||||||
const flipDurationMs = 200;
|
const flipDurationMs = 200;
|
||||||
@@ -488,21 +487,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if data.canEdit}
|
|
||||||
<button
|
|
||||||
onclick={() => { selectMode = !selectMode; if (!selectMode) selectedCardIds = new Set(); }}
|
|
||||||
class="rounded px-2 py-1 text-sm text-gray-500 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-300 transition flex items-center gap-1"
|
|
||||||
class:bg-gray-200={selectMode}
|
|
||||||
title="Select cards for bulk actions"
|
|
||||||
>
|
|
||||||
<svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
||||||
</svg>
|
|
||||||
Select
|
|
||||||
</button>
|
|
||||||
<BoardBackgroundPicker boardId={data.board.id} currentBackground={data.board.background || null} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onclick={() => toggleArchivedCards()}
|
onclick={() => toggleArchivedCards()}
|
||||||
class="ml-auto rounded px-2 py-1 text-sm text-gray-500 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-300 transition flex items-center gap-1"
|
class="ml-auto rounded px-2 py-1 text-sm text-gray-500 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-300 transition flex items-center gap-1"
|
||||||
@@ -554,7 +538,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main area: columns + optional activity sidebar -->
|
<!-- Main area: columns + optional activity sidebar -->
|
||||||
<div class="flex-1 flex overflow-hidden" style="{data.board.background ? `background: ${data.board.background}; background-size: cover; background-position: center;` : ''}">
|
<div class="flex-1 flex overflow-hidden">
|
||||||
<!-- Columns container -->
|
<!-- Columns container -->
|
||||||
<div class="flex-1 overflow-x-auto p-4">
|
<div class="flex-1 overflow-x-auto p-4">
|
||||||
<div
|
<div
|
||||||
@@ -644,8 +628,8 @@
|
|||||||
{#each visibleCards as card (card.id)}
|
{#each visibleCards as card (card.id)}
|
||||||
{@const progress = getChecklistProgress(card)}
|
{@const progress = getChecklistProgress(card)}
|
||||||
{@const dueUrgency = getDueUrgency(card.dueDate)}
|
{@const dueUrgency = getDueUrgency(card.dueDate)}
|
||||||
<button
|
<div
|
||||||
class="w-full text-left mb-2 p-3 shadow-sm hover:shadow-md transition cursor-pointer {selectMode && selectedCardIds.has(card.id) ? 'ring-2 ring-[var(--color-primary)]' : ''}"
|
class="group/card relative w-full text-left mb-2 p-3 shadow-sm hover:shadow-md transition cursor-pointer {selectedCardIds.has(card.id) ? 'ring-2 ring-[var(--color-primary)]' : ''}"
|
||||||
style="background: var(--color-card-bg); border: 1px solid var(--color-card-border); color: var(--color-card-text); border-radius: var(--color-card-radius); backdrop-filter: var(--card-backdrop-blur, none);"
|
style="background: var(--color-card-bg); border: 1px solid var(--color-card-border); color: var(--color-card-text); border-radius: var(--color-card-radius); backdrop-filter: var(--card-backdrop-blur, none);"
|
||||||
animate:flip={{ duration: flipDurationMs }}
|
animate:flip={{ duration: flipDurationMs }}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
@@ -658,7 +642,32 @@
|
|||||||
selectedCard = card;
|
selectedCard = card;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); selectedCard = card; } }}
|
||||||
>
|
>
|
||||||
|
{#if data.canEdit}
|
||||||
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||||
|
<div
|
||||||
|
class="absolute top-1.5 right-1.5 z-10 {selectedCardIds.has(card.id) ? 'opacity-100' : 'opacity-0 group-hover/card:opacity-100'} transition-opacity"
|
||||||
|
onclick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const next = new Set(selectedCardIds);
|
||||||
|
if (next.has(card.id)) next.delete(card.id);
|
||||||
|
else next.add(card.id);
|
||||||
|
selectedCardIds = next;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="w-5 h-5 rounded border-2 flex items-center justify-center cursor-pointer {selectedCardIds.has(card.id) ? 'bg-[var(--color-primary)] border-[var(--color-primary)]' : 'border-gray-300 dark:border-gray-500 bg-white dark:bg-gray-700 hover:border-[var(--color-primary)]'} transition">
|
||||||
|
{#if selectedCardIds.has(card.id)}
|
||||||
|
<svg class="w-3 h-3 text-white" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if card.labels && card.labels.length > 0}
|
{#if card.labels && card.labels.length > 0}
|
||||||
<div class="flex flex-wrap gap-1 mb-1.5">
|
<div class="flex flex-wrap gap-1 mb-1.5">
|
||||||
{#each card.labels as label}
|
{#each card.labels as label}
|
||||||
@@ -722,7 +731,7 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -863,13 +872,10 @@
|
|||||||
{selectedCardIds}
|
{selectedCardIds}
|
||||||
{columns}
|
{columns}
|
||||||
onaction={() => {
|
onaction={() => {
|
||||||
selectMode = false;
|
|
||||||
selectedCardIds = new Set();
|
selectedCardIds = new Set();
|
||||||
// Reload page data
|
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}}
|
}}
|
||||||
oncancel={() => {
|
oncancel={() => {
|
||||||
selectMode = false;
|
|
||||||
selectedCardIds = new Set();
|
selectedCardIds = new Set();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user