From 2642f97c8b192d9c40a94a140c05c2b45885393b Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 15 Feb 2026 10:25:49 +0000 Subject: [PATCH] v1 --- api_v1_messages.php | 35 ++++++ assets/css/discord.css | 213 ++++++++++++++++++++++++++++++++ assets/js/main.js | 55 +++++++++ database/schema.sql | 50 ++++++++ db_init.php | 10 ++ index.php | 274 ++++++++++++++++++++--------------------- 6 files changed, 496 insertions(+), 141 deletions(-) create mode 100644 api_v1_messages.php create mode 100644 assets/css/discord.css create mode 100644 assets/js/main.js create mode 100644 database/schema.sql create mode 100644 db_init.php diff --git a/api_v1_messages.php b/api_v1_messages.php new file mode 100644 index 0000000..c19c168 --- /dev/null +++ b/api_v1_messages.php @@ -0,0 +1,35 @@ + false, 'error' => 'Empty content']); + exit; +} + +try { + $stmt = db()->prepare("INSERT INTO messages (channel_id, user_id, content) VALUES (?, ?, ?)"); + $stmt->execute([$channel_id, $user_id, $content]); + $last_id = db()->lastInsertId(); + + // Fetch message with username for the response + $stmt = db()->prepare("SELECT m.*, u.username FROM messages m JOIN users u ON m.user_id = u.id WHERE m.id = ?"); + $stmt->execute([$last_id]); + $msg = $stmt->fetch(); + + echo json_encode([ + 'success' => true, + 'message' => [ + 'username' => $msg['username'], + 'content' => htmlspecialchars($msg['content']), + 'time' => date('H:i', strtotime($msg['created_at'])) + ] + ]); +} catch (Exception $e) { + echo json_encode(['success' => false, 'error' => $e->getMessage()]); +} diff --git a/assets/css/discord.css b/assets/css/discord.css new file mode 100644 index 0000000..2e91fd8 --- /dev/null +++ b/assets/css/discord.css @@ -0,0 +1,213 @@ +:root { + --bg-servers: #1e1f22; + --bg-channels: #2b2d31; + --bg-chat: #313338; + --bg-members: #2b2d31; + --text-primary: #dbdee1; + --text-muted: #949ba4; + --blurple: #5865f2; + --hover: #35373c; + --active: #3f4147; +} + +body { + margin: 0; + padding: 0; + font-family: 'Inter', system-ui, -apple-system, sans-serif; + background-color: var(--bg-servers); + color: var(--text-primary); + height: 100vh; + overflow: hidden; +} + +.discord-app { + display: flex; + height: 100vh; + width: 100vw; +} + +/* Servers Sidebar */ +.servers-sidebar { + width: 72px; + background-color: var(--bg-servers); + display: flex; + flex-direction: column; + align-items: center; + padding: 12px 0; + gap: 8px; + flex-shrink: 0; +} + +.server-icon { + width: 48px; + height: 48px; + background-color: var(--bg-chat); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s; + color: var(--text-primary); + text-decoration: none; + font-weight: bold; +} + +.server-icon:hover { + border-radius: 16px; + background-color: var(--blurple); +} + +.server-icon.active { + border-radius: 16px; + background-color: var(--blurple); +} + +/* Channels Sidebar */ +.channels-sidebar { + width: 240px; + background-color: var(--bg-channels); + display: flex; + flex-direction: column; + flex-shrink: 0; +} + +.channels-header { + height: 48px; + padding: 0 16px; + display: flex; + align-items: center; + box-shadow: 0 1px 0 rgba(0,0,0,0.2); + font-weight: bold; +} + +.channels-list { + flex: 1; + padding: 8px; + overflow-y: auto; +} + +.channel-item { + padding: 6px 8px; + border-radius: 4px; + cursor: pointer; + color: var(--text-muted); + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 2px; + text-decoration: none; +} + +.channel-item:hover { + background-color: var(--hover); + color: var(--text-primary); +} + +.channel-item.active { + background-color: var(--active); + color: var(--text-primary); +} + +.channel-item::before { + content: "#"; + font-size: 1.2em; + font-weight: 300; +} + +/* Chat Area */ +.chat-container { + flex: 1; + background-color: var(--bg-chat); + display: flex; + flex-direction: column; +} + +.chat-header { + height: 48px; + padding: 0 16px; + display: flex; + align-items: center; + box-shadow: 0 1px 0 rgba(0,0,0,0.2); + font-weight: bold; +} + +.messages-list { + flex: 1; + overflow-y: auto; + padding: 16px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.message-item { + display: flex; + gap: 16px; +} + +.message-avatar { + width: 40px; + height: 40px; + background-color: #4e5058; + border-radius: 50%; + flex-shrink: 0; +} + +.message-content { + flex: 1; +} + +.message-author { + font-weight: bold; + font-size: 0.95em; + margin-bottom: 4px; +} + +.message-text { + font-size: 0.95em; + line-height: 1.4; + color: #dbdee1; +} + +.message-time { + font-size: 0.75em; + color: var(--text-muted); + margin-left: 8px; + font-weight: normal; +} + +/* Input Area */ +.chat-input-container { + padding: 0 16px 24px 16px; +} + +.chat-input-wrapper { + background-color: #383a40; + border-radius: 8px; + padding: 11px 16px; + display: flex; +} + +.chat-input { + background: transparent; + border: none; + color: var(--text-primary); + width: 100%; + outline: none; + font-size: 1em; +} + +/* Members Sidebar */ +.members-sidebar { + width: 240px; + background-color: var(--bg-members); + padding: 24px 8px; + display: none; /* Hidden on mobile/small screens */ +} + +@media (min-width: 1024px) { + .members-sidebar { + display: block; + } +} diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..fba2c42 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,55 @@ +document.addEventListener('DOMContentLoaded', () => { + const chatForm = document.getElementById('chat-form'); + const chatInput = document.getElementById('chat-input'); + const messagesList = document.getElementById('messages-list'); + + // Scroll to bottom + messagesList.scrollTop = messagesList.scrollHeight; + + chatForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const content = chatInput.value.trim(); + if (!content) return; + + chatInput.value = ''; + + try { + const response = await fetch('api_v1_messages.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + content: content, + channel_id: new URLSearchParams(window.location.search).get('channel_id') || 1 + }) + }); + + const result = await response.json(); + if (result.success) { + appendMessage(result.message); + messagesList.scrollTop = messagesList.scrollHeight; + } else { + alert('Error: ' + result.error); + } + } catch (err) { + console.error('Failed to send message:', err); + } + }); + + function appendMessage(msg) { + const div = document.createElement('div'); + div.className = 'message-item'; + div.innerHTML = ` +
+
+
+ ${msg.username} + ${msg.time} +
+
+ ${msg.content.replace(/\n/g, '
')} +
+
+ `; + messagesList.appendChild(div); + } +}); diff --git a/database/schema.sql b/database/schema.sql new file mode 100644 index 0000000..359b2aa --- /dev/null +++ b/database/schema.sql @@ -0,0 +1,50 @@ +-- Initial schema for Discord-like app +CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(50) NOT NULL UNIQUE, + email VARCHAR(100) NOT NULL UNIQUE, + password_hash VARCHAR(255) NOT NULL, + avatar_url VARCHAR(255), + status VARCHAR(20) DEFAULT 'offline', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +CREATE TABLE IF NOT EXISTS servers ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(100) NOT NULL, + owner_id INT NOT NULL, + icon_url VARCHAR(255), + invite_code VARCHAR(10) UNIQUE, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (owner_id) REFERENCES users(id) +); + +CREATE TABLE IF NOT EXISTS channels ( + id INT AUTO_INCREMENT PRIMARY KEY, + server_id INT NOT NULL, + name VARCHAR(100) NOT NULL, + type ENUM('text', 'voice') DEFAULT 'text', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE +); + +CREATE TABLE IF NOT EXISTS messages ( + id INT AUTO_INCREMENT PRIMARY KEY, + channel_id INT NOT NULL, + user_id INT NOT NULL, + content TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (channel_id) REFERENCES channels(id) ON DELETE CASCADE, + FOREIGN KEY (user_id) REFERENCES users(id) +); + +-- Seed initial data +INSERT IGNORE INTO users (id, username, email, password_hash, status) VALUES +(1, 'System', 'system@local', '$2y$10$xyz', 'online'); + +INSERT IGNORE INTO servers (id, name, owner_id, invite_code) VALUES +(1, 'General Community', 1, 'GEN-123'); + +INSERT IGNORE INTO channels (id, server_id, name) VALUES +(1, 1, 'general'), +(2, 1, 'random'); diff --git a/db_init.php b/db_init.php new file mode 100644 index 0000000..9522d8a --- /dev/null +++ b/db_init.php @@ -0,0 +1,10 @@ +exec($sql); + echo "Database initialized successfully.\n"; +} catch (Exception $e) { + echo "Error initializing database: " . $e->getMessage() . "\n"; +} diff --git a/index.php b/index.php index 7205f3d..91d35d7 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,142 @@ - - - - - - New Style -query("SELECT * FROM servers LIMIT 10")->fetchAll(); +$active_server_id = $_GET['server_id'] ?? ($servers[0]['id'] ?? 1); + +// Fetch channels +$stmt = db()->prepare("SELECT * FROM channels WHERE server_id = ?"); +$stmt->execute([$active_server_id]); +$channels = $stmt->fetchAll(); +$active_channel_id = $_GET['channel_id'] ?? ($channels[0]['id'] ?? 1); + +// Fetch messages +$stmt = db()->prepare(" + SELECT m.*, u.username, u.avatar_url + FROM messages m + JOIN users u ON m.user_id = u.id + WHERE m.channel_id = ? + ORDER BY m.created_at ASC + LIMIT 50 +"); +$stmt->execute([$active_channel_id]); +$messages = $stmt->fetchAll(); + +$current_channel_name = 'general'; +foreach($channels as $c) if($c['id'] == $active_channel_id) $current_channel_name = $c['name']; + +// SEO & Env tags +$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Discord-like messaging app built with PHP'; $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; ?> - - - - - - - - - - - - - - - - - - + + + + + + #<?php echo htmlspecialchars($current_channel_name); ?> | <?php echo htmlspecialchars($projectDescription); ?> + + + + + + + + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+ +
+ +
+ + + +
+ + + + +
-
- + + +
+
+ +
+
+
+ Text Channels +
+ + + + + +
+
+ + +
+
+ # + +
+
+ +
+

Welcome to #!

+

This is the start of the # channel.

+
+ + +
+
+
+
+ + +
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+ + +
+
+ Online — 1 +
+
+
+ System +
+
+ + +