Cardcreationnnnn / index.html
Wavetype's picture
Create index.html
0a187ef verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fantasy Rally: Modular Workspace</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.1/font/bootstrap-icons.min.css" rel="stylesheet">
<style>
:root {
--accent: #3b82f6;
--bg-dark: #0f172a;
--card-bg: #1e293b;
}
body { background-color: var(--bg-dark); color: white; overflow: hidden; height: 100vh; }
.block-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
padding: 2rem;
height: calc(100vh - 80px);
overflow-y: auto;
}
.workspace-block {
background: var(--card-bg);
border: 2px solid #334155;
border-radius: 12px;
position: relative;
transition: all 0.2s ease;
min-height: 400px;
display: flex;
flex-direction: column;
}
.block-header {
padding: 0.75rem;
background: rgba(0,0,0,0.2);
border-bottom: 1px solid #334155;
display: flex;
justify-content: space-between;
align-items: center;
}
.content-area { flex-grow: 1; position: relative; overflow: hidden; border-radius: 0 0 12px 12px; }
/* Media Handling */
.preview-media { width: 100%; height: 100%; object-fit: cover; }
iframe { width: 100%; height: 100%; border: none; background: white; }
/* Floating Controls */
#toolbar {
height: 60px;
background: #1e293b;
border-bottom: 2px solid #3b82f6;
display: flex;
align-items: center;
padding: 0 2rem;
gap: 1rem;
}
.hidden-file { display: none; }
</style>
</head>
<body>
<div id="toolbar">
<h1 class="text-xl font-bold mr-4">Fantasy Rally: Workspace</h1>
<button onclick="addNewBlock()" class="bg-blue-600 hover:bg-blue-500 px-4 py-2 rounded-lg text-sm font-bold transition">
<i class="bi bi-plus-lg mr-2"></i>New Block
</button>
<button onclick="exportSQL()" class="bg-green-600 hover:bg-green-500 px-4 py-2 rounded-lg text-sm font-bold transition ml-auto">
<i class="bi bi-database-down mr-2"></i>Export SQL
</button>
</div>
<div id="grid" class="block-grid">
</div>
<div id="background-processes" class="hidden"></div>
<script>
let blocks = [];
const grid = document.getElementById('grid');
function addNewBlock() {
const id = Date.now();
const blockObj = {
id: id,
type: 'empty',
title: 'Unsaved Reward',
content: null,
fileName: 'none'
};
blocks.push(blockObj);
renderBlocks();
}
function handleFileUpload(event, id) {
const file = event.target.files[0];
if (!file) return;
const block = blocks.find(b => b.id === id);
block.fileName = file.name;
const extension = file.name.split('.').pop().toLowerCase();
const reader = new FileReader();
reader.onload = (e) => {
if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(extension)) {
block.type = 'image';
block.content = e.target.result;
} else if (['mp4', 'webm'].includes(extension)) {
block.type = 'video';
block.content = e.target.result;
} else if (['html', 'js'].includes(extension)) {
block.type = 'code';
block.content = e.target.result;
} else {
block.type = 'other';
block.content = e.target.result;
}
renderBlocks();
};
if (block.type === 'code') {
reader.readAsText(file);
} else {
reader.readAsDataURL(file);
}
}
function renderBlocks() {
grid.innerHTML = '';
blocks.forEach((block, index) => {
const card = document.createElement('div');
card.className = 'workspace-block';
let contentHtml = '';
if (block.type === 'empty') {
contentHtml = `
<div class="flex flex-col items-center justify-center h-full p-8 text-center">
<i class="bi bi-cloud-upload text-4xl text-slate-500 mb-4"></i>
<p class="text-slate-400 mb-4">Upload Asset (IMG, MP4, HTML)</p>
<input type="file" id="file-${block.id}" class="hidden-file" onchange="handleFileUpload(event, ${block.id})">
<button onclick="document.getElementById('file-${block.id}').click()" class="bg-slate-700 hover:bg-slate-600 px-4 py-2 rounded">Browse Files</button>
</div>
`;
} else if (block.type === 'image') {
contentHtml = `<img src="${block.content}" class="preview-media">`;
} else if (block.type === 'video') {
contentHtml = `<video src="${block.content}" class="preview-media" controls autoplay loop muted></video>`;
} else if (block.type === 'code') {
contentHtml = `<iframe srcdoc="${block.content.replace(/"/g, '&quot;')}" sandbox="allow-scripts"></iframe>`;
}
card.innerHTML = `
<div class="block-header">
<input class="bg-transparent border-none font-bold text-sm focus:ring-0 w-2/3" value="${block.title}" onchange="blocks[${index}].title = this.value">
<div class="flex gap-2">
<button onclick="deleteBlock(${block.id})" class="text-slate-400 hover:text-red-400"><i class="bi bi-trash"></i></button>
</div>
</div>
<div class="content-area">
${contentHtml}
</div>
`;
grid.appendChild(card);
});
}
function deleteBlock(id) {
blocks = blocks.filter(b => b.id !== id);
renderBlocks();
}
function exportSQL() {
if (blocks.length === 0) return alert("No blocks to export.");
let sql = "INSERT INTO fantasy_rally_assets (id, title, file_type, data) VALUES \n";
const values = blocks.map(b => {
const safeTitle = b.title.replace(/'/g, "''");
// Truncate data for preview in SQL string
const dataPreview = b.content ? b.content.substring(0, 50) + "..." : "NULL";
return `(${b.id}, '${safeTitle}', '${b.type}', '${dataPreview}')`;
}).join(",\n");
const blob = new Blob([sql + values + ";"], { type: 'text/sql' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = "workspace_export.sql";
a.click();
}
// Initialize with one empty block
window.onload = addNewBlock;
</script>
</body>
</html>