Wavetype commited on
Commit
0a187ef
·
verified ·
1 Parent(s): 1380fa9

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +201 -0
index.html ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Fantasy Rally: Modular Workspace</title>
7
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.1/font/bootstrap-icons.min.css" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ --accent: #3b82f6;
13
+ --bg-dark: #0f172a;
14
+ --card-bg: #1e293b;
15
+ }
16
+ body { background-color: var(--bg-dark); color: white; overflow: hidden; height: 100vh; }
17
+
18
+ .block-grid {
19
+ display: grid;
20
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
21
+ gap: 1.5rem;
22
+ padding: 2rem;
23
+ height: calc(100vh - 80px);
24
+ overflow-y: auto;
25
+ }
26
+
27
+ .workspace-block {
28
+ background: var(--card-bg);
29
+ border: 2px solid #334155;
30
+ border-radius: 12px;
31
+ position: relative;
32
+ transition: all 0.2s ease;
33
+ min-height: 400px;
34
+ display: flex;
35
+ flex-direction: column;
36
+ }
37
+
38
+ .block-header {
39
+ padding: 0.75rem;
40
+ background: rgba(0,0,0,0.2);
41
+ border-bottom: 1px solid #334155;
42
+ display: flex;
43
+ justify-content: space-between;
44
+ align-items: center;
45
+ }
46
+
47
+ .content-area { flex-grow: 1; position: relative; overflow: hidden; border-radius: 0 0 12px 12px; }
48
+
49
+ /* Media Handling */
50
+ .preview-media { width: 100%; height: 100%; object-fit: cover; }
51
+ iframe { width: 100%; height: 100%; border: none; background: white; }
52
+
53
+ /* Floating Controls */
54
+ #toolbar {
55
+ height: 60px;
56
+ background: #1e293b;
57
+ border-bottom: 2px solid #3b82f6;
58
+ display: flex;
59
+ align-items: center;
60
+ padding: 0 2rem;
61
+ gap: 1rem;
62
+ }
63
+
64
+ .hidden-file { display: none; }
65
+ </style>
66
+ </head>
67
+ <body>
68
+
69
+ <div id="toolbar">
70
+ <h1 class="text-xl font-bold mr-4">Fantasy Rally: Workspace</h1>
71
+ <button onclick="addNewBlock()" class="bg-blue-600 hover:bg-blue-500 px-4 py-2 rounded-lg text-sm font-bold transition">
72
+ <i class="bi bi-plus-lg mr-2"></i>New Block
73
+ </button>
74
+ <button onclick="exportSQL()" class="bg-green-600 hover:bg-green-500 px-4 py-2 rounded-lg text-sm font-bold transition ml-auto">
75
+ <i class="bi bi-database-down mr-2"></i>Export SQL
76
+ </button>
77
+ </div>
78
+
79
+ <div id="grid" class="block-grid">
80
+ </div>
81
+
82
+ <div id="background-processes" class="hidden"></div>
83
+
84
+ <script>
85
+ let blocks = [];
86
+ const grid = document.getElementById('grid');
87
+
88
+ function addNewBlock() {
89
+ const id = Date.now();
90
+ const blockObj = {
91
+ id: id,
92
+ type: 'empty',
93
+ title: 'Unsaved Reward',
94
+ content: null,
95
+ fileName: 'none'
96
+ };
97
+ blocks.push(blockObj);
98
+ renderBlocks();
99
+ }
100
+
101
+ function handleFileUpload(event, id) {
102
+ const file = event.target.files[0];
103
+ if (!file) return;
104
+
105
+ const block = blocks.find(b => b.id === id);
106
+ block.fileName = file.name;
107
+ const extension = file.name.split('.').pop().toLowerCase();
108
+
109
+ const reader = new FileReader();
110
+ reader.onload = (e) => {
111
+ if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(extension)) {
112
+ block.type = 'image';
113
+ block.content = e.target.result;
114
+ } else if (['mp4', 'webm'].includes(extension)) {
115
+ block.type = 'video';
116
+ block.content = e.target.result;
117
+ } else if (['html', 'js'].includes(extension)) {
118
+ block.type = 'code';
119
+ block.content = e.target.result;
120
+ } else {
121
+ block.type = 'other';
122
+ block.content = e.target.result;
123
+ }
124
+ renderBlocks();
125
+ };
126
+
127
+ if (block.type === 'code') {
128
+ reader.readAsText(file);
129
+ } else {
130
+ reader.readAsDataURL(file);
131
+ }
132
+ }
133
+
134
+ function renderBlocks() {
135
+ grid.innerHTML = '';
136
+ blocks.forEach((block, index) => {
137
+ const card = document.createElement('div');
138
+ card.className = 'workspace-block';
139
+
140
+ let contentHtml = '';
141
+ if (block.type === 'empty') {
142
+ contentHtml = `
143
+ <div class="flex flex-col items-center justify-center h-full p-8 text-center">
144
+ <i class="bi bi-cloud-upload text-4xl text-slate-500 mb-4"></i>
145
+ <p class="text-slate-400 mb-4">Upload Asset (IMG, MP4, HTML)</p>
146
+ <input type="file" id="file-${block.id}" class="hidden-file" onchange="handleFileUpload(event, ${block.id})">
147
+ <button onclick="document.getElementById('file-${block.id}').click()" class="bg-slate-700 hover:bg-slate-600 px-4 py-2 rounded">Browse Files</button>
148
+ </div>
149
+ `;
150
+ } else if (block.type === 'image') {
151
+ contentHtml = `<img src="${block.content}" class="preview-media">`;
152
+ } else if (block.type === 'video') {
153
+ contentHtml = `<video src="${block.content}" class="preview-media" controls autoplay loop muted></video>`;
154
+ } else if (block.type === 'code') {
155
+ contentHtml = `<iframe srcdoc="${block.content.replace(/"/g, '&quot;')}" sandbox="allow-scripts"></iframe>`;
156
+ }
157
+
158
+ card.innerHTML = `
159
+ <div class="block-header">
160
+ <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">
161
+ <div class="flex gap-2">
162
+ <button onclick="deleteBlock(${block.id})" class="text-slate-400 hover:text-red-400"><i class="bi bi-trash"></i></button>
163
+ </div>
164
+ </div>
165
+ <div class="content-area">
166
+ ${contentHtml}
167
+ </div>
168
+ `;
169
+ grid.appendChild(card);
170
+ });
171
+ }
172
+
173
+ function deleteBlock(id) {
174
+ blocks = blocks.filter(b => b.id !== id);
175
+ renderBlocks();
176
+ }
177
+
178
+ function exportSQL() {
179
+ if (blocks.length === 0) return alert("No blocks to export.");
180
+
181
+ let sql = "INSERT INTO fantasy_rally_assets (id, title, file_type, data) VALUES \n";
182
+ const values = blocks.map(b => {
183
+ const safeTitle = b.title.replace(/'/g, "''");
184
+ // Truncate data for preview in SQL string
185
+ const dataPreview = b.content ? b.content.substring(0, 50) + "..." : "NULL";
186
+ return `(${b.id}, '${safeTitle}', '${b.type}', '${dataPreview}')`;
187
+ }).join(",\n");
188
+
189
+ const blob = new Blob([sql + values + ";"], { type: 'text/sql' });
190
+ const url = window.URL.createObjectURL(blob);
191
+ const a = document.createElement('a');
192
+ a.href = url;
193
+ a.download = "workspace_export.sql";
194
+ a.click();
195
+ }
196
+
197
+ // Initialize with one empty block
198
+ window.onload = addNewBlock;
199
+ </script>
200
+ </body>
201
+ </html>