Compare commits

..

2 Commits

+63 -62
View File
@@ -13,25 +13,21 @@ $isAdmin = ($userRole === 'ADMIN');
?>
<style>
/* Volledige breedte benutting en soepele schermmaximalisatie */
#boardMainWrapper {
width: 100% !important;
max-width: 100% !important;
/* Soepele overgang voor de lanes container bij maximaliseren */
#lanesSectionWrapper {
transition: all 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
#boardMainWrapper.is-maximized {
padding-left: 0 !important;
padding-right: 0 !important;
}
#boardMainWrapper #boardLanesContainer {
#lanesSectionWrapper.is-maximized {
max-width: 100% !important;
width: 100% !important;
}
</style>
<div id="boardMainWrapper" class="space-y-4 w-full max-w-none">
<div id="boardPageContainer" class="space-y-4 w-full">
<!-- Bovenbalk: Bord Titel, Filters & Actieknoppen -->
<div class="fociz-card p-4 sm:p-5">
<!-- Bovenbalk: Bord Titel, Filters & Actieknoppen (ALTIJD vaste standaard breedte) -->
<div class="max-w-7xl mx-auto w-full">
<div class="fociz-card p-4 sm:p-5">
<div class="flex flex-col xl:flex-row xl:items-center justify-between gap-4">
<!-- Linkerkant: Bordkiezer & Titel -->
@@ -120,26 +116,32 @@ $isAdmin = ($userRole === 'ADMIN');
</div>
</div>
</div>
<!-- Strook direct boven de lane blokken: klein maximaliseer-icoon rechts -->
<div class="flex items-center justify-between px-1 -mb-1">
<div class="text-[11px] font-semibold text-slate-500 dark:text-slate-400" id="boardLanesSummary"></div>
<button
id="btnToggleMaximize"
onclick="toggleBoardMaximize()"
title="Bord maximaliseren naar volledige vensterbreedte"
class="w-7 h-7 rounded-lg bg-white dark:bg-[#111624] hover:bg-slate-100 dark:hover:bg-slate-800 border border-slate-200 dark:border-slate-800 text-slate-600 dark:text-slate-300 flex items-center justify-center transition cursor-pointer shadow-2xs hover:scale-105 active:scale-95 ml-auto"
>
<i id="maximizeIcon" data-lucide="maximize-2" class="w-3.5 h-3.5"></i>
</button>
</div>
<!-- Kanban Board Container (Horizontaal scrollbaar indien te smal, past automatisch in de breedte) -->
<div id="boardLanesContainer" class="flex gap-4 overflow-x-auto pb-8 pt-1 min-h-[650px] items-start select-none w-full transition-all duration-300">
<div class="flex items-center justify-center w-full py-20 text-slate-400 text-sm">
<i data-lucide="loader-2" class="w-5 h-5 animate-spin mr-2"></i>
<span>Bord laden...</span>
<!-- Lanes Sectie: Wisselt tussen standaard gecentreerde breedte (max-w-7xl) en volledig scherm (max-w-none w-full) -->
<div id="lanesSectionWrapper" class="max-w-7xl mx-auto w-full transition-all duration-300">
<!-- Strook direct boven de lane blokken: klein maximaliseer-icoon rechts -->
<div class="flex items-center justify-between px-1 mb-2">
<div class="text-[11px] font-semibold text-slate-500 dark:text-slate-400" id="boardLanesSummary"></div>
<button
id="btnToggleMaximize"
onclick="toggleBoardMaximize()"
title="Kolommen maximaliseren naar volledige vensterbreedte"
class="w-7 h-7 rounded-lg bg-white dark:bg-[#111624] hover:bg-slate-100 dark:hover:bg-slate-800 border border-slate-200 dark:border-slate-800 text-slate-600 dark:text-slate-300 flex items-center justify-center transition cursor-pointer shadow-2xs hover:scale-105 active:scale-95 ml-auto"
>
<i id="maximizeIcon" data-lucide="maximize-2" class="w-3.5 h-3.5"></i>
</button>
</div>
<!-- Kanban Board Container (past zich in standaardmodus soepel aan zonder scrollbalk) -->
<div id="boardLanesContainer" class="flex gap-3 overflow-x-auto pb-2 pt-1 min-h-[440px] items-start select-none w-full transition-all duration-300">
<div class="flex items-center justify-center w-full py-20 text-slate-400 text-sm">
<i data-lucide="loader-2" class="w-5 h-5 animate-spin mr-2"></i>
<span>Bord laden...</span>
</div>
</div>
</div>
</div>
@@ -635,9 +637,9 @@ function renderCards() {
const dotColorClass = LANE_ACCENT_COLORS[lane.color] || 'bg-slate-500';
// Lane kolom HTML (past zich automatisch aan de schermbreedte aan)
// Lane kolom HTML: flex-1 en min-w-[160px] zodat 5+ lanes in standaardmodus binnen 1280px passen zonder scrollbalk
const laneEl = document.createElement('div');
laneEl.className = 'flex-1 min-w-[260px] rounded-2xl bg-slate-100/70 dark:bg-[#0c0f17]/70 border border-slate-200/80 dark:border-slate-800/80 p-3.5 flex flex-col shadow-xs max-h-[82vh] transition-all duration-200';
laneEl.className = 'flex-1 min-w-0 sm:min-w-[160px] rounded-2xl bg-slate-100/70 dark:bg-[#0c0f17]/70 border border-slate-200/80 dark:border-slate-800/80 p-3 flex flex-col shadow-xs max-h-[calc(100vh-310px)] min-h-[440px] transition-all duration-200';
laneEl.setAttribute('data-lane-id', lane.id);
let cardsHtml = '';
@@ -695,16 +697,16 @@ function renderCards() {
ondragstart="onCardDragStart(event, ${card.id})"
ondragend="onCardDragEnd(event)"
onclick="onCardClick(event, ${card.id})"
class="group/card relative p-3.5 rounded-xl border ${colorClass} shadow-2xs hover:shadow-md hover:-translate-y-0.5 transition cursor-grab active:cursor-grabbing mb-2.5"
class="group/card relative p-3 rounded-xl border ${colorClass} shadow-2xs hover:shadow-md hover:-translate-y-0.5 transition cursor-grab active:cursor-grabbing mb-2.5"
>
<div class="flex items-start justify-between gap-2 mb-1.5">
<h4 class="text-xs font-bold leading-snug line-clamp-2">
<div class="flex items-start justify-between gap-1.5 mb-1.5">
<h4 class="text-xs font-bold leading-snug line-clamp-2 break-words">
${escapeHtml(card.title)}
</h4>
${priorityBadge}
<div class="flex-shrink-0">${priorityBadge}</div>
</div>
${card.description ? `<p class="text-[11px] opacity-80 line-clamp-2 leading-relaxed mb-2.5">${escapeHtml(card.description)}</p>` : ''}
${card.description ? `<p class="text-[11px] opacity-80 line-clamp-2 leading-relaxed mb-2.5 break-words">${escapeHtml(card.description)}</p>` : ''}
<div class="flex items-center justify-between mt-auto">
${assigneeHtml}
@@ -725,14 +727,14 @@ function renderCards() {
laneEl.innerHTML = `
<!-- Lane Header -->
<div class="flex items-center justify-between pb-3 mb-3 border-b border-slate-200/80 dark:border-slate-800/80">
<div class="flex items-center space-x-2">
<span class="w-2.5 h-2.5 rounded-full ${dotColorClass}"></span>
<h3 class="text-xs font-bold text-slate-800 dark:text-slate-200 uppercase tracking-wider">
<div class="flex items-center justify-between pb-2.5 mb-2.5 border-b border-slate-200/80 dark:border-slate-800/80">
<div class="flex items-center space-x-2 min-w-0">
<span class="w-2.5 h-2.5 rounded-full ${dotColorClass} flex-shrink-0"></span>
<h3 class="text-xs font-bold text-slate-800 dark:text-slate-200 uppercase tracking-wider truncate">
${escapeHtml(lane.title)}
</h3>
</div>
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-white dark:bg-slate-800 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-700 shadow-2xs">
<span class="px-2 py-0.5 rounded-full text-[10px] font-bold bg-white dark:bg-slate-800 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-700 shadow-2xs flex-shrink-0 ml-1">
${cards.length}
</span>
</div>
@@ -1206,40 +1208,39 @@ function escapeHtml(str) {
.replace(/'/g, '&#039;');
}
// 10. Bord Maximaliseren & Verkleinen (Soepele breedte-overgang)
// 10. Kolommen Maximaliseren & Verkleinen (Soepele breedte-overgang)
// De site-header blijft ALTIJD staan.
// De bovenbalk (Hoofdbord, filters, actieknoppen) behoudt altijd de vaste standaard breedte.
// ALLEEN de aparte lanes wisselen tussen standaard gecentreerde breedte en de volledige schermbreedte.
let isBoardMaximized = localStorage.getItem('fociz_board_maximized') === 'true';
function applyMaximizeState(isMax) {
const wrapper = document.getElementById('boardMainWrapper');
const lanesWrapper = document.getElementById('lanesSectionWrapper');
const mainContainer = document.getElementById('focizMainContainer');
const icon = document.getElementById('maximizeIcon');
const btn = document.getElementById('btnToggleMaximize');
if (!wrapper || !btn) return;
if (!lanesWrapper || !btn) return;
// Zorg dat header altijd zichtbaar blijft
document.querySelector('header')?.classList.remove('hidden');
if (mainContainer) {
mainContainer.style.maxWidth = '';
mainContainer.style.paddingLeft = '';
mainContainer.style.paddingRight = '';
}
if (isMax) {
wrapper.classList.add('is-maximized');
if (mainContainer) {
mainContainer.style.maxWidth = '100vw';
mainContainer.style.width = '100%';
mainContainer.style.paddingLeft = '0.5rem';
mainContainer.style.paddingRight = '0.5rem';
}
document.querySelector('header')?.classList.add('hidden');
btn.setAttribute('title', 'Bord verkleinen / navigatie tonen (Escape)');
lanesWrapper.classList.remove('max-w-7xl', 'mx-auto');
lanesWrapper.classList.add('is-maximized', 'max-w-none', 'w-full', 'px-1', 'sm:px-3');
btn.setAttribute('title', 'Kolommen verkleinen naar standaard breedte (Escape)');
if (icon) {
icon.setAttribute('data-lucide', 'minimize-2');
}
} else {
wrapper.classList.remove('is-maximized');
if (mainContainer) {
mainContainer.style.maxWidth = '';
mainContainer.style.width = '';
mainContainer.style.paddingLeft = '';
mainContainer.style.paddingRight = '';
}
document.querySelector('header')?.classList.remove('hidden');
btn.setAttribute('title', 'Bord maximaliseren (volledig venster)');
lanesWrapper.classList.remove('is-maximized', 'max-w-none', 'px-1', 'sm:px-3');
lanesWrapper.classList.add('max-w-7xl', 'mx-auto', 'w-full');
btn.setAttribute('title', 'Kolommen maximaliseren naar volledige vensterbreedte');
if (icon) {
icon.setAttribute('data-lucide', 'maximize-2');
}