feat: add dev tools page and update sidebar toggle and team mood dashboard UI

This commit is contained in:
root
2026-03-29 15:04:44 +07:00
parent 2a670d80d1
commit f4f842d658
6 changed files with 201 additions and 39 deletions

View File

@@ -91,6 +91,14 @@ if($_SERVER['REQUEST_METHOD'] === 'POST') {
else notify_group($parts[1], $msg);
}
}
if(isset($_POST['remove_note_share'])) {
$share_id = (int)$_POST['share_id'];
$chk = query("SELECT ns.id FROM note_shares ns JOIN notes n ON ns.note_id=n.id WHERE ns.id=? AND n.owner_id=?", [$share_id, $user_id])->fetch();
if($chk) {
$pdo->prepare("DELETE FROM note_shares WHERE id=?")->execute([$share_id]);
}
}
}
// ── Fetch Notes ───────────────────────────────────────────────────────────────
@@ -287,7 +295,8 @@ $note_colors = [
<!-- Share section (only for owner) -->
<div id="edit-share-section" style="border-top:1px solid var(--border); padding-top:0.75rem; margin-top:0.5rem;">
<label style="font-size:0.8rem; color:var(--text-light); margin-bottom:0.4rem; display:block;">Share this note</label>
<label style="font-size:0.8rem; color:var(--text-light); margin-bottom:0.4rem; display:block;">Shared with</label>
<div id="note-shares-list" style="display:flex; flex-wrap:wrap; gap:0.35rem; margin-bottom:0.75rem;"></div>
<div style="display:flex; gap:0.5rem; flex-wrap:wrap;">
<select name="share_target" id="edit-share-target" class="form-control" style="flex:1; min-width:150px; padding:0.4rem;">
<?php foreach($all_users as $u): ?>
@@ -327,6 +336,11 @@ $note_colors = [
<input type="hidden" name="share_target" id="share-note-standalone-target">
</form>
<form method="POST" id="remove-note-share-form" style="display:none;">
<input type="hidden" name="remove_note_share" value="1">
<input type="hidden" name="share_id" id="remove-note-share-id">
</form>
<!-- Markdown Libs -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
@@ -343,6 +357,11 @@ $note_colors = [
$bg = $n['color'] ?: 'var(--surface)';
$preview = strip_tags(isset($n['content']) ? (function_exists('marked') ? $n['content'] : $n['content']) : '');
$preview = mb_substr($preview, 0, 120) . (mb_strlen($preview) > 120 ? '...' : '');
$note_shares = [];
if($n['is_mine']) {
$note_shares = query("SELECT ns.id, ns.share_type, ns.share_id, u.username, g.name as gname FROM note_shares ns LEFT JOIN users u ON (ns.share_type='user' AND ns.share_id=u.id) LEFT JOIN groups g ON (ns.share_type='group' AND ns.share_id=g.id) WHERE ns.note_id=?", [$n['id']])->fetchAll();
}
$shares_json = htmlspecialchars(json_encode($note_shares), ENT_QUOTES, 'UTF-8');
?>
<div class="note-card note-filter-item"
style="background:<?= htmlspecialchars($bg) ?>;"
@@ -353,6 +372,7 @@ $note_colors = [
data-label-raw="<?= htmlspecialchars(trim((string)($n['label_name'] ?? ''))) ?>"
data-color="<?= htmlspecialchars((string)$n['color']) ?>"
data-image="<?= htmlspecialchars((string)($n['image_path'] ?? '')) ?>"
data-shares="<?= $shares_json ?>"
data-mine="<?= $n['is_mine'] ?>"
onclick="openNote(this)">
<?php if($n['image_path'] && file_exists($n['image_path'])): ?>
@@ -479,6 +499,9 @@ function openNote(card) {
// Share section
document.getElementById('edit-share-section').style.display = isMine ? 'block' : 'none';
if(isMine) {
renderNoteShares(card.dataset.shares || '[]');
}
// Wire up share button
const shareBtn = document.querySelector('#edit-note-form button[name="share_note"]');
@@ -495,6 +518,35 @@ function openNote(card) {
document.getElementById('edit-note-modal').classList.add('active');
}
function renderNoteShares(jsonShares) {
const list = document.getElementById('note-shares-list');
list.innerHTML = '';
let shares = [];
try { shares = JSON.parse(jsonShares || '[]'); } catch(e) { shares = []; }
if(shares.length === 0) return;
shares.forEach(sh => {
const label = sh.share_type === 'user' ? ('👤 ' + (sh.username || 'User')) : ('👥 ' + (sh.gname || 'Group'));
const chip = document.createElement('div');
chip.style.display = 'inline-flex';
chip.style.alignItems = 'center';
chip.style.gap = '0.35rem';
chip.style.fontSize = '0.72rem';
chip.style.padding = '3px 7px';
chip.style.borderRadius = '999px';
chip.style.background = 'rgba(var(--primary-rgb),0.12)';
chip.style.color = 'var(--primary)';
chip.innerHTML = `<span>${label}</span><button type="button" style="border:none;background:transparent;color:inherit;cursor:pointer;line-height:1;" title="Unshare" onclick="removeNoteShare(${Number(sh.id)})">×</button>`;
list.appendChild(chip);
});
}
function removeNoteShare(shareId) {
if(!shareId) return;
if(!confirm('Unshare this note access?')) return;
document.getElementById('remove-note-share-id').value = String(shareId);
document.getElementById('remove-note-share-form').submit();
}
function filterNotes() {
const q = (document.getElementById('notes-search-input')?.value || '').toLowerCase().trim();
const lbl = (document.getElementById('notes-label-filter')?.value || '').trim();