Ai aanpassingen en slepen in planner blokken

This commit is contained in:
2026-09-12 14:24:24 +02:00
parent 797aaa76c7
commit 5e35f5152d
7 changed files with 545 additions and 31 deletions
+144 -18
View File
@@ -121,33 +121,45 @@ $categories = [
<?php foreach ($categories as $catKey => $catConfig):
$catCards = array_filter($cards, fn($c) => $c['category'] === $catKey);
?>
<div class="fociz-card p-4 flex flex-col min-h-[500px]">
<div class="fociz-card p-4 flex flex-col min-h-[500px] transition-all duration-200">
<!-- Column Header -->
<div class="flex items-center justify-between pb-3 mb-3 border-b border-slate-100 dark:border-slate-800">
<div class="flex items-center space-x-2">
<i data-lucide="<?= $catConfig['icon'] ?>" class="w-4 h-4 text-<?= $catConfig['color'] ?>-500"></i>
<h3 class="text-xs font-bold text-slate-900 dark:text-white uppercase tracking-wider"><?= $catConfig['title'] ?></h3>
</div>
<span class="text-xs font-mono font-bold px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-700">
<span id="badge-count-<?= htmlspecialchars(md5($catKey)) ?>" class="text-xs font-mono font-bold px-2 py-0.5 rounded-full bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 border border-slate-200 dark:border-slate-700">
<?= count($catCards) ?>
</span>
</div>
<!-- Cards Container -->
<div class="flex-1 space-y-3">
<!-- Cards Container as Drop Zone -->
<div
class="brainstorm-lane flex-1 space-y-3 min-h-[140px] rounded-xl p-1.5 transition-all duration-150"
data-category="<?= htmlspecialchars($catKey, ENT_QUOTES) ?>"
ondragover="handleCanvasLaneDragOver(event)"
ondragleave="handleCanvasLaneDragLeave(event)"
ondrop="handleCanvasLaneDrop(event, '<?= htmlspecialchars($catKey, ENT_QUOTES) ?>')"
>
<?php if (empty($catCards)): ?>
<div class="py-8 text-center text-slate-400 dark:text-slate-600 text-xs font-medium">
<div class="lane-empty-placeholder py-8 text-center text-slate-400 dark:text-slate-600 text-xs font-medium pointer-events-none">
Nog geen kaarten in deze categorie.
</div>
<?php else: ?>
<?php foreach ($catCards as $card): ?>
<div class="group relative rounded-xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-2xs transition hover:-translate-y-0.5" id="card-<?= $card['id'] ?>">
<div
id="card-<?= $card['id'] ?>"
draggable="true"
ondragstart="handleCanvasCardDragStart(event, <?= $card['id'] ?>)"
ondragend="handleCanvasCardDragEnd(event)"
class="brainstorm-card group relative rounded-2xl p-4 border <?= $catConfig['border'] ?> <?= $catConfig['bg'] ?> backdrop-blur-sm shadow-sm hover:shadow-md transition-all duration-150 cursor-grab active:cursor-grabbing hover:-translate-y-0.5 flex flex-col justify-between"
>
<!-- Top: Checkbox voor selectie + Roadmap badge -->
<div class="flex items-center justify-between mb-2">
<label class="flex items-center space-x-2 cursor-pointer">
<div class="flex items-center justify-between gap-2 mb-2.5">
<label class="inline-flex items-center space-x-2 cursor-pointer select-none">
<input type="checkbox" value="<?= $card['id'] ?>" data-content="<?= htmlspecialchars($card['content'], ENT_QUOTES) ?>" class="card-checkbox w-4 h-4 rounded bg-white dark:bg-slate-900 border-slate-300 dark:border-slate-700 text-indigo-600 focus:ring-0">
<span class="text-[10px] text-slate-500 dark:text-slate-400 font-medium">Selecteer</span>
<span class="text-[11px] text-slate-500 dark:text-slate-400 font-medium">Selecteer</span>
</label>
<?php if (!empty($card['converted_to_roadmap_item_id'])): ?>
@@ -158,24 +170,26 @@ $categories = [
<?php endif; ?>
</div>
<!-- Inhoud -->
<p class="text-xs text-slate-800 dark:text-slate-200 leading-relaxed whitespace-pre-wrap font-medium">
<?= htmlspecialchars($card['content']) ?>
</p>
<!-- Inhoud Post-it met verfijnde typografie en uitlijning -->
<div class="text-left py-1">
<p class="text-xs text-slate-800 dark:text-slate-100 font-medium leading-relaxed whitespace-pre-wrap break-words text-left">
<?= htmlspecialchars($card['content']) ?>
</p>
</div>
<!-- Footer van kaart -->
<div class="mt-3 pt-2.5 border-t border-slate-200/60 dark:border-slate-800/60 flex items-center justify-between text-[10px] text-slate-500 dark:text-slate-400">
<div class="flex items-center space-x-1.5">
<span><?= htmlspecialchars($card['author_name'] ?? 'Collega') ?></span>
<div class="flex items-center space-x-1.5 min-w-0">
<span class="truncate font-semibold text-slate-700 dark:text-slate-300"><?= htmlspecialchars($card['author_name'] ?? 'Collega') ?></span>
<?php if ($aiSettings['ai_enabled'] && $aiSettings['has_key']): ?>
<button onclick="openAiBreakdownModal(<?= $card['id'] ?>, <?= htmlspecialchars(json_encode($card['content']), ENT_QUOTES) ?>)" class="inline-flex items-center space-x-1 px-2 py-0.5 rounded-lg bg-violet-100/90 hover:bg-violet-200 dark:bg-violet-950/60 dark:hover:bg-violet-900/60 text-violet-700 dark:text-violet-300 font-bold text-[10px] transition cursor-pointer border border-violet-200/80 dark:border-violet-800/60 shadow-2xs" title="Splits dit idee uit naar behapbare taken via Google Gemini Pro">
<button onclick="openAiBreakdownModal(<?= $card['id'] ?>, <?= htmlspecialchars(json_encode($card['content']), ENT_QUOTES) ?>)" class="inline-flex items-center space-x-1 px-2 py-0.5 rounded-lg bg-violet-100/90 hover:bg-violet-200 dark:bg-violet-950/60 dark:hover:bg-violet-900/60 text-violet-700 dark:text-violet-300 font-bold text-[10px] transition cursor-pointer border border-violet-200/80 dark:border-violet-800/60 shadow-2xs flex-shrink-0" title="Splits dit idee uit naar behapbare taken via Google Gemini Pro">
<i data-lucide="sparkles" class="w-3 h-3 text-violet-500"></i>
<span>Werk uit met AI</span>
<span>AI</span>
</button>
<?php endif; ?>
</div>
<div class="flex items-center space-x-2">
<div class="flex items-center space-x-1.5 flex-shrink-0">
<!-- Upvote button -->
<button onclick="voteCard(<?= $card['id'] ?>)" class="flex items-center space-x-1 px-2 py-1 rounded-lg bg-white/80 hover:bg-white dark:bg-slate-800/80 dark:hover:bg-slate-700 text-slate-600 dark:text-slate-300 hover:text-amber-500 dark:hover:text-amber-400 border border-slate-200/80 dark:border-transparent transition shadow-xs cursor-pointer">
<i data-lucide="thumbs-up" class="w-3 h-3"></i>
@@ -550,6 +564,118 @@ async function deleteCard(cardId) {
document.getElementById(`card-${cardId}`)?.remove();
}
// --- Drag & Drop tussen Brainstorm Categorie Lanes ---
let draggedCanvasCardId = null;
function handleCanvasCardDragStart(e, cardId) {
draggedCanvasCardId = cardId;
try {
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/plain', String(cardId));
} catch (err) {}
setTimeout(() => {
const el = document.getElementById(`card-${cardId}`);
if (el) {
el.classList.add('opacity-40', 'scale-[0.98]');
}
}, 0);
}
function handleCanvasCardDragEnd(e) {
if (draggedCanvasCardId) {
const el = document.getElementById(`card-${draggedCanvasCardId}`);
if (el) {
el.classList.remove('opacity-40', 'scale-[0.98]');
}
draggedCanvasCardId = null;
}
document.querySelectorAll('.brainstorm-lane').forEach(lane => {
lane.classList.remove('bg-indigo-50/80', 'dark:bg-indigo-950/40', 'ring-2', 'ring-indigo-400', 'dark:ring-indigo-500', 'ring-inset');
});
}
function handleCanvasLaneDragOver(e) {
if (!draggedCanvasCardId) return;
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
const lane = e.currentTarget;
if (lane && !lane.classList.contains('ring-2')) {
lane.classList.add('bg-indigo-50/80', 'dark:bg-indigo-950/40', 'ring-2', 'ring-indigo-400', 'dark:ring-indigo-500', 'ring-inset');
}
}
function handleCanvasLaneDragLeave(e) {
const lane = e.currentTarget;
if (lane && !lane.contains(e.relatedTarget)) {
lane.classList.remove('bg-indigo-50/80', 'dark:bg-indigo-950/40', 'ring-2', 'ring-indigo-400', 'dark:ring-indigo-500', 'ring-inset');
}
}
async function handleCanvasLaneDrop(e, targetCategory) {
e.preventDefault();
const lane = e.currentTarget;
if (lane) {
lane.classList.remove('bg-indigo-50/80', 'dark:bg-indigo-950/40', 'ring-2', 'ring-indigo-400', 'dark:ring-indigo-500', 'ring-inset');
}
const cardId = draggedCanvasCardId || parseInt(e.dataTransfer.getData('text/plain'), 10);
draggedCanvasCardId = null;
if (!cardId || !targetCategory) return;
const cardEl = document.getElementById(`card-${cardId}`);
if (!cardEl) return;
const sourceLane = cardEl.closest('.brainstorm-lane');
const sourceCategory = sourceLane ? sourceLane.getAttribute('data-category') : null;
// Als de kaart al in deze categorie zit, doe niets
if (sourceCategory === targetCategory) return;
// Verplaats DOM element direct voor een directe, vloeiende UX
lane.appendChild(cardEl);
const placeholder = lane.querySelector('.lane-empty-placeholder');
if (placeholder) placeholder.remove();
// Kleurstijlen per categorie bijwerken
const categoryStyles = {
'Ideeën': { border: 'border-amber-200/80', darkBorder: 'dark:border-amber-800/40', bg: 'bg-amber-50/60', darkBg: 'dark:bg-amber-950/20' },
'Knelpunten': { border: 'border-rose-200/80', darkBorder: 'dark:border-rose-800/40', bg: 'bg-rose-50/60', darkBg: 'dark:bg-rose-950/20' },
'Oplossingen': { border: 'border-teal-200/80', darkBorder: 'dark:border-teal-800/40', bg: 'bg-teal-50/60', darkBg: 'dark:bg-teal-950/20' },
'Quick Wins': { border: 'border-indigo-200/80', darkBorder: 'dark:border-indigo-800/40', bg: 'bg-indigo-50/60', darkBg: 'dark:bg-indigo-950/20' }
};
// Verwijder oude kleurklassen en voeg nieuwe toe
Object.values(categoryStyles).forEach(st => {
cardEl.classList.remove(st.border, st.darkBorder, st.bg, st.darkBg);
});
const targetStyle = categoryStyles[targetCategory] || categoryStyles['Ideeën'];
cardEl.classList.add(targetStyle.border, targetStyle.darkBorder, targetStyle.bg, targetStyle.darkBg);
// Stuur POST naar backend om categorie en kleur te bewaren
try {
const res = await fetch('/api/brainstorm.php?action=move_card', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
card_id: cardId,
category: targetCategory
})
});
const data = await res.json();
if (!data.success) {
alert(data.error || 'Kon kaart niet verplaatsen');
location.reload();
}
} catch (err) {
console.error('Fout bij verplaatsen brainstormkaart:', err);
alert('Netwerkfout bij verplaatsen');
location.reload();
}
}
// --- Roadmap Conversie Logica ---
function getSelectedCardIds() {
const checkboxes = document.querySelectorAll('.card-checkbox:checked');