exec("ALTER TABLE notes ADD COLUMN color TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE notes ADD COLUMN image_path TEXT DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("ALTER TABLE notes ADD COLUMN updated_at DATETIME DEFAULT NULL"); } catch(Exception $e) {} try { $pdo->exec("CREATE TABLE IF NOT EXISTS notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, content TEXT, owner_id INTEGER, color TEXT DEFAULT NULL, image_path TEXT DEFAULT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT NULL, FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE CASCADE )"); } catch(Exception $e) {} try { $pdo->exec("CREATE TABLE IF NOT EXISTS note_shares ( id INTEGER PRIMARY KEY AUTOINCREMENT, note_id INTEGER, share_type TEXT, share_id INTEGER, FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE )"); } catch(Exception $e) {} // ── Handle POST ─────────────────────────────────────────────────────────────── if($_SERVER['REQUEST_METHOD'] === 'POST') { if(isset($_POST['create_note'])) { $image_path = null; if(isset($_FILES['note_image']) && $_FILES['note_image']['error'] === 0) { $allowed = ['image/jpeg','image/png','image/gif','image/webp']; if(in_array($_FILES['note_image']['type'], $allowed)) { $ext = pathinfo($_FILES['note_image']['name'], PATHINFO_EXTENSION); $fname = 'note_' . $user_id . '_' . time() . '.' . $ext; $dest = 'uploads/' . $fname; if(move_uploaded_file($_FILES['note_image']['tmp_name'], $dest)) $image_path = $dest; } } $stmt = $pdo->prepare("INSERT INTO notes (title, content, owner_id, color, image_path) VALUES (?, ?, ?, ?, ?)"); $stmt->execute([$_POST['title'] ?? 'Untitled', $_POST['content'], $user_id, $_POST['color'] ?? null, $image_path]); } if(isset($_POST['update_note'])) { $n = query("SELECT owner_id, image_path FROM notes WHERE id=?", [$_POST['note_id']])->fetch(); if($n && $n['owner_id'] == $user_id) { $image_path = $n['image_path']; if(isset($_FILES['note_image']) && $_FILES['note_image']['error'] === 0) { $allowed = ['image/jpeg','image/png','image/gif','image/webp']; if(in_array($_FILES['note_image']['type'], $allowed)) { $ext = pathinfo($_FILES['note_image']['name'], PATHINFO_EXTENSION); $fname = 'note_' . $user_id . '_' . time() . '.' . $ext; $dest = 'uploads/' . $fname; if(move_uploaded_file($_FILES['note_image']['tmp_name'], $dest)) { if($image_path && file_exists($image_path)) @unlink($image_path); $image_path = $dest; } } } if(isset($_POST['remove_image']) && $_POST['remove_image']) { if($image_path && file_exists($image_path)) @unlink($image_path); $image_path = null; } $stmt = $pdo->prepare("UPDATE notes SET title=?, content=?, color=?, image_path=?, updated_at=CURRENT_TIMESTAMP WHERE id=? AND owner_id=?"); $stmt->execute([$_POST['title'] ?? 'Untitled', $_POST['content'], $_POST['color'] ?? null, $image_path, $_POST['note_id'], $user_id]); } } if(isset($_POST['delete_note'])) { $n = query("SELECT owner_id, image_path FROM notes WHERE id=?", [$_POST['note_id']])->fetch(); if($n && $n['owner_id'] == $user_id) { if($n['image_path'] && file_exists($n['image_path'])) @unlink($n['image_path']); query("DELETE FROM notes WHERE id=? AND owner_id=?", [$_POST['note_id'], $user_id]); } } if(isset($_POST['share_note'])) { $n_id = $_POST['note_id']; $share = $_POST['share_target']; $parts = explode('_', $share, 2); if(count($parts)===2) { $stmt = $pdo->prepare("INSERT INTO note_shares (note_id, share_type, share_id) VALUES (?, ?, ?)"); $stmt->execute([$n_id, $parts[0], $parts[1]]); $n = query("SELECT title FROM notes WHERE id=?", [$n_id])->fetch(); $msg = "A note '{$n['title']}' has been shared with you."; if($parts[0] === 'user') notify_user($parts[1], $msg); else notify_group($parts[1], $msg); } } } // ── Fetch Notes ─────────────────────────────────────────────────────────────── $user_groups = get_user_groups($user_id); $my_group_ids = array_column($user_groups, 'id'); $group_in = implode(',', array_fill(0, count($my_group_ids), '?')) ?: '0'; $sql = "SELECT n.*, (n.owner_id = ?) as is_mine, u.username as owner_name FROM notes n LEFT JOIN note_shares ns ON n.id = ns.note_id LEFT JOIN users u ON n.owner_id = u.id WHERE n.owner_id = ? OR (ns.share_type='user' AND ns.share_id = ?) OR (ns.share_type='group' AND ns.share_id IN ($group_in)) GROUP BY n.id ORDER BY n.updated_at DESC, n.created_at DESC"; $params = array_merge([$user_id, $user_id, $user_id], $my_group_ids); $stmt = $pdo->prepare($sql); $stmt->execute($params); $notes = $stmt->fetchAll(); $all_users = query("SELECT id, username FROM users WHERE id != ?", [$user_id])->fetchAll(); $all_groups = query("SELECT * FROM groups")->fetchAll(); // Define note colors $note_colors = [ null => ['bg'=>'var(--surface)', 'label'=>'Default'], '#fff9c4' => ['bg'=>'#fff9c4', 'label'=>'Yellow'], '#d4edda' => ['bg'=>'#d4edda', 'label'=>'Green'], '#cce5ff' => ['bg'=>'#cce5ff', 'label'=>'Blue'], '#f8d7da' => ['bg'=>'#f8d7da', 'label'=>'Pink'], '#e2d9f3' => ['bg'=>'#e2d9f3', 'label'=>'Purple'], '#fde8d8' => ['bg'=>'#fde8d8', 'label'=>'Orange'], '#f5f5f5' => ['bg'=>'#f5f5f5', 'label'=>'Gray'], ]; // dark mode color overrides handled via JS ?>

📝 Notes

📝

No notes yet

Click New Note to start writing something.

120 ? '...' : ''); ?>
Note image