🐘
artifacts.php
Back
📝 Php ⚡ Executable Ctrl+S: Save • Ctrl+R: Run • Ctrl+F: Find
<?php // artifacts.php - Artifact Management System session_start(); // Initialize session artifacts if not exists if (!isset($_SESSION['artifacts'])) { $_SESSION['artifacts'] = []; } // Handle artifact operations if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; switch ($action) { case 'save_artifact': $id = trim($_POST['artifact_id'] ?? ''); $title = trim($_POST['artifact_title'] ?? ''); $content = $_POST['artifact_content'] ?? ''; if ($id && $title) { $_SESSION['artifacts'][$id] = [ 'title' => $title, 'content' => $content, 'created' => $_SESSION['artifacts'][$id]['created'] ?? time(), 'modified' => time() ]; } break; case 'delete_artifact': $id = $_POST['artifact_id'] ?? ''; if ($id && isset($_SESSION['artifacts'][$id])) { unset($_SESSION['artifacts'][$id]); } break; case 'create_new': $newId = 'artifact_' . time() . '_' . rand(1000, 9999); $_SESSION['artifacts'][$newId] = [ 'title' => 'New Artifact', 'content' => '', 'created' => time(), 'modified' => time() ]; break; } // Redirect to prevent form resubmission header('Location: ' . $_SERVER['PHP_SELF']); exit; } function h($s) { return htmlspecialchars($s ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>Artifacts Manager</title> <style> :root{ --bg:#0f1115; --panel:#151823; --ink:#e8e8e8; --muted:#9aa0a6; --br:#252a36; --accent:#2f6feb; --bot:#2a2f3a; --sep:#2b3242; --code:#0b0e14; --gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%); --gradient-secondary: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); --glow-color: #4f46e5; --danger: #ef4444; --success: #10b981; } * { box-sizing: border-box; } html, body { height: 100%; margin: 0; } body { background: var(--bg); color: var(--ink); font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; display: flex; flex-direction: column; } /* Header */ .header { height: 56px; background: var(--panel); border-bottom: 1px solid var(--br); display: flex; align-items: center; justify-content: space-between; padding: 0 16px; } .title { font-weight: 600; font-size: 1.1rem; } .header-actions { display: flex; gap: 8px; } .btn { background: #1b1f2a; color: var(--ink); border: 1px solid var(--br); border-radius: 10px; padding: 8px 16px; cursor: pointer; font-size: 0.9rem; text-decoration: none; display: inline-flex; align-items: center; gap: 6px; transition: all 0.2s ease; } .btn:hover { border-color: var(--accent); } .btn-primary { background: var(--accent); border-color: var(--accent); color: white; } .btn-primary:hover { filter: brightness(1.1); } .btn-danger { background: var(--danger); border-color: var(--danger); color: white; } .btn-fullscreen { background: var(--gradient-primary); border: none; color: white; font-weight: 600; } /* Main Layout */ .main { flex: 1; display: flex; overflow: hidden; } /* Sidebar */ .sidebar { width: 280px; background: var(--panel); border-right: 1px solid var(--br); display: flex; flex-direction: column; } .sidebar-header { padding: 16px; border-bottom: 1px solid var(--br); } .artifact-list { flex: 1; overflow-y: auto; padding: 8px; } .artifact-item { display: flex; align-items: center; gap: 12px; padding: 12px; margin-bottom: 4px; border-radius: 8px; cursor: pointer; transition: all 0.2s ease; border: 1px solid transparent; } .artifact-item:hover { background: rgba(255, 255, 255, 0.05); border-color: var(--br); } .artifact-item.active { background: rgba(47, 111, 235, 0.1); border-color: var(--accent); } .artifact-radio { width: 16px; height: 16px; accent-color: var(--accent); } .artifact-info { flex: 1; min-width: 0; } .artifact-title { font-weight: 500; font-size: 0.9rem; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .artifact-meta { font-size: 0.75rem; color: var(--muted); } .artifact-delete { opacity: 0; background: var(--danger); border: none; color: white; width: 24px; height: 24px; border-radius: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 12px; transition: opacity 0.2s ease; } .artifact-item:hover .artifact-delete { opacity: 1; } /* Content Area */ .content { flex: 1; display: flex; flex-direction: column; overflow: hidden; } .content-header { padding: 16px; border-bottom: 1px solid var(--br); background: var(--panel); } .content-body { flex: 1; padding: 16px; display: flex; flex-direction: column; gap: 16px; overflow: auto; } .form-group { display: flex; flex-direction: column; gap: 6px; } .form-label { font-size: 0.9rem; font-weight: 500; color: var(--ink); } .form-input { background: #0d111a; color: var(--ink); border: 1px solid var(--br); border-radius: 8px; padding: 10px 12px; font-size: 0.95rem; font-family: inherit; } .form-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(47, 111, 235, 0.1); } .form-textarea { resize: vertical; min-height: 400px; font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 0.9rem; line-height: 1.5; } .form-actions { display: flex; gap: 12px; padding-top: 8px; } /* Empty State */ .empty-state { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; color: var(--muted); gap: 16px; } .empty-icon { width: 64px; height: 64px; opacity: 0.5; } /* Responsive */ @media (max-width: 768px) { .sidebar { width: 100%; max-height: 200px; } .main { flex-direction: column; } .artifact-item { padding: 8px; } .content-body { padding: 12px; } } </style> </head> <body> <div class="header"> <div class="title">Artifacts Manager</div> <div class="header-actions"> <a href="index.php" class="btn">← Back to Chat</a> <button class="btn btn-primary" onclick="submitToChat()" id="submitBtn" disabled> 📤 Submit to Chat </button> </div> </div> <div class="main"> <!-- Sidebar --> <div class="sidebar"> <div class="sidebar-header"> <form method="post" style="margin: 0;"> <button type="submit" name="action" value="create_new" class="btn btn-primary" style="width: 100%;"> + New Artifact </button> </form> </div> <div class="artifact-list"> <?php if (empty($_SESSION['artifacts'])): ?> <div style="padding: 20px; text-align: center; color: var(--muted); font-size: 0.9rem;"> No artifacts yet.<br>Create your first one! </div> <?php else: ?> <?php foreach ($_SESSION['artifacts'] as $id => $artifact): ?> <div class="artifact-item" onclick="selectArtifact('<?= h($id) ?>')" id="item-<?= h($id) ?>"> <input type="radio" name="selected_artifact" value="<?= h($id) ?>" class="artifact-radio" id="radio-<?= h($id) ?>"> <div class="artifact-info"> <div class="artifact-title"><?= h($artifact['title']) ?></div> <div class="artifact-meta"> Modified <?= date('M j, Y g:i A', $artifact['modified']) ?> </div> </div> <form method="post" style="margin: 0;" onclick="event.stopPropagation();"> <input type="hidden" name="action" value="delete_artifact"> <input type="hidden" name="artifact_id" value="<?= h($id) ?>"> <button type="submit" class="artifact-delete" onclick="return confirm('Delete this artifact?')" title="Delete">×</button> </form> </div> <?php endforeach; ?> <?php endif; ?> </div> </div> <!-- Content Area --> <div class="content"> <div class="content-header"> <h2 id="content-title">Select an artifact to edit</h2> </div> <div class="content-body"> <div id="editor-form" style="display: none;"> <form method="post" id="artifact-form"> <input type="hidden" name="action" value="save_artifact"> <input type="hidden" name="artifact_id" id="current-artifact-id"> <div class="form-group"> <label class="form-label" for="artifact-title">Title</label> <input type="text" id="artifact-title" name="artifact_title" class="form-input" placeholder="Enter artifact title..."> </div> <div class="form-group"> <label class="form-label" for="artifact-content">Content</label> <textarea id="artifact-content" name="artifact_content" class="form-input form-textarea" placeholder="Enter your artifact content here..."></textarea> </div> <div class="form-actions"> <button type="submit" class="btn btn-primary">💾 Save Artifact</button> <button type="button" class="btn" onclick="clearEditor()">Clear</button> </div> </form> </div> <div id="empty-state" class="empty-state"> <svg class="empty-icon" fill="currentColor" viewBox="0 0 24 24"> <path d="M14,2H6A2,2 0 0,0 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2M18,20H6V4H13V9H18V20Z" /> </svg> <h3>No artifact selected</h3> <p>Choose an artifact from the sidebar to start editing, or create a new one.</p> </div> </div> </div> </div> <script> // Artifact data from PHP const artifacts = <?= json_encode($_SESSION['artifacts']) ?>; let currentArtifactId = null; // Select artifact function function selectArtifact(artifactId) { // Update radio button document.getElementById('radio-' + artifactId).checked = true; // Update visual selection document.querySelectorAll('.artifact-item').forEach(item => { item.classList.remove('active'); }); document.getElementById('item-' + artifactId).classList.add('active'); // Load artifact data const artifact = artifacts[artifactId]; if (artifact) { currentArtifactId = artifactId; document.getElementById('current-artifact-id').value = artifactId; document.getElementById('artifact-title').value = artifact.title; document.getElementById('artifact-content').value = artifact.content; document.getElementById('content-title').textContent = artifact.title; document.getElementById('editor-form').style.display = 'block'; document.getElementById('empty-state').style.display = 'none'; // Enable submit button document.getElementById('submitBtn').disabled = false; } } // Clear editor function clearEditor() { document.getElementById('artifact-title').value = ''; document.getElementById('artifact-content').value = ''; } // Auto-save on content change (debounced) let saveTimeout; function autoSave() { clearTimeout(saveTimeout); saveTimeout = setTimeout(() => { if (currentArtifactId) { const form = document.getElementById('artifact-form'); const formData = new FormData(form); fetch(window.location.href, { method: 'POST', body: formData }).then(() => { // Update local artifacts object artifacts[currentArtifactId].title = document.getElementById('artifact-title').value; artifacts[currentArtifactId].content = document.getElementById('artifact-content').value; artifacts[currentArtifactId].modified = Date.now() / 1000; // Update sidebar display const titleElement = document.querySelector(`#item-${currentArtifactId} .artifact-title`); if (titleElement) { titleElement.textContent = artifacts[currentArtifactId].title; } }); } }, 2000); } // Add auto-save listeners document.getElementById('artifact-title').addEventListener('input', autoSave); document.getElementById('artifact-content').addEventListener('input', autoSave); // Submit to chat functionality function submitToChat() { if (currentArtifactId && artifacts[currentArtifactId]) { const title = artifacts[currentArtifactId].title; const content = artifacts[currentArtifactId].content; // Create a compact version for chat submission const compactContent = content.substring(0, 200) + (content.length > 200 ? '...' : ''); // Store in session for chat to pick up const chatData = { title: title, content: content, compactContent: compactContent, timestamp: Date.now() }; // Send to backend to store in session fetch('submit_artifact.php', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(chatData) }).then(response => response.json()) .then(data => { if (data.success) { // Add delay to ensure session write completes setTimeout(() => { window.location.href = 'index.php?artifact_submitted=1&_=' + Date.now(); }, 500); // 500ms delay } else { alert('Error submitting artifact to chat'); } }).catch(error => { console.error('Error:', error); alert('Error submitting artifact to chat'); }); } } // Prevent form submission on Enter in title field document.getElementById('artifact-title').addEventListener('keydown', function(e) { if (e.key === 'Enter') { e.preventDefault(); document.getElementById('artifact-content').focus(); } }); // Initialize first artifact if available window.addEventListener('load', function() { const firstArtifact = Object.keys(artifacts)[0]; if (firstArtifact) { selectArtifact(firstArtifact); } }); </script> </body> </html>