Private
Public Access
1
0

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:
Catherine Renelle
2026-02-27 10:58:46 -05:00
parent 8c41b33313
commit 986c88143a
+30 -24
View File
@@ -10,7 +10,6 @@
import CardModal from '$lib/components/CardModal.svelte';
import ActivityFeed from '$lib/components/ActivityFeed.svelte';
import BoardFilters from '$lib/components/BoardFilters.svelte';
import BoardBackgroundPicker from '$lib/components/BoardBackgroundPicker.svelte';
import BulkToolbar from '$lib/components/BulkToolbar.svelte';
import ColumnSortMenu from '$lib/components/ColumnSortMenu.svelte';
import Avatar from '$lib/components/Avatar.svelte';
@@ -38,8 +37,8 @@
let showArchivedCards = $state(false);
let archivedCards = $state<any[]>([]);
let activeFilters = $state<FilterState>({ labelIds: [], assigneeIds: [], due: null });
let selectMode = $state(false);
let selectedCardIds = $state(new Set<string>());
let selectMode = $derived(selectedCardIds.size > 0);
let columnSorts = $state<Record<string, string | null>>({});
const flipDurationMs = 200;
@@ -488,21 +487,6 @@
</div>
{/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
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"
@@ -554,7 +538,7 @@
</div>
<!-- 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 -->
<div class="flex-1 overflow-x-auto p-4">
<div
@@ -644,8 +628,8 @@
{#each visibleCards as card (card.id)}
{@const progress = getChecklistProgress(card)}
{@const dueUrgency = getDueUrgency(card.dueDate)}
<button
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)]' : ''}"
<div
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);"
animate:flip={{ duration: flipDurationMs }}
onclick={() => {
@@ -658,7 +642,32 @@
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}
<div class="flex flex-wrap gap-1 mb-1.5">
{#each card.labels as label}
@@ -722,7 +731,7 @@
{/if}
</div>
{/if}
</button>
</div>
{/each}
</div>
@@ -863,13 +872,10 @@
{selectedCardIds}
{columns}
onaction={() => {
selectMode = false;
selectedCardIds = new Set();
// Reload page data
window.location.reload();
}}
oncancel={() => {
selectMode = false;
selectedCardIds = new Set();
}}
/>