( ′∀`)σ≡σ☆))Д′)レ(゚∀゚;)ヘ=З=З=Зε≡(ノ´_ゝ`)ノ
<?php
// public/canvas-editor.php
session_start();
require_once 'config/database.php';
$themeid = $_GET['themeid'] ?? 1;
$pageId = $_GET['page_id'] ?? 0;
$userId = $_SESSION['user_id'] ?? 'guest_' . uniqid();
?>
<!DOCTYPE html>
<html>
<head>
<title>Canvas Editor - Theme <?php echo $themeid; ?> Page <?php echo $pageId; ?></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
<script src="brandSync/js/canvas-sync.js"></script>
<script src="brandSync/js/canvas-enhanced.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: Arial, sans-serif; background: #f0f0f0; }
.toolbar {
background: #2c3e50; color: white; padding: 10px 20px;
display: flex; gap: 10px; align-items: center;
}
.toolbar button {
background: #3498db; color: white; border: none;
padding: 8px 16px; border-radius: 4px; cursor: pointer;
font-size: 14px;
}
.toolbar button:hover { background: #2980b9; }
.toolbar button:disabled { background: #95a5a6; cursor: not-allowed; }
.status {
margin-left: auto; display: flex; gap: 10px; align-items: center;
}
.status-dot {
width: 10px; height: 10px; border-radius: 50%; background: #e74c3c;
}
.status-dot.connected { background: #2ecc71; }
.canvas-container {
display: flex; justify-content: center; padding: 20px;
background: #ecf0f1; min-height: calc(100vh - 60px);
}
#canvas { box-shadow: 0 0 10px rgba(0,0,0,0.1); }
@keyframes slideIn {
from { transform: translateX(400px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slideOut {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(400px); opacity: 0; }
}
</style>
</head>
<body>
<div class="toolbar">
<button id="brand-json-save">💾 Save</button>
<button id="undoBtn">↶ Undo</button>
<button id="redoBtn">↷ Redo</button>
<button id="addRectBtn">▭ Rectangle</button>
<button id="addCircleBtn">● Circle</button>
<button id="addTextBtn">T Text</button>
<button id="exportBtn">📥 Export</button>
<button id="clearBtn">🗑️ Clear</button>
<div class="status">
<span id="userCount">0 users</span>
<div class="status-dot" id="statusDot"></div>
<span id="statusText">Connecting...</span>
</div>
</div>
<div class="canvas-container">
<canvas id="canvas" width="2240" height="1260"></canvas>
</div>
<script>
const canvas = new fabric.Canvas('canvas', {
backgroundColor: '#ffffff',
preserveObjectStacking: true
});
const collab = new EnhancedCanvasCollaboration(
canvas,
'<?php echo $userId; ?>',
<?php echo $themeid; ?>,
<?php echo $pageId; ?>
);
collab.loadFromBackend();
// Status updates
collab.ws.addEventListener('open', () => {
document.getElementById('statusDot').classList.add('connected');
document.getElementById('statusText').textContent = 'Connected';
});
collab.ws.addEventListener('close', () => {
document.getElementById('statusDot').classList.remove('connected');
document.getElementById('statusText').textContent = 'Disconnected';
});
// Toolbar
document.getElementById('brand-json-save').addEventListener('click', async () => {
const btn = document.getElementById('brand-json-save');
btn.disabled = true;
btn.textContent = '⏳ Saving...';
await collab.manualSave();
btn.disabled = false;
btn.textContent = '💾 Save';
});
document.getElementById('undoBtn').onclick = () => collab.undo();
document.getElementById('redoBtn').onclick = () => collab.redo();
document.getElementById('addRectBtn').onclick = () => {
canvas.add(new fabric.Rect({
left: 100, top: 100, width: 150, height: 100,
fill: '#3498db', id: 'rect_' + Date.now(),
objectType: 'shape', layerType: 'layer'
}));
};
document.getElementById('addCircleBtn').onclick = () => {
canvas.add(new fabric.Circle({
left: 150, top: 150, radius: 50, fill: '#e74c3c',
id: 'circle_' + Date.now(), objectType: 'shape', layerType: 'layer'
}));
};
document.getElementById('addTextBtn').onclick = () => {
canvas.add(new fabric.IText('Edit me', {
left: 200, top: 200, fontSize: 24, fill: '#2c3e50',
id: 'text_' + Date.now(), objectType: 'text', layerType: 'layer'
}));
};
document.getElementById('exportBtn').onclick = () => collab.exportAsImage('png', 1.0);
document.getElementById('clearBtn').onclick = () => collab.clearCanvas();
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
if (e.key === 's') { e.preventDefault(); document.getElementById('brand-json-save').click(); }
else if (e.key === 'z' && !e.shiftKey) { e.preventDefault(); collab.undo(); }
else if (e.key === 'z' && e.shiftKey) { e.preventDefault(); collab.redo(); }
}
if (e.key === 'Delete' || e.key === 'Backspace') {
const activeObjects = canvas.getActiveObjects();
if (activeObjects.length > 0) {
activeObjects.forEach(obj => canvas.remove(obj));
canvas.discardActiveObject();
canvas.renderAll();
}
}
});
// User count updates
collab.onUserJoined = (data) => {
document.getElementById('userCount').textContent = data.count + ' users';
};
collab.onUserLeft = (data) => {
document.getElementById('userCount').textContent = data.count + ' users';
};
window.addEventListener('beforeunload', () => collab.disconnect());
</script>
</body>
</html>