drakosfire commited on
Commit
454d813
2 Parent(s): c3c0e66 6b59dc7

merging with script and storeUI.css

Browse files
Files changed (3) hide show
  1. scripts.js +794 -0
  2. storeUI.css +518 -0
  3. storeUI.html +2 -1316
scripts.js ADDED
@@ -0,0 +1,794 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Waits for DOM content to be fully loaded and assigns critical elements to variables.
2
+ let initialPositions = [];
3
+ document.addEventListener("DOMContentLoaded", function() {
4
+ const blockContainer = document.getElementById('blockContainer');
5
+ let blockContainerPage = document.getElementById('block-page');
6
+ const pageContainer = document.getElementById('pages');
7
+ const trashArea = document.getElementById('trashArea');
8
+ const resetButton = document.getElementById('resetButton');
9
+ let currentPage = pageContainer.querySelector('.block.monster.frame.wide');
10
+ const modal = document.getElementById('imageModal');
11
+ const modalImg = document.getElementById('modalImage');
12
+ const captionText = document.getElementById('caption');
13
+ const closeModal = document.getElementsByClassName('close')[0];
14
+ const MAX_COLUMN_HEIGHT = 847;
15
+
16
+ if (!blockContainer || !pageContainer || !trashArea || !currentPage) {
17
+ console.error('Required elements are null');
18
+ return;
19
+ }
20
+ if (!modal) {
21
+ console.error('modal element not found');
22
+ return;
23
+ }
24
+ if (!modalImg) {
25
+ console.error('modalImg element not found');
26
+ return;
27
+ }
28
+ if (!captionText) {
29
+ console.error('captionText element not found');
30
+ return;
31
+ }
32
+ if (!closeModal) {
33
+ console.error('closeModal element not found');
34
+ return;
35
+ }
36
+
37
+ // Event delegation for image clicks
38
+ blockContainer.addEventListener('click', function(event) {
39
+ console.log('Click detected in blockContainer:', event.target);
40
+ if (event.target.tagName === 'IMG' && event.target.id.startsWith('generated-image-')) {
41
+ console.log('Image clicked for modal display. Image ID:', event.target.id);
42
+ modal.style.display = 'block';
43
+ modalImg.src = event.target.src;
44
+ captionText.innerHTML = event.target.alt;
45
+ } else {
46
+ console.log('Clicked element is not an image or does not match ID pattern.');
47
+ }
48
+ });
49
+
50
+ // Function to close the modal
51
+ closeModal.onclick = function() {
52
+ modal.style.display = "none";
53
+ }
54
+
55
+ // Function to close the modal when clicking outside of the modal content
56
+ window.onclick = function(event) {
57
+ if (event.target == modal) {
58
+ modal.style.display = "none";
59
+ }
60
+ }
61
+
62
+ document.getElementById('submitDescription').addEventListener('click', function() {
63
+ const userInput = document.getElementById('user-description').value;
64
+ // Clear the block container before inserting new blocks
65
+ blockContainerPage.innerHTML = '';
66
+
67
+
68
+ fetch('http://127.0.0.1:5000/process-description', {
69
+ method: 'POST',
70
+ headers: {
71
+ 'Content-Type': 'application/json'
72
+ },
73
+ body: JSON.stringify({ user_input: userInput })
74
+ })
75
+ .then(response => response.json())
76
+ .then(data => {
77
+ console.log('Success:', data);
78
+ initialPositions.length = 0; // Clear the initialPositions array
79
+ insertHtmlBlocks(data.html_blocks);
80
+ const blocks = blockContainerPage.querySelectorAll('.block-item');
81
+ blocks.forEach(block => {
82
+ block.setAttribute('data-page-id', 'block-container');
83
+ block.setAttribute('draggable', true);
84
+ block.addEventListener('dragstart', handleDragStart);
85
+ block.addEventListener('dragend', handleDragEnd);
86
+ });
87
+ storeInitialPositions();
88
+ })
89
+ .catch((error) => {
90
+ console.error('Error:', error);
91
+ });
92
+ });
93
+ // Print Function
94
+ window.printPageContainer = function() {
95
+ var pageContainer = document.getElementById('pages');
96
+ if (pageContainer) {
97
+ var printContents = pageContainer.innerHTML;
98
+ var originalContents = document.body.innerHTML;
99
+
100
+ document.body.innerHTML = printContents;
101
+
102
+ window.print();
103
+
104
+ document.body.innerHTML = originalContents;
105
+ } else {
106
+ console.error('Element with ID "pageContainer" not found.');
107
+ }
108
+ }
109
+
110
+ // Store initial positions of the blocks
111
+ function storeInitialPositions() {
112
+ initialPositions = []; // Clear initialPositions before updating
113
+ const blocks = blockContainer.querySelectorAll('.block-item');
114
+ blocks.forEach((block, index) => {
115
+ const blockId = block.getAttribute('data-block-id');
116
+ if (!blockId) {
117
+ console.error(`Block at index ${index} is missing data-block-id`);
118
+ }
119
+ initialPositions.push({
120
+ id: blockId,
121
+ index: index
122
+ });
123
+ });
124
+ console.log('Initial positions:', initialPositions);
125
+ }
126
+
127
+ function insertHtmlBlocks(blocks) {
128
+ console.log('blockContainerPage = ', blockContainerPage)
129
+ console.log('List of blocks:', blocks);
130
+
131
+ const parser = new DOMParser();
132
+
133
+ blocks.forEach(blockHtml => {
134
+ console.log('Original blockHtml:', blockHtml);
135
+
136
+ // Parse the HTML string
137
+ const doc = parser.parseFromString(blockHtml, 'text/html');
138
+ console.log('Parsed document:', doc);
139
+ const block = doc.body.firstChild;
140
+ console.log('Parsed block:', block);
141
+ if (block) {
142
+ blockContainerPage.appendChild(block); // Append the parsed block to the container
143
+ console.log('Appended block:', block);
144
+ }
145
+
146
+ });
147
+ // console.log('Final state of blockContainer:', blockContainer.innerHTML);
148
+ initializeTextareaResizing();
149
+ }
150
+
151
+ storeInitialPositions();
152
+
153
+ function adjustTextareaHeight(el) {
154
+ if (el.scrollHeight > 16){
155
+ el.style.height = 'auto';
156
+ el.style.height = (el.scrollHeight) + 'px';
157
+ }
158
+ console.log('Original height:', el.style.height);
159
+ }
160
+
161
+ function initializeTextareaResizing() {
162
+ const classes = [
163
+ 'description-textarea',
164
+ 'user-description-textarea',
165
+ 'heading-textarea',
166
+ 'properties-textarea',
167
+ 'string-stat-textarea',
168
+ 'string-action-description-textarea',
169
+ ];
170
+
171
+ classes.forEach(className => {
172
+ const textareas = document.querySelectorAll(`.${className}`);
173
+ console.log(`Textareas found for ${className}:`, textareas.length); // Debugging line
174
+ textareas.forEach(textarea => {
175
+ console.log('scrollHeight:', textarea.scrollHeight);
176
+ console.log('clientHeight:', textarea.clientHeight);
177
+ console.log('offsetHeight:', textarea.offsetHeight);
178
+ console.log('Computed line-height:', window.getComputedStyle(textarea).lineHeight);
179
+
180
+ // Adjust height on page load
181
+ adjustTextareaHeight(textarea);
182
+ // Adjust height on input
183
+ textarea.addEventListener('input', function() {
184
+ adjustTextareaHeight(textarea);
185
+ console.log('Input event triggered for:', textarea.id); // Debugging line
186
+ });
187
+ });
188
+ });
189
+ }
190
+
191
+ // Initial run on page load
192
+ initializeTextareaResizing();
193
+
194
+ async function extractBlocks() {
195
+
196
+ try {
197
+ if (blockContainerPage.children.length > 0) {
198
+ console.log('Blocks already loaded, skipping fetch');
199
+ return;
200
+ }
201
+ const response = await fetch('The_Mirage_Emporium.html');
202
+ if (!response.ok) {
203
+ throw new Error('Network response was not ok ' + response.statusText);
204
+ }
205
+ const text = await response.text();
206
+ const parser = new DOMParser();
207
+ const doc = parser.parseFromString(text, 'text/html');
208
+ const blocks = doc.querySelectorAll('[class^="Block_"]');
209
+
210
+
211
+ blocks.forEach((block, index) => {
212
+ const blockContent = block.innerHTML;
213
+ const blockItem = document.createElement('div');
214
+ blockItem.classList.add('block-item');
215
+ blockItem.innerHTML = blockContent;
216
+ const blockId = `block-${index}`;
217
+ blockItem.setAttribute('data-block-id', blockId);
218
+ const pageId = 'block-container';
219
+ blockItem.setAttribute('data-page-id', pageId);
220
+ blockItem.setAttribute('draggable', true);
221
+ blockItem.addEventListener('dragstart', handleDragStart);
222
+ blockItem.addEventListener('dragend', handleDragEnd);
223
+
224
+ console.log(`Loaded block with ID: ${blockId}`);
225
+ blockContainerPage.appendChild(blockItem);
226
+ });
227
+
228
+ storeInitialPositions();
229
+ } catch (error) {
230
+ console.error('Error fetching and parsing template.html:', error);
231
+ }
232
+ }
233
+
234
+ blockContainer.addEventListener('click', function(event) {
235
+ if (event.target && event.target.classList.contains('generate-image-button')) {
236
+ const blockId = event.target.getAttribute('data-block-id');
237
+ generateImage(blockId);
238
+ }
239
+ });
240
+
241
+ // Function to generate image
242
+ function generateImage(blockId) {
243
+ const sdPromptElement = document.getElementById(`user-storefront-prompt-${blockId}`);
244
+ const imageElement = document.getElementById(`generated-image-${blockId}`);
245
+
246
+ if (!sdPromptElement) {
247
+ console.error('Element with ID user-storefront-prompt not found');
248
+ return;
249
+ }
250
+
251
+ if (!imageElement) {
252
+ console.error('Element with ID generated-image not found');
253
+ return;
254
+ }
255
+
256
+ const sdPrompt = sdPromptElement.value;
257
+
258
+ fetch('http://127.0.0.1:5000/generate-image', {
259
+ method: 'POST',
260
+ headers: {
261
+ 'Content-Type': 'application/json'
262
+ },
263
+ body: JSON.stringify({ sd_prompt: sdPrompt })
264
+ })
265
+ .then(response => response.json())
266
+ .then(data => {
267
+ console.log('Received data:', data);
268
+ imageElement.src = data.image_url;
269
+ imageElement.style.display = 'block';
270
+
271
+ // Log the image element's HTML structure
272
+ console.log('Updated imageElement HTML:', imageElement.outerHTML);
273
+ })
274
+ .catch((error) => {
275
+ console.error('Error:', error);
276
+ });
277
+ }
278
+
279
+ function handleDragStart(e) {
280
+ const target = e.target.closest('.block-item, .block-content');
281
+ if (!target) {
282
+ console.error('Drag started for an element without a valid target');
283
+ return;
284
+ }
285
+ const blockId = target.getAttribute('data-block-id');
286
+ const pageId = target.getAttribute('data-page-id');
287
+ if (!blockId) {
288
+ console.error('Drag started for an element without a data-block-id');
289
+ return;
290
+ }
291
+ if (!pageId) {
292
+ console.error('Drag started for an element without a data-page-id');
293
+ return;
294
+ }
295
+ const innerHTML = target.innerHTML;
296
+ e.dataTransfer.setData('block-id', blockId);
297
+ e.dataTransfer.setData('text/plain', innerHTML); // Store inner HTML
298
+ e.dataTransfer.setData('data-page-id', pageId); // Store original page ID
299
+ e.dataTransfer.effectAllowed = 'move';
300
+ target.style.opacity = '0.4';
301
+
302
+ // Create an invisible drag image
303
+ const dragImage = document.createElement('div');
304
+ dragImage.style.width = '1px';
305
+ dragImage.style.height = '1px';
306
+ dragImage.style.opacity = '0';
307
+ document.body.appendChild(dragImage);
308
+ e.dataTransfer.setDragImage(dragImage, 0, 0);
309
+
310
+ console.log(`Drag started for block ID: ${blockId} page ID: ${pageId}`);
311
+ }
312
+
313
+ function handleDragEnd(e) {
314
+ const target = e.target.closest('.block-item, .block-content');
315
+ if (target) {
316
+ target.style.opacity = '1'; // Reset the opacity
317
+ const blockId = target.getAttribute('data-block-id');
318
+ console.log(`Drag ended for block ID: ${blockId}`);
319
+ }
320
+
321
+ // Remove highlight classes from pages and blocks
322
+ document.querySelectorAll('.highlight-page').forEach(el => el.classList.remove('highlight-page'));
323
+ document.querySelectorAll('.highlight-block').forEach(el => el.classList.remove('highlight-block'));
324
+ document.querySelectorAll('.highlight-block-top').forEach(el => el.classList.remove('highlight-block-top'));
325
+ }
326
+
327
+ function handleDragOver(e) {
328
+ e.preventDefault();
329
+ e.dataTransfer.dropEffect = 'move';
330
+ console.log('Drag over event');
331
+
332
+ const targetPage = e.target.closest('.page');
333
+ if (targetPage) {
334
+ targetPage.classList.add('highlight-page'); // Add highlight class for pages
335
+ }
336
+
337
+ const targetBlock = e.target.closest('.block-item, .block-content');
338
+ if (targetBlock) {
339
+ const bounding = targetBlock.getBoundingClientRect();
340
+ const offset = e.clientY - bounding.top;
341
+ if (offset > bounding.height / 2) {
342
+ targetBlock.classList.add('highlight-block');
343
+ targetBlock.classList.remove('highlight-block-top');
344
+ } else {
345
+ targetBlock.classList.add('highlight-block-top');
346
+ targetBlock.classList.remove('highlight-block');
347
+ }
348
+ }
349
+ }
350
+
351
+ function handleDrop(e) {
352
+ e.preventDefault();
353
+ const blockId = e.dataTransfer.getData('block-id');
354
+ const originalPageId = e.dataTransfer.getData('data-page-id');
355
+ const innerHTML = e.dataTransfer.getData('text/plain');
356
+ console.log(`Drop event for block ID: ${blockId} from page ID: ${originalPageId}`);
357
+
358
+ // Ensure we are not dropping into a textarea or another block
359
+ if (event.target.classList.contains('block-item', 'block-content') || event.target.tagName === 'TEXTAREA') {
360
+ console.log('Cannot drop block inside another block or textarea');
361
+ return;
362
+ }
363
+
364
+ if (blockId && originalPageId) {
365
+ const originalBlock = document.querySelector(`[data-block-id="${blockId}"]`);
366
+ const newPage = e.target.closest('.page');
367
+ console.log(`Over page ${newPage} from page ID: ${originalPageId}`);
368
+ const newPageId = newPage.getAttribute('data-page-id');
369
+
370
+ // Ensure the original block exists before proceeding
371
+ if (!originalBlock || !newPage) {
372
+ console.error(`Block with ID ${blockId} on page ${originalPageId} not found`);
373
+ return;
374
+ }
375
+
376
+ const newBlockContent = document.createElement('div');
377
+ newBlockContent.classList.add('block-content');
378
+ newBlockContent.innerHTML = originalBlock.innerHTML; // Transfer inner content only
379
+
380
+ // Add necessary attributes and event listeners
381
+ newBlockContent.setAttribute('data-block-id', blockId);
382
+ newBlockContent.setAttribute('data-page-id', newPageId);
383
+ console.log('newPageID:', newPageId);
384
+ newBlockContent.setAttribute('draggable', true);
385
+ newBlockContent.addEventListener('dragstart', handleDragStart);
386
+ newBlockContent.addEventListener('dragend', handleDragEnd);
387
+
388
+ const target = e.target.closest('.block-item, .block-content');
389
+ let targetColumn = 1;
390
+ if (target) {
391
+ const bounding = target.getBoundingClientRect();
392
+ const offset = e.clientY - bounding.top;
393
+
394
+ console.log('Drop target found:', target);
395
+ console.log('Bounding rectangle:', bounding);
396
+ console.log('Offset from top:', offset);
397
+ console.log('Target height:', bounding.height);
398
+ console.log('Insert before or after decision point (height / 2):', bounding.height / 2);
399
+
400
+ targetColumn = getColumnFromOffset(target, offset);
401
+ if (offset > bounding.height / 2) {
402
+ console.log('Inserting after the target');
403
+ target.parentNode.insertBefore(newBlockContent, target.nextSibling);
404
+ } else {
405
+ console.log('Inserting before the target');
406
+ target.parentNode.insertBefore(newBlockContent, target);
407
+ }
408
+
409
+ // Remove highlight borders
410
+ target.style['border-bottom'] = '';
411
+ target.style['border-top'] = '';
412
+ } else {
413
+ console.log('No valid drop target found, appending to the end');
414
+ newPage.querySelector('.block.monster.frame.wide').appendChild(newBlockContent);
415
+ }
416
+
417
+ // Remove the original block from the original container
418
+ originalBlock.parentNode.removeChild(originalBlock);
419
+
420
+ // Reset opacity of dragged element
421
+ newBlockContent.style.opacity = '1';
422
+ console.log(`Moved existing block with ID: ${blockId} to page ID: ${newPageId}`);
423
+ initializeTextareaResizing();
424
+ // Adjust layouts
425
+ if (originalPageId !== 'block-container') {
426
+ adjustPageLayout(originalPageId);
427
+ }
428
+ adjustPageLayout(newPageId, targetColumn);
429
+ } else {
430
+ console.log('No data transferred');
431
+ }
432
+ }
433
+
434
+ function getColumnFromOffset(block, offset) {
435
+ const page = block.closest('.page');
436
+ if (!page) return 1;
437
+ const columnWrapper = page.querySelector('.columnWrapper');
438
+ const columnWrapperRect = columnWrapper.getBoundingClientRect();
439
+ const relativeOffset = offset - columnWrapperRect.left; // Calculate the offset relative to the column wrapper
440
+ const columnWidth = columnWrapper.clientWidth / 2; // Assuming two columns
441
+
442
+ // Log details for debugging
443
+ console.log('Block offset:', offset);
444
+ console.log('Relative offset:', relativeOffset);
445
+
446
+ const columnNumber = Math.ceil(relativeOffset / columnWidth);
447
+
448
+ // Ensure the column number is within valid bounds (1 or 2)
449
+ const validColumnNumber = Math.min(Math.max(columnNumber, 1), 2);
450
+ return validColumnNumber;
451
+ }
452
+
453
+
454
+ // Function to get the height of a column by index
455
+ function getColumnHeights(pageElement) {
456
+ const columns = [0, 0]; // Assuming two columns for simplicity
457
+ const blocks = pageElement.querySelectorAll('.block-content');
458
+ blocks.forEach(block => {
459
+ const column = getColumnFromOffset(block, block.getBoundingClientRect().left);
460
+ columns[column - 1] += block.offsetHeight;
461
+ });
462
+ return columns;
463
+ }
464
+
465
+ function adjustPageLayout(pageId) {
466
+ const page = document.querySelector(`[data-page-id="${pageId}"]`);
467
+ if (!page) {
468
+ console.error(`Page with ID ${pageId} not found`);
469
+ return;
470
+ }
471
+
472
+ const columnHeights = getColumnHeights(page);
473
+ console.log(`Total height of columns in ${pageId}: ${columnHeights}`);
474
+
475
+ for (let i = 0; i < columnHeights.length; i++) {
476
+ if (columnHeights[i] > MAX_COLUMN_HEIGHT) {
477
+ console.log(`Column ${i + 1} in ${pageId} exceeds max height, total height: ${columnHeights[i]}px`);
478
+ handleColumnOverflow(page, i + 1);
479
+ }
480
+ }
481
+ }
482
+
483
+ let pageCounter = 1;
484
+ // Function to create new page
485
+ function createNewPage() {
486
+ const newPage = document.createElement('div');
487
+ newPage.classList.add('page');
488
+ newPage.setAttribute('data-page-id', `page-${pageCounter}`);
489
+ newPage.id = `page-${pageCounter}`;
490
+
491
+ const columnWrapper = document.createElement('div');
492
+ columnWrapper.classList.add('columnWrapper');
493
+
494
+ const newMonsterFrame = document.createElement('div');
495
+ newMonsterFrame.classList.add('block', 'monster', 'frame', 'wide');
496
+
497
+ columnWrapper.appendChild(newMonsterFrame);
498
+ newPage.appendChild(columnWrapper);
499
+ pageContainer.appendChild(newPage);
500
+
501
+ currentPage = newMonsterFrame;
502
+ console.log(`Created new page with ID: ${newPage.id}`);
503
+
504
+ // Add event listeners to the new currentPage
505
+ currentPage.addEventListener('dragover', handleDragOver);
506
+ currentPage.addEventListener('drop', handleDrop);
507
+
508
+ pageCounter++;
509
+ return newPage;
510
+ }
511
+
512
+ function handleColumnOverflow(page, targetColumn) {
513
+ console.log(`Handling overflow for page ID: ${page.getAttribute('data-page-id')} in column ${targetColumn}`);
514
+ const blocks = Array.from(page.querySelectorAll('.block-content'));
515
+ let columnHeights = [0, 0];
516
+ let overflowStartIndex = -1;
517
+
518
+ // Find the start index where overflow begins in the target column
519
+ blocks.forEach((block, index) => {
520
+ const column = getColumnFromOffset(block, block.getBoundingClientRect().left);
521
+ columnHeights[column - 1] += block.offsetHeight;
522
+ if (columnHeights[targetColumn - 1] > MAX_COLUMN_HEIGHT && overflowStartIndex === -1) {
523
+ overflowStartIndex = index;
524
+ }
525
+ });
526
+
527
+ // If no overflow, return early
528
+ if (overflowStartIndex === -1) {
529
+ return;
530
+ }
531
+ const overflowBlocks = blocks.slice(overflowStartIndex);
532
+ const overflowHeight = overflowBlocks.reduce((acc, block) => acc + block.offsetHeight, 0);
533
+
534
+ // If the target column is the first column, check if the second column has enough space
535
+ if (targetColumn === 1) {
536
+ const secondColumnAvailableHeight = MAX_COLUMN_HEIGHT - columnHeights[1];
537
+
538
+ if (overflowHeight <= secondColumnAvailableHeight) {
539
+ // Move the overflowing blocks to the second column within the same page
540
+ overflowBlocks.forEach(block => {
541
+ const blockWrapper = block.closest('.block.monster.frame.wide');
542
+ if (blockWrapper) {
543
+ blockWrapper.appendChild(block);
544
+ block.setAttribute('data-page-id', page.getAttribute('data-page-id'));
545
+ }
546
+ });
547
+ return;
548
+ }
549
+ }
550
+
551
+ // Get the next page if it exists
552
+ const nextPage = getNextPage(page);
553
+ if (nextPage) {
554
+ const nextPageBlocks = nextPage.querySelectorAll('.block-content, .block-item');
555
+ let nextPageColumnHeights = [0, 0];
556
+
557
+ nextPageBlocks.forEach(block => {
558
+ const column = getColumnFromOffset(block, block.getBoundingClientRect().left);
559
+ nextPageColumnHeights[column - 1] += block.offsetHeight;
560
+ });
561
+
562
+ // Check if there's enough space in the target column of the next page
563
+ if (nextPageColumnHeights[targetColumn - 1] + overflowHeight <= MAX_COLUMN_HEIGHT) {
564
+ const nextPageContainer = nextPage.querySelector('.block.monster.frame.wide');
565
+ overflowBlocks.forEach(block => {
566
+ nextPageContainer.appendChild(block);
567
+ block.setAttribute('data-page-id', nextPage.getAttribute('data-page-id'));
568
+ });
569
+ return;
570
+ }
571
+
572
+ // If the next page's second column has enough space for overflow from the first column
573
+ if (targetColumn === 1 && nextPageColumnHeights[1] + overflowHeight <= MAX_COLUMN_HEIGHT) {
574
+ const nextPageContainer = nextPage.querySelector('.block.monster.frame.wide');
575
+ overflowBlocks.forEach(block => {
576
+ nextPageContainer.appendChild(block);
577
+ block.setAttribute('data-page-id', nextPage.getAttribute('data-page-id'));
578
+ });
579
+ return;
580
+ }
581
+ }
582
+
583
+ // Otherwise, create a new page and move the overflowing blocks there
584
+ const newPage = createNewPage();
585
+ if (!newPage) {
586
+ console.error('Failed to create a new page');
587
+ return;
588
+ }
589
+ const newMonsterFrame = newPage.querySelector('.block.monster.frame.wide');
590
+ if (!newMonsterFrame) {
591
+ console.error('New monster frame not found in the new page');
592
+ return;
593
+ }
594
+
595
+
596
+ overflowBlocks.forEach(block => {
597
+ newMonsterFrame.appendChild(block);
598
+ });
599
+ console.log(`Moved overflowing blocks to new page with ID: ${newPage.getAttribute('data-page-id')}`);
600
+ }
601
+
602
+ // Utility function to get the next page element
603
+ function getNextPage(currentPage) {
604
+ const nextPageId = parseInt(currentPage.getAttribute('data-page-id').split('-')[1]) + 1;
605
+ return document.querySelector(`[data-page-id="page-${nextPageId}"]`);
606
+ }
607
+
608
+ function moveBlockToPage(block, newPageId) {
609
+ block.setAttribute('data-page-id', newPageId);
610
+ const newPage = document.querySelector(`[data-page-id="${newPageId}"] .block-container`);
611
+ newPage.appendChild(block);
612
+ }
613
+
614
+ // Handle the drop event on the trash area
615
+ function handleTrashDrop(e) {
616
+ e.preventDefault();
617
+ const innerHTML = e.dataTransfer.getData('text/plain');
618
+ const blockId = e.dataTransfer.getData('block-id');
619
+ console.log('Trash Drop event:', e);
620
+ console.log('Dragged block ID to trash:', blockId);
621
+
622
+ if (innerHTML && blockId) {
623
+ // Find the dragged element and remove it from the DOM
624
+ let draggedElement = document.querySelector(`[data-block-id="${blockId}"].block-content`);
625
+ if (!draggedElement) {
626
+ draggedElement = document.querySelector(`[data-block-id="${blockId}"].block-item`);
627
+ }
628
+ if (draggedElement && draggedElement.parentElement) {
629
+ draggedElement.parentElement.removeChild(draggedElement);
630
+ console.log(`Removed block with ID: ${blockId} from the page`);
631
+ }
632
+
633
+ // Check if the block already exists in the block-container and remove it if it does
634
+ let existingBlock = blockContainer.querySelector(`[data-block-id="${blockId}"].block-content`);
635
+ if (!existingBlock) {
636
+ existingBlock = blockContainer.querySelector(`[data-block-id="${blockId}"].block-item`);
637
+ }
638
+ if (existingBlock && existingBlock.parentElement) {
639
+ existingBlock.parentElement.removeChild(existingBlock);
640
+ console.log(`Removed duplicate block with ID: ${blockId} from block-container`);
641
+ }
642
+
643
+ // Create a new block-item to be placed back in the block-container
644
+ const newBlock = document.createElement('div');
645
+ newBlock.classList.add('block-item');
646
+ newBlock.setAttribute('data-block-id', blockId);
647
+ newBlock.setAttribute('data-page-id', 'block-container');
648
+ newBlock.innerHTML = innerHTML;
649
+ newBlock.setAttribute('draggable', true);
650
+ newBlock.addEventListener('dragstart', handleDragStart);
651
+ newBlock.addEventListener('dragend', handleDragEnd);
652
+
653
+ // Ensure the block is appended to the page wrapper inside blockContainer
654
+ let pageWrapper = blockContainer.querySelector('.page');
655
+ if (!pageWrapper) {
656
+ pageWrapper = document.createElement('div');
657
+ pageWrapper.classList.add('page');
658
+ pageWrapper.setAttribute('data-page-id', 'block-container');
659
+ blockContainer.appendChild(pageWrapper);
660
+ }
661
+
662
+ // Debugging output
663
+ console.log('Page wrapper:', pageWrapper);
664
+ console.log('New block:', newBlock);
665
+
666
+ // Find the original position to insert the new block
667
+ const originalPosition = initialPositions.find(pos => pos.id === blockId);
668
+ console.log('Original position:', originalPosition);
669
+
670
+ if (originalPosition) {
671
+ const blocks = pageWrapper.querySelectorAll('.block-item');
672
+ console.log('Blocks in pageWrapper:', blocks);
673
+ console.log('Inserting at position:', originalPosition.index);
674
+
675
+ if (originalPosition.index < blocks.length) {
676
+ const referenceNode = blocks[originalPosition.index];
677
+ if (referenceNode && referenceNode.parentNode === pageWrapper) {
678
+ console.log('Inserting before block at index:', originalPosition.index);
679
+ pageWrapper.insertBefore(newBlock, referenceNode);
680
+ console.log(`Moved block back to original position ${originalPosition.index} in block-container`);
681
+ } else {
682
+ console.warn('Reference node does not belong to pageWrapper, appending to the end');
683
+ pageWrapper.appendChild(newBlock);
684
+ console.log('Appended block to the end of block-container');
685
+ }
686
+ } else {
687
+ console.log('Appending block to the end of pageWrapper');
688
+ pageWrapper.appendChild(newBlock);
689
+ console.log('Appended block to the end of block-container');
690
+ }
691
+ } else {
692
+ console.log('Original position not found, appending block to the end of pageWrapper');
693
+ pageWrapper.appendChild(newBlock);
694
+ console.log('Appended block to the end of block-container');
695
+ }
696
+
697
+ console.log(`Restored block with ID: ${blockId}`);
698
+ } else {
699
+ console.log('No data transferred');
700
+ }
701
+
702
+ // Remove the "over" class and reset the background image
703
+ trashArea.classList.remove('over');
704
+ trashArea.style.backgroundImage = "url('./closed-mimic-trashcan.png')";
705
+ initializeTextareaResizing();
706
+ }
707
+
708
+ function handleTrashOver(e) {
709
+ e.preventDefault();
710
+ e.dataTransfer.dropEffect = 'move';
711
+ trashArea.classList.add('over');
712
+ trashArea.style.backgroundImage = "url('./mimic_trashcan.png')";
713
+ console.log('Trash over event');
714
+ }
715
+
716
+ function handleTrashLeave(e) {
717
+ trashArea.classList.remove('over');
718
+ trashArea.style.backgroundImage = "url('./closed-mimic-trashcan.png')";
719
+ console.log('Trash leave event');
720
+ }
721
+
722
+ function handleReset() {
723
+ console.log('Reset button clicked');
724
+
725
+ // Collect all blocks from all pages
726
+ const allBlocks = [];
727
+ const pages = document.querySelectorAll('.page');
728
+ pages.forEach(page => {
729
+ const blocksOnPage = page.querySelectorAll('[data-block-id]');
730
+ blocksOnPage.forEach(block => {
731
+ const blockId = block.getAttribute('data-block-id');
732
+ allBlocks.push({
733
+ id: blockId,
734
+ innerHTML: block.innerHTML
735
+ });
736
+ block.remove();
737
+ console.log(`Removed block with ID: ${blockId} from page ID: ${page.getAttribute('data-page-id')}`);
738
+ });
739
+ });
740
+
741
+ // Clear all pages
742
+ pages.forEach(page => page.remove());
743
+
744
+ // Clear blockContainer before reinserting blocks
745
+ blockContainer.innerHTML = '';
746
+
747
+ // Reinsert blocks back into the blockContainer in their original order
748
+ let pageWrapper = blockContainer.querySelector('.page');
749
+ if (!pageWrapper) {
750
+ pageWrapper = document.createElement('div');
751
+ pageWrapper.classList.add('page');
752
+ pageWrapper.setAttribute('id', 'block-page');
753
+ blockContainer.appendChild(pageWrapper);
754
+ }
755
+ // Reassign blockContainerPage to the newly created block-page element
756
+ blockContainerPage = document.getElementById('block-page');
757
+
758
+ initialPositions.forEach(pos => {
759
+ const blockData = allBlocks.find(block => block.id === pos.id);
760
+ if (blockData) {
761
+ const newBlock = document.createElement('div');
762
+ newBlock.classList.add('block-item');
763
+ newBlock.setAttribute('data-block-id', blockData.id);
764
+ newBlock.setAttribute('data-page-id', 'block-container');
765
+ newBlock.innerHTML = blockData.innerHTML;
766
+ newBlock.setAttribute('draggable', true);
767
+ newBlock.addEventListener('dragstart', handleDragStart);
768
+ newBlock.addEventListener('dragend', handleDragEnd);
769
+
770
+ const blocks = pageWrapper.querySelectorAll('.block-item');
771
+ if (pos.index < blocks.length) {
772
+ pageWrapper.insertBefore(newBlock, blocks[pos.index]);
773
+ console.log(`Moved block back to original position ${pos.index} in block-container`);
774
+ } else {
775
+ pageWrapper.appendChild(newBlock);
776
+ console.log('Appended block to the end of block-container');
777
+ }
778
+ }
779
+ });
780
+ createNewPage();
781
+
782
+ console.log('Reset complete, all blocks moved back to block-container');
783
+ initializeTextareaResizing();
784
+ }
785
+
786
+ pageContainer.addEventListener('dragover', handleDragOver);
787
+ pageContainer.addEventListener('drop', handleDrop);
788
+
789
+ trashArea.addEventListener('dragover', handleTrashOver);
790
+ trashArea.addEventListener('dragleave', handleTrashLeave);
791
+ trashArea.addEventListener('drop', handleTrashDrop);
792
+ resetButton.addEventListener('click', handleReset);
793
+ extractBlocks();
794
+ });
storeUI.css ADDED
@@ -0,0 +1,518 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root {
2
+ --HB_Color_Background: #EEE5CE;
3
+ --HB_Color_Accent: #E0E5C1;
4
+ --HB_Color_HeaderUnderline: #C0AD6A;
5
+ --HB_Color_HorizontalRule: #9C2B1B;
6
+ --HB_Color_HeaderText: #58180D;
7
+ --HB_Color_MonsterStatBackground: #F2E5B5;
8
+ --HB_Color_CaptionText: #766649;
9
+ --HB_Color_WatercolorStain: #BBAD82;
10
+ --HB_Color_Footnotes: #C9AD6A;
11
+ }
12
+ input[type="text"], textarea {
13
+ width: auto;
14
+ padding: 8px;
15
+ margin: 5px 0;
16
+ border: 1px solid #ccc;
17
+ border-radius: 4px;
18
+ font-size: 14px;
19
+ background-color: #f9f9f9;
20
+ transition: background-color 0.3s ease, border-color 0.3s ease;
21
+ }
22
+ .grid-container {
23
+ display: grid;
24
+ grid-template-columns: 1fr 3fr; /* Two columns with the second column being three times as wide */
25
+ grid-gap: 20px;
26
+ padding: 20px;
27
+ height: 100vh;
28
+ }
29
+ .block-container {
30
+ position: fixed; /* Lock the block-container in place */
31
+ top: 20px; /* Distance from the top of the viewport */
32
+ left: 20px; /* Distance from the left of the viewport */
33
+ width: 450px; /* Set the width of the block-container */
34
+ height: calc(100vh - 40px); /* Full viewport height minus top and bottom padding */
35
+ overflow-y: auto; /* Enable vertical scrolling if needed */
36
+ border-right: 1px solid #ccc; /* Right border for visual separation */
37
+ padding-right: 20px; /* Padding inside the block-container */
38
+ box-sizing: border-box; /* Include padding and border in the element's total width and height */
39
+ background-color: #f9f9f9; /* Background color */
40
+ z-index: 1000; /* Ensure it is on top of other elements */
41
+ }
42
+
43
+ .block-container .page {
44
+ column-count: 1;
45
+ padding: 0;
46
+ width: 425px;
47
+ height: auto; /* Allow the page to expand to fit content */
48
+ overflow: visible; /* Allow content to overflow if necessary */
49
+ page-break-before: auto;
50
+ page-break-after: auto;
51
+
52
+ }
53
+ .page-container {
54
+ margin-left: 450px; /* Offset the page content by the width of block-container plus margin */
55
+ width: 900px;
56
+ padding: 20px;
57
+ overflow: auto; /* Enable scrolling if needed */
58
+ height: 100vh; /* Full viewport height */
59
+ box-sizing: border-box; /* Include padding and border in the element's total width and height */
60
+ }
61
+
62
+
63
+ .page {
64
+ column-count: 2;
65
+ column-gap: .9cm;
66
+ column-width: 8cm;
67
+ -webkit-column-count: 2;
68
+ -moz-column-count: 2;
69
+ -webkit-column-width: 8cm;
70
+ -moz-column-width: 8cm;
71
+ -webkit-column-gap: .9cm;
72
+ -moz-column-gap: .9cm;
73
+ position: relative;
74
+ z-index: 15;
75
+ box-sizing: border-box;
76
+ width: 215.9mm;
77
+ height: 279.4mm; /* Original height for print layout */
78
+ padding: 1.4cm 1.9cm 1.7cm;
79
+ overflow: hidden;
80
+ font-family: "BookInsanityRemake";
81
+ font-size: .34cm;
82
+ counter-increment: phb-page-numbers;
83
+ background-color: var(--HB_Color_Background);
84
+ background-image: url('./themes/assets/parchmentBackground.jpg');
85
+ text-rendering: optimizeLegibility;
86
+ page-break-before: always;
87
+ page-break-after: always;
88
+ contain: size;
89
+ }
90
+
91
+ .page .monster hr:last-of-type + * {
92
+ margin-top: .1cm;
93
+ }
94
+ .page * + h3 {
95
+ margin-top: .05cm;
96
+ }
97
+ .page * + h4 {
98
+ margin-top: .1cm;
99
+ }
100
+ .page h4 + * {
101
+ margin-top: .1cm;
102
+ }
103
+ .page dl + * {
104
+ margin-top: .1cm;
105
+ }
106
+ .page p + * {
107
+ margin-top: .1cm;
108
+ }
109
+ .page img {
110
+ width: 100%;
111
+ height: auto;
112
+ cursor: pointer;
113
+ }
114
+ .page .classTable.frame{
115
+ margin-right:0.1cm;
116
+ margin-left: 0.1cm;
117
+ }
118
+
119
+ /* Ensure the h1 tag is constrained within its column */
120
+ .block-content h1 {
121
+ column-span: none;
122
+ box-sizing: border-box; /* Include padding and border in the element's total width and height */
123
+ margin: 0 auto; /* Center the h1 within the column */
124
+ overflow: hidden; /* Handle overflow content */
125
+ word-wrap: break-word; /* Break long words to prevent overflow */
126
+ }
127
+ .columnWrapper {
128
+ column-gap: inherit;
129
+ max-height: 100%;
130
+ column-span: all;
131
+ columns: inherit;
132
+ height: 100%; /* Ensure it takes full height of the parent */
133
+ box-sizing: border-box; /* Ensures padding and border are included in the element's total width and height */
134
+ }
135
+ /* block-item styling */
136
+ .block-item {
137
+ border: 1px solid #ccc;
138
+ border-radius: 8px;
139
+ background-color: transparent;
140
+ padding: 15px;
141
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
142
+ transition: transform 0.3s;
143
+ }
144
+ .block-item:hover {
145
+ /* transform: translateY(-5px);
146
+ background-color: rgba(255, 255, 255, 0.5); /* Slightly visible background on hover */
147
+ }
148
+
149
+ .block-item img {
150
+ width: 100%;
151
+ height: auto;
152
+ cursor: pointer;
153
+ }
154
+
155
+ /* Modal styling */
156
+ .modal {
157
+ display: none; /* Hidden by default */
158
+ position: fixed; /* Stay in place */
159
+ z-index: 1001; /* Sit on top */
160
+ left: 0;
161
+ top: 0;
162
+ width: 100%; /* Full width */
163
+ height: 100%; /* Full height */
164
+ overflow: auto; /* Enable scroll if needed */
165
+ background-color: rgb(0,0,0); /* Fallback color */
166
+ background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
167
+ }
168
+
169
+ .modal-content {
170
+ margin: auto;
171
+ display: block;
172
+ width: 80%;
173
+ max-width: 700px;
174
+ }
175
+
176
+ .modal-content, #caption {
177
+ animation-name: zoom;
178
+ animation-duration: 0.6s;
179
+ }
180
+
181
+ @keyframes zoom {
182
+ from {transform: scale(0)}
183
+ to {transform: scale(1)}
184
+ }
185
+
186
+ .close {
187
+ position: absolute;
188
+ top: 15px;
189
+ right: 35px;
190
+ color: #f1f1f1;
191
+ font-size: 40px;
192
+ font-weight: bold;
193
+ transition: 0.3s;
194
+ }
195
+
196
+ .close:hover,
197
+ .close:focus {
198
+ color: #bbb;
199
+ text-decoration: none;
200
+ cursor: pointer;
201
+ }
202
+ input[type="text"]:focus, textarea:focus {
203
+ background-color: #e9e9e9;
204
+ border-color: #aaa;
205
+ outline: none;
206
+ }
207
+
208
+ /* Specific styles for different textboxes */
209
+
210
+ .user-description-textarea {
211
+ width: 400px;
212
+ height: 40px; /* Adjust as needed for 3 lines */
213
+ resize: vertical;
214
+ background: none;
215
+ font-family: "ScalySansRemake";
216
+ font-weight: 800;
217
+
218
+ }
219
+ /* Focus styles for description textbox */
220
+ .user-description-textarea:focus {
221
+ background-color: #e9e9e9;
222
+ border-color: #aaa;
223
+ outline: none;
224
+ }
225
+
226
+ .heading-textarea {
227
+ width: 100%;
228
+ font-size: .458cm; /* Matches the font size of an h4 heading */
229
+ line-height: .7em;
230
+ font-weight: 800;
231
+ border: none;
232
+ background: none;
233
+ margin: 0;
234
+ padding: 0;
235
+ resize: none; /* Prevents the textarea from being resizable */
236
+ overflow: hidden; /* Prevents scrollbars */
237
+ outline: none; /* Removes the focus outline */
238
+ font-family: "MrEavesRemake"; /* Ensures font family is inherited */
239
+ color: var(--HB_Color_HeaderText)
240
+
241
+ }
242
+ .title-textarea{
243
+ height:30px;
244
+ width: 100%;
245
+ margin-bottom: 5px;
246
+ column-span: all;
247
+ font-size: .89cm;
248
+ line-height: 1em;
249
+ font-family: "MrEavesRemake";
250
+ font-weight: 800;
251
+ color: var(--HB_Color_HeaderText);
252
+ border: 0;
253
+ font: inherit;
254
+ background: none;
255
+ padding: 0;
256
+ resize: none; /* Prevents the textarea from being resizable */
257
+ overflow: hidden; /* Prevents scrollbars */
258
+ outline: none; /* Removes the focus outline */
259
+
260
+ }
261
+
262
+ .subtitle-textarea{
263
+ height:20px;
264
+ width: 100%;
265
+ margin-bottom: 5px;
266
+ column-span: all;
267
+ font-size: .89cm;
268
+ line-height: 1em;
269
+ font-family: "MrEavesRemake";
270
+ font-weight: 800;
271
+ color: var(--HB_Color_HeaderText);
272
+ border: 0;
273
+ font: inherit;
274
+ background: none;
275
+ padding: 0;
276
+ resize: none; /* Prevents the textarea from being resizable */
277
+ overflow: hidden; /* Prevents scrollbars */
278
+ outline: none; /* Removes the focus outline */
279
+
280
+ }
281
+
282
+ div[contenteditable="true"]:focus {
283
+ background-color: #e9e9e9;
284
+ border-color: #aaa;
285
+ outline: none;
286
+ }
287
+
288
+ div[contenteditable="true"] p::first-letter {
289
+ float: left;
290
+ padding-bottom: 2px;
291
+ padding-left: 40px;
292
+ margin-top: 0cm;
293
+ margin-bottom: -20px;
294
+ margin-left: -40px;
295
+ font-family: "SolberaImitationRemake";
296
+ font-size: 3.5cm;
297
+ line-height: 1em;
298
+ color: rgba(0, 0, 0, 0);
299
+ background-image: linear-gradient(-45deg, #322814, #998250, #322814);
300
+ -webkit-background-clip: text;
301
+ background-clip: text;
302
+ border: 0;
303
+ }
304
+ .properties-textarea {
305
+ width: 100%;
306
+ font-size: 12px;
307
+ font-weight: 400;
308
+ line-height: .7em;
309
+ margin-bottom: 0;
310
+ font-style: italic;
311
+ box-sizing: border-box;
312
+ border: 0;
313
+ font-family: "ScalySansRemake";
314
+ vertical-align: baseline;
315
+ margin: 0;
316
+ padding: 0;
317
+ overflow-wrap: break-word;
318
+ text-rendering: optimizeLegibility;
319
+ background: none;
320
+ resize: none; /* Prevents the textarea from being resizable */
321
+
322
+ }
323
+
324
+ .description-textarea {
325
+ width: 100%;
326
+ height: auto;
327
+ font-size: .318cm;
328
+ font-weight: 400;
329
+ line-height: .9em;
330
+ margin-bottom: 0;
331
+ font-style: italic;
332
+ box-sizing: border-box;
333
+ border: 0;
334
+ font-family: "ScalySansSmallCapsRemake";
335
+ vertical-align: baseline;
336
+ margin: 0;
337
+ padding: 0;
338
+ overflow-wrap: break-word;
339
+ text-rendering: optimizeLegibility;
340
+ background: none;
341
+ resize: none; /* Prevents the textarea from being manually resizable */
342
+ overflow: hidden; /* Hide scrollbars */
343
+ }
344
+
345
+ .red-integer-stat-textarea {
346
+ width: 20px;
347
+ height:13px;
348
+ font-size: .318cm;
349
+ font-weight: 400;
350
+ line-height: 1.2em;
351
+ margin-bottom: 0;
352
+ font-style: italic;
353
+ box-sizing: border-box;
354
+ border: 0;
355
+ font-family: "ScalySansSmallCapsRemake";
356
+ vertical-align: baseline;
357
+ margin: 0;
358
+ padding: 0;
359
+ overflow-wrap: break-word;
360
+ text-rendering: optimizeLegibility;
361
+ background: none;
362
+ resize: none; /* Prevents the textarea from being manually resizable */
363
+ overflow: hidden; /* Hide scrollbars */
364
+ color: var(--HB_Color_HeaderText);
365
+ white-space: pre-line;
366
+ }
367
+
368
+ .integer-stat-textarea {
369
+ width: 20px;
370
+ height:13px;
371
+ font-size: .318cm;
372
+ font-weight: 400;
373
+ line-height: 1.2em;
374
+ margin-bottom: 0;
375
+ font-style: italic;
376
+ box-sizing: border-box;
377
+ border: 0;
378
+ font-family: "ScalySansRemake";
379
+ vertical-align: baseline;
380
+ margin: 0;
381
+ padding: 0;
382
+ overflow-wrap: break-word;
383
+ text-rendering: optimizeLegibility;
384
+ background: none;
385
+ resize: none; /* Prevents the textarea from being manually resizable */
386
+ overflow: hidden; /* Hide scrollbars */
387
+ white-space: pre-line;
388
+ }
389
+
390
+ .string-stat-textarea {
391
+ width: 200px;
392
+ height:13px;
393
+ font-size: .318cm;
394
+ font-weight: 400;
395
+ line-height: 1.2em;
396
+ margin-bottom: 0;
397
+ font-style: italic;
398
+ box-sizing: border-box;
399
+ border: 0;
400
+ font-family: "ScalySansRemake";
401
+ vertical-align: baseline;
402
+ margin: 0;
403
+ padding: 0;
404
+ overflow-wrap: break-word;
405
+ text-rendering: optimizeLegibility;
406
+ background: none;
407
+ resize: none; /* Prevents the textarea from being manually resizable */
408
+ overflow: hidden; /* Hide scrollbars */
409
+ white-space: pre-wrap;
410
+ }
411
+
412
+ .string-action-name-textarea {
413
+ width: 100%;
414
+ height:13px;
415
+ font-size: .318cm;
416
+ font-style: italic;
417
+ font-weight: bold;
418
+ line-height: 1.2em;
419
+ margin-bottom: 0;
420
+ font-style: italic;
421
+ box-sizing: border-box;
422
+ border: 0;
423
+ font-family: "ScalySansRemake";
424
+ vertical-align: baseline;
425
+ margin: 0;
426
+ padding: 0;
427
+ overflow-wrap: break-word;
428
+ text-rendering: optimizeLegibility;
429
+ background: none;
430
+ resize: none; /* Prevents the textarea from being manually resizable */
431
+ overflow: hidden; /* Hide scrollbars */
432
+
433
+ }
434
+
435
+ .string-action-description-textarea {
436
+ width: 100%;
437
+ height:16px;
438
+ font-size: 14px;
439
+ font-weight: 400;
440
+ line-height: 16px;
441
+ margin-bottom: 0;
442
+ box-sizing: border-box;
443
+ border: 0;
444
+ font-family: "ScalySansRemake";
445
+ vertical-align: baseline;
446
+ margin: 0;
447
+ padding: 0;
448
+ overflow-wrap: break-word;
449
+ text-rendering: optimizeLegibility;
450
+ background: none;
451
+ resize: none; /* Prevents the textarea from being manually resizable */
452
+ overflow: hidden; /* Hide scrollbars */
453
+ }
454
+
455
+ .block.monster.frame.wide {
456
+ column-count: inherit;
457
+ min-height: 100px; /* Set an appropriate minimum height */
458
+ height: 859px; /* Allow height to expand automatically */
459
+ column-fill: auto;
460
+ overflow: hidden; /* Ensure content overflow is visible */
461
+ width: 100%; /* Ensure it takes the full width of the container */
462
+
463
+ }
464
+
465
+ .highlight-page {
466
+ outline: 2px dashed #2196F3; /* Blue dashed border */
467
+ background-color: rgba(33, 150, 243, 0.1); /* Light blue background */
468
+ }
469
+
470
+ .highlight-block {
471
+ border-bottom: 2px solid #2196F3; /* Blue solid border */
472
+ background-color: rgba(33, 150, 243, 0.1); /* Light blue background */
473
+ }
474
+
475
+ .highlight-block-top {
476
+ border-top: 2px solid #2196F3; /* Blue solid border at the top */
477
+ background-color: rgba(33, 150, 243, 0.1); /* Light blue background */
478
+ }
479
+
480
+ .name-textbox {
481
+ width: 50px;
482
+ font-size: 1.5em;
483
+ padding: 10px;
484
+ }
485
+
486
+ .stat-textbox {
487
+ width: 50px;
488
+ text-align: center;
489
+ font-size: 1em;
490
+ padding: 5px;
491
+ }
492
+
493
+ .trash-area {
494
+ position: fixed;
495
+ bottom: 20px;
496
+ right: 20px;
497
+ width: 100px;
498
+ height: 100px;
499
+
500
+ display: flex;
501
+ align-items: center;
502
+ justify-content: center;
503
+
504
+ cursor: pointer;
505
+ background-image: url('./closed-mimic-trashcan.png'); /* Adjust the path to your image file */
506
+ background-size: contain;
507
+ background-repeat: no-repeat;
508
+ background-position: center;
509
+ }
510
+
511
+ .trash-area:hover {
512
+ background-image: url('./mimic_trashcan.png');
513
+ }
514
+ .trash-area.over {
515
+ color: white;
516
+ background-image: url('./mimic_trashcan.png'); /* Example image change */
517
+ }
518
+
storeUI.html CHANGED
@@ -8,532 +8,12 @@
8
  <link href='./dependencies/bundle.css' rel='stylesheet' />
9
  <link href="./dependencies/style.css" rel='stylesheet' />
10
  <link href="./dependencies/5ePHBstyle.css" rel='stylesheet' />
 
11
  <title>DnD Stat Block</title>
12
  <link rel="stylesheet" href="styles.css">
13
  <script src="https://unpkg.com/[email protected]/dist/htmx.min.js"></script>
14
  </head>
15
- <style>
16
- :root {
17
- --HB_Color_Background: #EEE5CE;
18
- --HB_Color_Accent: #E0E5C1;
19
- --HB_Color_HeaderUnderline: #C0AD6A;
20
- --HB_Color_HorizontalRule: #9C2B1B;
21
- --HB_Color_HeaderText: #58180D;
22
- --HB_Color_MonsterStatBackground: #F2E5B5;
23
- --HB_Color_CaptionText: #766649;
24
- --HB_Color_WatercolorStain: #BBAD82;
25
- --HB_Color_Footnotes: #C9AD6A;
26
- }
27
- input[type="text"], textarea {
28
- width: auto;
29
- padding: 8px;
30
- margin: 5px 0;
31
- border: 1px solid #ccc;
32
- border-radius: 4px;
33
- font-size: 14px;
34
- background-color: #f9f9f9;
35
- transition: background-color 0.3s ease, border-color 0.3s ease;
36
- }
37
- .grid-container {
38
- display: grid;
39
- grid-template-columns: 1fr 3fr; /* Two columns with the second column being three times as wide */
40
- grid-gap: 20px;
41
- padding: 20px;
42
- height: 100vh;
43
- }
44
- .block-container {
45
- position: fixed; /* Lock the block-container in place */
46
- top: 20px; /* Distance from the top of the viewport */
47
- left: 20px; /* Distance from the left of the viewport */
48
- width: 450px; /* Set the width of the block-container */
49
- height: calc(100vh - 40px); /* Full viewport height minus top and bottom padding */
50
- overflow-y: auto; /* Enable vertical scrolling if needed */
51
- border-right: 1px solid #ccc; /* Right border for visual separation */
52
- padding-right: 20px; /* Padding inside the block-container */
53
- box-sizing: border-box; /* Include padding and border in the element's total width and height */
54
- background-color: #f9f9f9; /* Background color */
55
- z-index: 1000; /* Ensure it is on top of other elements */
56
- }
57
 
58
- .block-container .page {
59
- column-count: 1;
60
- padding: 0;
61
- width: 425px;
62
- height: auto; /* Allow the page to expand to fit content */
63
- overflow: visible; /* Allow content to overflow if necessary */
64
- page-break-before: auto;
65
- page-break-after: auto;
66
-
67
- }
68
- .page-container {
69
- margin-left: 450px; /* Offset the page content by the width of block-container plus margin */
70
- width: 900px;
71
- padding: 20px;
72
- overflow: auto; /* Enable scrolling if needed */
73
- height: 100vh; /* Full viewport height */
74
- box-sizing: border-box; /* Include padding and border in the element's total width and height */
75
- }
76
-
77
-
78
- .page {
79
- column-count: 2;
80
- column-gap: .9cm;
81
- column-width: 8cm;
82
- -webkit-column-count: 2;
83
- -moz-column-count: 2;
84
- -webkit-column-width: 8cm;
85
- -moz-column-width: 8cm;
86
- -webkit-column-gap: .9cm;
87
- -moz-column-gap: .9cm;
88
- position: relative;
89
- z-index: 15;
90
- box-sizing: border-box;
91
- width: 215.9mm;
92
- height: 279.4mm; /* Original height for print layout */
93
- padding: 1.4cm 1.9cm 1.7cm;
94
- overflow: hidden;
95
- font-family: "BookInsanityRemake";
96
- font-size: .34cm;
97
- counter-increment: phb-page-numbers;
98
- background-color: var(--HB_Color_Background);
99
- background-image: url('./themes/assets/parchmentBackground.jpg');
100
- text-rendering: optimizeLegibility;
101
- page-break-before: always;
102
- page-break-after: always;
103
- contain: size;
104
- }
105
-
106
- .page .monster hr:last-of-type + * {
107
- margin-top: .1cm;
108
- }
109
- .page * + h3 {
110
- margin-top: .05cm;
111
- }
112
- .page * + h4 {
113
- margin-top: .1cm;
114
- }
115
- .page h4 + * {
116
- margin-top: .1cm;
117
- }
118
- .page dl + * {
119
- margin-top: .1cm;
120
- }
121
- .page p + * {
122
- margin-top: .1cm;
123
- }
124
- .page img {
125
- width: 100%;
126
- height: auto;
127
- cursor: pointer;
128
- }
129
- .page .classTable.frame{
130
- margin-right:0.1cm;
131
- margin-left: 0.1cm;
132
- }
133
-
134
- /* Ensure the h1 tag is constrained within its column */
135
- .block-content h1 {
136
- column-span: none;
137
- box-sizing: border-box; /* Include padding and border in the element's total width and height */
138
- margin: 0 auto; /* Center the h1 within the column */
139
- overflow: hidden; /* Handle overflow content */
140
- word-wrap: break-word; /* Break long words to prevent overflow */
141
- }
142
- .columnWrapper {
143
- column-gap: inherit;
144
- max-height: 100%;
145
- column-span: all;
146
- columns: inherit;
147
- height: 100%; /* Ensure it takes full height of the parent */
148
- box-sizing: border-box; /* Ensures padding and border are included in the element's total width and height */
149
- }
150
- /* block-item styling */
151
- .block-item {
152
- border: 1px solid #ccc;
153
- border-radius: 8px;
154
- background-color: transparent;
155
- padding: 15px;
156
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
157
- transition: transform 0.3s;
158
- }
159
- .block-item:hover {
160
- /* transform: translateY(-5px);
161
- background-color: rgba(255, 255, 255, 0.5); /* Slightly visible background on hover */
162
- }
163
-
164
- .block-item img {
165
- width: 100%;
166
- height: auto;
167
- cursor: pointer;
168
- }
169
-
170
- /* Modal styling */
171
- .modal {
172
- display: none; /* Hidden by default */
173
- position: fixed; /* Stay in place */
174
- z-index: 1001; /* Sit on top */
175
- left: 0;
176
- top: 0;
177
- width: 100%; /* Full width */
178
- height: 100%; /* Full height */
179
- overflow: auto; /* Enable scroll if needed */
180
- background-color: rgb(0,0,0); /* Fallback color */
181
- background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
182
- }
183
-
184
- .modal-content {
185
- margin: auto;
186
- display: block;
187
- width: 80%;
188
- max-width: 700px;
189
- }
190
-
191
- .modal-content, #caption {
192
- animation-name: zoom;
193
- animation-duration: 0.6s;
194
- }
195
-
196
- @keyframes zoom {
197
- from {transform: scale(0)}
198
- to {transform: scale(1)}
199
- }
200
-
201
- .close {
202
- position: absolute;
203
- top: 15px;
204
- right: 35px;
205
- color: #f1f1f1;
206
- font-size: 40px;
207
- font-weight: bold;
208
- transition: 0.3s;
209
- }
210
-
211
- .close:hover,
212
- .close:focus {
213
- color: #bbb;
214
- text-decoration: none;
215
- cursor: pointer;
216
- }
217
- input[type="text"]:focus, textarea:focus {
218
- background-color: #e9e9e9;
219
- border-color: #aaa;
220
- outline: none;
221
- }
222
-
223
- /* Specific styles for different textboxes */
224
-
225
- .user-description-textarea {
226
- width: 400px;
227
- height: 40px; /* Adjust as needed for 3 lines */
228
- resize: vertical;
229
- background: none;
230
- font-family: "ScalySansRemake";
231
- font-weight: 800;
232
-
233
- }
234
- /* Focus styles for description textbox */
235
- .user-description-textarea:focus {
236
- background-color: #e9e9e9;
237
- border-color: #aaa;
238
- outline: none;
239
- }
240
-
241
- .heading-textarea {
242
- width: 100%;
243
- font-size: .458cm; /* Matches the font size of an h4 heading */
244
- line-height: .7em;
245
- font-weight: 800;
246
- border: none;
247
- background: none;
248
- margin: 0;
249
- padding: 0;
250
- resize: none; /* Prevents the textarea from being resizable */
251
- overflow: hidden; /* Prevents scrollbars */
252
- outline: none; /* Removes the focus outline */
253
- font-family: "MrEavesRemake"; /* Ensures font family is inherited */
254
- color: var(--HB_Color_HeaderText)
255
-
256
- }
257
- .title-textarea{
258
- height:30px;
259
- width: 100%;
260
- margin-bottom: 5px;
261
- column-span: all;
262
- font-size: .89cm;
263
- line-height: 1em;
264
- font-family: "MrEavesRemake";
265
- font-weight: 800;
266
- color: var(--HB_Color_HeaderText);
267
- border: 0;
268
- font: inherit;
269
- background: none;
270
- padding: 0;
271
- resize: none; /* Prevents the textarea from being resizable */
272
- overflow: hidden; /* Prevents scrollbars */
273
- outline: none; /* Removes the focus outline */
274
-
275
- }
276
-
277
- .subtitle-textarea{
278
- height:20px;
279
- width: 100%;
280
- margin-bottom: 5px;
281
- column-span: all;
282
- font-size: .89cm;
283
- line-height: 1em;
284
- font-family: "MrEavesRemake";
285
- font-weight: 800;
286
- color: var(--HB_Color_HeaderText);
287
- border: 0;
288
- font: inherit;
289
- background: none;
290
- padding: 0;
291
- resize: none; /* Prevents the textarea from being resizable */
292
- overflow: hidden; /* Prevents scrollbars */
293
- outline: none; /* Removes the focus outline */
294
-
295
- }
296
-
297
- div[contenteditable="true"]:focus {
298
- background-color: #e9e9e9;
299
- border-color: #aaa;
300
- outline: none;
301
- }
302
-
303
- div[contenteditable="true"] p::first-letter {
304
- float: left;
305
- padding-bottom: 2px;
306
- padding-left: 40px;
307
- margin-top: 0cm;
308
- margin-bottom: -20px;
309
- margin-left: -40px;
310
- font-family: "SolberaImitationRemake";
311
- font-size: 3.5cm;
312
- line-height: 1em;
313
- color: rgba(0, 0, 0, 0);
314
- background-image: linear-gradient(-45deg, #322814, #998250, #322814);
315
- -webkit-background-clip: text;
316
- background-clip: text;
317
- border: 0;
318
- }
319
- .properties-textarea {
320
- width: 100%;
321
- font-size: 12px;
322
- font-weight: 400;
323
- line-height: .7em;
324
- margin-bottom: 0;
325
- font-style: italic;
326
- box-sizing: border-box;
327
- border: 0;
328
- font-family: "ScalySansRemake";
329
- vertical-align: baseline;
330
- margin: 0;
331
- padding: 0;
332
- overflow-wrap: break-word;
333
- text-rendering: optimizeLegibility;
334
- background: none;
335
- resize: none; /* Prevents the textarea from being resizable */
336
-
337
- }
338
-
339
- .description-textarea {
340
- width: 100%;
341
- height: auto;
342
- font-size: .318cm;
343
- font-weight: 400;
344
- line-height: .9em;
345
- margin-bottom: 0;
346
- font-style: italic;
347
- box-sizing: border-box;
348
- border: 0;
349
- font-family: "ScalySansSmallCapsRemake";
350
- vertical-align: baseline;
351
- margin: 0;
352
- padding: 0;
353
- overflow-wrap: break-word;
354
- text-rendering: optimizeLegibility;
355
- background: none;
356
- resize: none; /* Prevents the textarea from being manually resizable */
357
- overflow: hidden; /* Hide scrollbars */
358
- }
359
-
360
- .red-integer-stat-textarea {
361
- width: 20px;
362
- height:13px;
363
- font-size: .318cm;
364
- font-weight: 400;
365
- line-height: 1.2em;
366
- margin-bottom: 0;
367
- font-style: italic;
368
- box-sizing: border-box;
369
- border: 0;
370
- font-family: "ScalySansSmallCapsRemake";
371
- vertical-align: baseline;
372
- margin: 0;
373
- padding: 0;
374
- overflow-wrap: break-word;
375
- text-rendering: optimizeLegibility;
376
- background: none;
377
- resize: none; /* Prevents the textarea from being manually resizable */
378
- overflow: hidden; /* Hide scrollbars */
379
- color: var(--HB_Color_HeaderText);
380
- white-space: pre-line;
381
- }
382
-
383
- .integer-stat-textarea {
384
- width: 20px;
385
- height:13px;
386
- font-size: .318cm;
387
- font-weight: 400;
388
- line-height: 1.2em;
389
- margin-bottom: 0;
390
- font-style: italic;
391
- box-sizing: border-box;
392
- border: 0;
393
- font-family: "ScalySansRemake";
394
- vertical-align: baseline;
395
- margin: 0;
396
- padding: 0;
397
- overflow-wrap: break-word;
398
- text-rendering: optimizeLegibility;
399
- background: none;
400
- resize: none; /* Prevents the textarea from being manually resizable */
401
- overflow: hidden; /* Hide scrollbars */
402
- white-space: pre-line;
403
- }
404
-
405
- .string-stat-textarea {
406
- width: 200px;
407
- height:13px;
408
- font-size: .318cm;
409
- font-weight: 400;
410
- line-height: 1.2em;
411
- margin-bottom: 0;
412
- font-style: italic;
413
- box-sizing: border-box;
414
- border: 0;
415
- font-family: "ScalySansRemake";
416
- vertical-align: baseline;
417
- margin: 0;
418
- padding: 0;
419
- overflow-wrap: break-word;
420
- text-rendering: optimizeLegibility;
421
- background: none;
422
- resize: none; /* Prevents the textarea from being manually resizable */
423
- overflow: hidden; /* Hide scrollbars */
424
- white-space: pre-wrap;
425
- }
426
-
427
- .string-action-name-textarea {
428
- width: 100%;
429
- height:13px;
430
- font-size: .318cm;
431
- font-style: italic;
432
- font-weight: bold;
433
- line-height: 1.2em;
434
- margin-bottom: 0;
435
- font-style: italic;
436
- box-sizing: border-box;
437
- border: 0;
438
- font-family: "ScalySansRemake";
439
- vertical-align: baseline;
440
- margin: 0;
441
- padding: 0;
442
- overflow-wrap: break-word;
443
- text-rendering: optimizeLegibility;
444
- background: none;
445
- resize: none; /* Prevents the textarea from being manually resizable */
446
- overflow: hidden; /* Hide scrollbars */
447
-
448
- }
449
-
450
- .string-action-description-textarea {
451
- width: 100%;
452
- height:16px;
453
- font-size: 14px;
454
- font-weight: 400;
455
- line-height: 16px;
456
- margin-bottom: 0;
457
- box-sizing: border-box;
458
- border: 0;
459
- font-family: "ScalySansRemake";
460
- vertical-align: baseline;
461
- margin: 0;
462
- padding: 0;
463
- overflow-wrap: break-word;
464
- text-rendering: optimizeLegibility;
465
- background: none;
466
- resize: none; /* Prevents the textarea from being manually resizable */
467
- overflow: hidden; /* Hide scrollbars */
468
- }
469
-
470
- .block.monster.frame.wide {
471
- column-count: inherit;
472
- min-height: 100px; /* Set an appropriate minimum height */
473
- height: 859px; /* Allow height to expand automatically */
474
- column-fill: auto;
475
- overflow: hidden; /* Ensure content overflow is visible */
476
- width: 100%; /* Ensure it takes the full width of the container */
477
-
478
- }
479
-
480
- .highlight-page {
481
- outline: 2px dashed #2196F3; /* Blue dashed border */
482
- background-color: rgba(33, 150, 243, 0.1); /* Light blue background */
483
- }
484
-
485
- .highlight-block {
486
- border-bottom: 2px solid #2196F3; /* Blue solid border */
487
- background-color: rgba(33, 150, 243, 0.1); /* Light blue background */
488
- }
489
-
490
- .highlight-block-top {
491
- border-top: 2px solid #2196F3; /* Blue solid border at the top */
492
- background-color: rgba(33, 150, 243, 0.1); /* Light blue background */
493
- }
494
-
495
- .name-textbox {
496
- width: 50px;
497
- font-size: 1.5em;
498
- padding: 10px;
499
- }
500
-
501
- .stat-textbox {
502
- width: 50px;
503
- text-align: center;
504
- font-size: 1em;
505
- padding: 5px;
506
- }
507
-
508
- .trash-area {
509
- position: fixed;
510
- bottom: 20px;
511
- right: 20px;
512
- width: 100px;
513
- height: 100px;
514
-
515
- display: flex;
516
- align-items: center;
517
- justify-content: center;
518
-
519
- cursor: pointer;
520
- background-image: url('./closed-mimic-trashcan.png'); /* Adjust the path to your image file */
521
- background-size: contain;
522
- background-repeat: no-repeat;
523
- background-position: center;
524
- }
525
-
526
- .trash-area:hover {
527
- background-image: url('./mimic_trashcan.png');
528
- }
529
- .trash-area.over {
530
- color: white;
531
- background-image: url('./mimic_trashcan.png'); /* Example image change */
532
- }
533
-
534
-
535
-
536
- </style>
537
  <body>
538
  <div class="grid-container">
539
  <div class="block-container" id="blockContainer" >
@@ -571,801 +51,7 @@ div[contenteditable="true"] p::first-letter {
571
  <img class="modal-content" id="modalImage">
572
  <div id="caption"></div>
573
  </div>
574
- <script>
575
- // Waits for DOM content to be fully loaded and assigns critical elements to variables.
576
- let initialPositions = [];
577
- document.addEventListener("DOMContentLoaded", function() {
578
- const blockContainer = document.getElementById('blockContainer');
579
- let blockContainerPage = document.getElementById('block-page');
580
- const pageContainer = document.getElementById('pages');
581
- const trashArea = document.getElementById('trashArea');
582
- const resetButton = document.getElementById('resetButton');
583
- let currentPage = pageContainer.querySelector('.block.monster.frame.wide');
584
- const modal = document.getElementById('imageModal');
585
- const modalImg = document.getElementById('modalImage');
586
- const captionText = document.getElementById('caption');
587
- const closeModal = document.getElementsByClassName('close')[0];
588
- const MAX_COLUMN_HEIGHT = 847;
589
-
590
- if (!blockContainer || !pageContainer || !trashArea || !currentPage) {
591
- console.error('Required elements are null');
592
- return;
593
- }
594
- if (!modal) {
595
- console.error('modal element not found');
596
- return;
597
- }
598
- if (!modalImg) {
599
- console.error('modalImg element not found');
600
- return;
601
- }
602
- if (!captionText) {
603
- console.error('captionText element not found');
604
- return;
605
- }
606
- if (!closeModal) {
607
- console.error('closeModal element not found');
608
- return;
609
- }
610
-
611
- // Event delegation for image clicks
612
- blockContainer.addEventListener('click', function(event) {
613
- console.log('Click detected in blockContainer:', event.target);
614
- if (event.target.tagName === 'IMG' && event.target.id.startsWith('generated-image-')) {
615
- console.log('Image clicked for modal display. Image ID:', event.target.id);
616
- modal.style.display = 'block';
617
- modalImg.src = event.target.src;
618
- captionText.innerHTML = event.target.alt;
619
- } else {
620
- console.log('Clicked element is not an image or does not match ID pattern.');
621
- }
622
- });
623
-
624
- // Function to close the modal
625
- closeModal.onclick = function() {
626
- modal.style.display = "none";
627
- }
628
-
629
- // Function to close the modal when clicking outside of the modal content
630
- window.onclick = function(event) {
631
- if (event.target == modal) {
632
- modal.style.display = "none";
633
- }
634
- }
635
-
636
- document.getElementById('submitDescription').addEventListener('click', function() {
637
- const userInput = document.getElementById('user-description').value;
638
- // Clear the block container before inserting new blocks
639
- blockContainerPage.innerHTML = '';
640
-
641
-
642
- fetch('http://127.0.0.1:5000/process-description', {
643
- method: 'POST',
644
- headers: {
645
- 'Content-Type': 'application/json'
646
- },
647
- body: JSON.stringify({ user_input: userInput })
648
- })
649
- .then(response => response.json())
650
- .then(data => {
651
- console.log('Success:', data);
652
- initialPositions.length = 0; // Clear the initialPositions array
653
- insertHtmlBlocks(data.html_blocks);
654
- const blocks = blockContainerPage.querySelectorAll('.block-item');
655
- blocks.forEach(block => {
656
- block.setAttribute('data-page-id', 'block-container');
657
- block.setAttribute('draggable', true);
658
- block.addEventListener('dragstart', handleDragStart);
659
- block.addEventListener('dragend', handleDragEnd);
660
- });
661
- storeInitialPositions();
662
- })
663
- .catch((error) => {
664
- console.error('Error:', error);
665
- });
666
- });
667
- // Print Function
668
- window.printPageContainer = function() {
669
- var pageContainer = document.getElementById('pages');
670
- if (pageContainer) {
671
- var printContents = pageContainer.innerHTML;
672
- var originalContents = document.body.innerHTML;
673
-
674
- document.body.innerHTML = printContents;
675
-
676
- window.print();
677
-
678
- document.body.innerHTML = originalContents;
679
- } else {
680
- console.error('Element with ID "pageContainer" not found.');
681
- }
682
- }
683
-
684
- // Store initial positions of the blocks
685
- function storeInitialPositions() {
686
- initialPositions = []; // Clear initialPositions before updating
687
- const blocks = blockContainer.querySelectorAll('.block-item');
688
- blocks.forEach((block, index) => {
689
- const blockId = block.getAttribute('data-block-id');
690
- if (!blockId) {
691
- console.error(`Block at index ${index} is missing data-block-id`);
692
- }
693
- initialPositions.push({
694
- id: blockId,
695
- index: index
696
- });
697
- });
698
- console.log('Initial positions:', initialPositions);
699
- }
700
-
701
- function insertHtmlBlocks(blocks) {
702
- console.log('blockContainerPage = ', blockContainerPage)
703
- console.log('List of blocks:', blocks);
704
-
705
- const parser = new DOMParser();
706
-
707
- blocks.forEach(blockHtml => {
708
- console.log('Original blockHtml:', blockHtml);
709
-
710
- // Parse the HTML string
711
- const doc = parser.parseFromString(blockHtml, 'text/html');
712
- console.log('Parsed document:', doc);
713
- const block = doc.body.firstChild;
714
- console.log('Parsed block:', block);
715
- if (block) {
716
- blockContainerPage.appendChild(block); // Append the parsed block to the container
717
- console.log('Appended block:', block);
718
- }
719
-
720
- });
721
- // console.log('Final state of blockContainer:', blockContainer.innerHTML);
722
- initializeTextareaResizing();
723
- }
724
-
725
- storeInitialPositions();
726
-
727
- function adjustTextareaHeight(el) {
728
- if (el.scrollHeight > 16){
729
- el.style.height = 'auto';
730
- el.style.height = (el.scrollHeight) + 'px';
731
- }
732
- console.log('Original height:', el.style.height);
733
- }
734
-
735
- function initializeTextareaResizing() {
736
- const classes = [
737
- 'description-textarea',
738
- 'user-description-textarea',
739
- 'heading-textarea',
740
- 'properties-textarea',
741
- 'string-stat-textarea',
742
- 'string-action-description-textarea',
743
- ];
744
-
745
- classes.forEach(className => {
746
- const textareas = document.querySelectorAll(`.${className}`);
747
- console.log(`Textareas found for ${className}:`, textareas.length); // Debugging line
748
- textareas.forEach(textarea => {
749
- console.log('scrollHeight:', textarea.scrollHeight);
750
- console.log('clientHeight:', textarea.clientHeight);
751
- console.log('offsetHeight:', textarea.offsetHeight);
752
- console.log('Computed line-height:', window.getComputedStyle(textarea).lineHeight);
753
-
754
- // Adjust height on page load
755
- adjustTextareaHeight(textarea);
756
- // Adjust height on input
757
- textarea.addEventListener('input', function() {
758
- adjustTextareaHeight(textarea);
759
- console.log('Input event triggered for:', textarea.id); // Debugging line
760
- });
761
- });
762
- });
763
- }
764
-
765
- // Initial run on page load
766
- initializeTextareaResizing();
767
-
768
- async function extractBlocks() {
769
-
770
- try {
771
- if (blockContainerPage.children.length > 0) {
772
- console.log('Blocks already loaded, skipping fetch');
773
- return;
774
- }
775
- const response = await fetch('The_Mirage_Emporium.html');
776
- if (!response.ok) {
777
- throw new Error('Network response was not ok ' + response.statusText);
778
- }
779
- const text = await response.text();
780
- const parser = new DOMParser();
781
- const doc = parser.parseFromString(text, 'text/html');
782
- const blocks = doc.querySelectorAll('[class^="Block_"]');
783
-
784
-
785
- blocks.forEach((block, index) => {
786
- const blockContent = block.innerHTML;
787
- const blockItem = document.createElement('div');
788
- blockItem.classList.add('block-item');
789
- blockItem.innerHTML = blockContent;
790
- const blockId = `block-${index}`;
791
- blockItem.setAttribute('data-block-id', blockId);
792
- const pageId = 'block-container';
793
- blockItem.setAttribute('data-page-id', pageId);
794
- blockItem.setAttribute('draggable', true);
795
- blockItem.addEventListener('dragstart', handleDragStart);
796
- blockItem.addEventListener('dragend', handleDragEnd);
797
-
798
- console.log(`Loaded block with ID: ${blockId}`);
799
- blockContainerPage.appendChild(blockItem);
800
- });
801
-
802
- storeInitialPositions();
803
- } catch (error) {
804
- console.error('Error fetching and parsing template.html:', error);
805
- }
806
- }
807
-
808
- blockContainer.addEventListener('click', function(event) {
809
- if (event.target && event.target.classList.contains('generate-image-button')) {
810
- const blockId = event.target.getAttribute('data-block-id');
811
- generateImage(blockId);
812
- }
813
- });
814
-
815
- // Function to generate image
816
- function generateImage(blockId) {
817
- const sdPromptElement = document.getElementById(`user-storefront-prompt-${blockId}`);
818
- const imageElement = document.getElementById(`generated-image-${blockId}`);
819
-
820
- if (!sdPromptElement) {
821
- console.error('Element with ID user-storefront-prompt not found');
822
- return;
823
- }
824
-
825
- if (!imageElement) {
826
- console.error('Element with ID generated-image not found');
827
- return;
828
- }
829
-
830
- const sdPrompt = sdPromptElement.value;
831
-
832
- fetch('http://127.0.0.1:5000/generate-image', {
833
- method: 'POST',
834
- headers: {
835
- 'Content-Type': 'application/json'
836
- },
837
- body: JSON.stringify({ sd_prompt: sdPrompt })
838
- })
839
- .then(response => response.json())
840
- .then(data => {
841
- console.log('Received data:', data);
842
- imageElement.src = data.image_url;
843
- imageElement.style.display = 'block';
844
-
845
- // Log the image element's HTML structure
846
- console.log('Updated imageElement HTML:', imageElement.outerHTML);
847
- })
848
- .catch((error) => {
849
- console.error('Error:', error);
850
- });
851
- }
852
-
853
- function handleDragStart(e) {
854
- const target = e.target.closest('.block-item, .block-content');
855
- if (!target) {
856
- console.error('Drag started for an element without a valid target');
857
- return;
858
- }
859
- const blockId = target.getAttribute('data-block-id');
860
- const pageId = target.getAttribute('data-page-id');
861
- if (!blockId) {
862
- console.error('Drag started for an element without a data-block-id');
863
- return;
864
- }
865
- if (!pageId) {
866
- console.error('Drag started for an element without a data-page-id');
867
- return;
868
- }
869
- const innerHTML = target.innerHTML;
870
- e.dataTransfer.setData('block-id', blockId);
871
- e.dataTransfer.setData('text/plain', innerHTML); // Store inner HTML
872
- e.dataTransfer.setData('data-page-id', pageId); // Store original page ID
873
- e.dataTransfer.effectAllowed = 'move';
874
- target.style.opacity = '0.4';
875
-
876
- // Create an invisible drag image
877
- const dragImage = document.createElement('div');
878
- dragImage.style.width = '1px';
879
- dragImage.style.height = '1px';
880
- dragImage.style.opacity = '0';
881
- document.body.appendChild(dragImage);
882
- e.dataTransfer.setDragImage(dragImage, 0, 0);
883
-
884
- console.log(`Drag started for block ID: ${blockId} page ID: ${pageId}`);
885
- }
886
-
887
- function handleDragEnd(e) {
888
- const target = e.target.closest('.block-item, .block-content');
889
- if (target) {
890
- target.style.opacity = '1'; // Reset the opacity
891
- const blockId = target.getAttribute('data-block-id');
892
- console.log(`Drag ended for block ID: ${blockId}`);
893
- }
894
-
895
- // Remove highlight classes from pages and blocks
896
- document.querySelectorAll('.highlight-page').forEach(el => el.classList.remove('highlight-page'));
897
- document.querySelectorAll('.highlight-block').forEach(el => el.classList.remove('highlight-block'));
898
- document.querySelectorAll('.highlight-block-top').forEach(el => el.classList.remove('highlight-block-top'));
899
- }
900
-
901
- function handleDragOver(e) {
902
- e.preventDefault();
903
- e.dataTransfer.dropEffect = 'move';
904
- console.log('Drag over event');
905
-
906
- const targetPage = e.target.closest('.page');
907
- if (targetPage) {
908
- targetPage.classList.add('highlight-page'); // Add highlight class for pages
909
- }
910
-
911
- const targetBlock = e.target.closest('.block-item, .block-content');
912
- if (targetBlock) {
913
- const bounding = targetBlock.getBoundingClientRect();
914
- const offset = e.clientY - bounding.top;
915
- if (offset > bounding.height / 2) {
916
- targetBlock.classList.add('highlight-block');
917
- targetBlock.classList.remove('highlight-block-top');
918
- } else {
919
- targetBlock.classList.add('highlight-block-top');
920
- targetBlock.classList.remove('highlight-block');
921
- }
922
- }
923
- }
924
-
925
- function handleDrop(e) {
926
- e.preventDefault();
927
- const blockId = e.dataTransfer.getData('block-id');
928
- const originalPageId = e.dataTransfer.getData('data-page-id');
929
- const innerHTML = e.dataTransfer.getData('text/plain');
930
- console.log(`Drop event for block ID: ${blockId} from page ID: ${originalPageId}`);
931
-
932
- // Ensure we are not dropping into a textarea or another block
933
- if (event.target.classList.contains('block-item', 'block-content') || event.target.tagName === 'TEXTAREA') {
934
- console.log('Cannot drop block inside another block or textarea');
935
- return;
936
- }
937
-
938
- if (blockId && originalPageId) {
939
- const originalBlock = document.querySelector(`[data-block-id="${blockId}"]`);
940
- const newPage = e.target.closest('.page');
941
- console.log(`Over page ${newPage} from page ID: ${originalPageId}`);
942
- const newPageId = newPage.getAttribute('data-page-id');
943
-
944
- // Ensure the original block exists before proceeding
945
- if (!originalBlock || !newPage) {
946
- console.error(`Block with ID ${blockId} on page ${originalPageId} not found`);
947
- return;
948
- }
949
-
950
- const newBlockContent = document.createElement('div');
951
- newBlockContent.classList.add('block-content');
952
- newBlockContent.innerHTML = originalBlock.innerHTML; // Transfer inner content only
953
-
954
- // Add necessary attributes and event listeners
955
- newBlockContent.setAttribute('data-block-id', blockId);
956
- newBlockContent.setAttribute('data-page-id', newPageId);
957
- console.log('newPageID:', newPageId);
958
- newBlockContent.setAttribute('draggable', true);
959
- newBlockContent.addEventListener('dragstart', handleDragStart);
960
- newBlockContent.addEventListener('dragend', handleDragEnd);
961
-
962
- const target = e.target.closest('.block-item, .block-content');
963
- let targetColumn = 1;
964
- if (target) {
965
- const bounding = target.getBoundingClientRect();
966
- const offset = e.clientY - bounding.top;
967
-
968
- console.log('Drop target found:', target);
969
- console.log('Bounding rectangle:', bounding);
970
- console.log('Offset from top:', offset);
971
- console.log('Target height:', bounding.height);
972
- console.log('Insert before or after decision point (height / 2):', bounding.height / 2);
973
-
974
- targetColumn = getColumnFromOffset(target, offset);
975
- if (offset > bounding.height / 2) {
976
- console.log('Inserting after the target');
977
- target.parentNode.insertBefore(newBlockContent, target.nextSibling);
978
- } else {
979
- console.log('Inserting before the target');
980
- target.parentNode.insertBefore(newBlockContent, target);
981
- }
982
-
983
- // Remove highlight borders
984
- target.style['border-bottom'] = '';
985
- target.style['border-top'] = '';
986
- } else {
987
- console.log('No valid drop target found, appending to the end');
988
- newPage.querySelector('.block.monster.frame.wide').appendChild(newBlockContent);
989
- }
990
-
991
- // Remove the original block from the original container
992
- originalBlock.parentNode.removeChild(originalBlock);
993
-
994
- // Reset opacity of dragged element
995
- newBlockContent.style.opacity = '1';
996
- console.log(`Moved existing block with ID: ${blockId} to page ID: ${newPageId}`);
997
- initializeTextareaResizing();
998
- // Adjust layouts
999
- if (originalPageId !== 'block-container') {
1000
- adjustPageLayout(originalPageId);
1001
- }
1002
- adjustPageLayout(newPageId, targetColumn);
1003
- } else {
1004
- console.log('No data transferred');
1005
- }
1006
- }
1007
-
1008
- function getColumnFromOffset(block, offset) {
1009
- const page = block.closest('.page');
1010
- if (!page) return 1;
1011
- const columnWrapper = page.querySelector('.columnWrapper');
1012
- const columnWrapperRect = columnWrapper.getBoundingClientRect();
1013
- const relativeOffset = offset - columnWrapperRect.left; // Calculate the offset relative to the column wrapper
1014
- const columnWidth = columnWrapper.clientWidth / 2; // Assuming two columns
1015
-
1016
- // Log details for debugging
1017
- console.log('Block offset:', offset);
1018
- console.log('Relative offset:', relativeOffset);
1019
-
1020
- const columnNumber = Math.ceil(relativeOffset / columnWidth);
1021
-
1022
- // Ensure the column number is within valid bounds (1 or 2)
1023
- const validColumnNumber = Math.min(Math.max(columnNumber, 1), 2);
1024
- return validColumnNumber;
1025
- }
1026
-
1027
-
1028
- // Function to get the height of a column by index
1029
- function getColumnHeights(pageElement) {
1030
- const columns = [0, 0]; // Assuming two columns for simplicity
1031
- const blocks = pageElement.querySelectorAll('.block-content');
1032
- blocks.forEach(block => {
1033
- const column = getColumnFromOffset(block, block.getBoundingClientRect().left);
1034
- columns[column - 1] += block.offsetHeight;
1035
- });
1036
- return columns;
1037
- }
1038
-
1039
- function adjustPageLayout(pageId) {
1040
- const page = document.querySelector(`[data-page-id="${pageId}"]`);
1041
- if (!page) {
1042
- console.error(`Page with ID ${pageId} not found`);
1043
- return;
1044
- }
1045
-
1046
- const columnHeights = getColumnHeights(page);
1047
- console.log(`Total height of columns in ${pageId}: ${columnHeights}`);
1048
-
1049
- for (let i = 0; i < columnHeights.length; i++) {
1050
- if (columnHeights[i] > MAX_COLUMN_HEIGHT) {
1051
- console.log(`Column ${i + 1} in ${pageId} exceeds max height, total height: ${columnHeights[i]}px`);
1052
- handleColumnOverflow(page, i + 1);
1053
- }
1054
- }
1055
- }
1056
-
1057
- let pageCounter = 1;
1058
- // Function to create new page
1059
- function createNewPage() {
1060
- const newPage = document.createElement('div');
1061
- newPage.classList.add('page');
1062
- newPage.setAttribute('data-page-id', `page-${pageCounter}`);
1063
- newPage.id = `page-${pageCounter}`;
1064
-
1065
- const columnWrapper = document.createElement('div');
1066
- columnWrapper.classList.add('columnWrapper');
1067
-
1068
- const newMonsterFrame = document.createElement('div');
1069
- newMonsterFrame.classList.add('block', 'monster', 'frame', 'wide');
1070
-
1071
- columnWrapper.appendChild(newMonsterFrame);
1072
- newPage.appendChild(columnWrapper);
1073
- pageContainer.appendChild(newPage);
1074
-
1075
- currentPage = newMonsterFrame;
1076
- console.log(`Created new page with ID: ${newPage.id}`);
1077
-
1078
- // Add event listeners to the new currentPage
1079
- currentPage.addEventListener('dragover', handleDragOver);
1080
- currentPage.addEventListener('drop', handleDrop);
1081
-
1082
- pageCounter++;
1083
- return newPage;
1084
- }
1085
-
1086
- function handleColumnOverflow(page, targetColumn) {
1087
- console.log(`Handling overflow for page ID: ${page.getAttribute('data-page-id')} in column ${targetColumn}`);
1088
- const blocks = Array.from(page.querySelectorAll('.block-content'));
1089
- let columnHeights = [0, 0];
1090
- let overflowStartIndex = -1;
1091
-
1092
- // Find the start index where overflow begins in the target column
1093
- blocks.forEach((block, index) => {
1094
- const column = getColumnFromOffset(block, block.getBoundingClientRect().left);
1095
- columnHeights[column - 1] += block.offsetHeight;
1096
- if (columnHeights[targetColumn - 1] > MAX_COLUMN_HEIGHT && overflowStartIndex === -1) {
1097
- overflowStartIndex = index;
1098
- }
1099
- });
1100
-
1101
- // If no overflow, return early
1102
- if (overflowStartIndex === -1) {
1103
- return;
1104
- }
1105
- const overflowBlocks = blocks.slice(overflowStartIndex);
1106
- const overflowHeight = overflowBlocks.reduce((acc, block) => acc + block.offsetHeight, 0);
1107
-
1108
- // If the target column is the first column, check if the second column has enough space
1109
- if (targetColumn === 1) {
1110
- const secondColumnAvailableHeight = MAX_COLUMN_HEIGHT - columnHeights[1];
1111
-
1112
- if (overflowHeight <= secondColumnAvailableHeight) {
1113
- // Move the overflowing blocks to the second column within the same page
1114
- overflowBlocks.forEach(block => {
1115
- const blockWrapper = block.closest('.block.monster.frame.wide');
1116
- if (blockWrapper) {
1117
- blockWrapper.appendChild(block);
1118
- block.setAttribute('data-page-id', page.getAttribute('data-page-id'));
1119
- }
1120
- });
1121
- return;
1122
- }
1123
- }
1124
-
1125
- // Get the next page if it exists
1126
- const nextPage = getNextPage(page);
1127
- if (nextPage) {
1128
- const nextPageBlocks = nextPage.querySelectorAll('.block-content, .block-item');
1129
- let nextPageColumnHeights = [0, 0];
1130
-
1131
- nextPageBlocks.forEach(block => {
1132
- const column = getColumnFromOffset(block, block.getBoundingClientRect().left);
1133
- nextPageColumnHeights[column - 1] += block.offsetHeight;
1134
- });
1135
-
1136
- // Check if there's enough space in the target column of the next page
1137
- if (nextPageColumnHeights[targetColumn - 1] + overflowHeight <= MAX_COLUMN_HEIGHT) {
1138
- const nextPageContainer = nextPage.querySelector('.block.monster.frame.wide');
1139
- overflowBlocks.forEach(block => {
1140
- nextPageContainer.appendChild(block);
1141
- block.setAttribute('data-page-id', nextPage.getAttribute('data-page-id'));
1142
- });
1143
- return;
1144
- }
1145
-
1146
- // If the next page's second column has enough space for overflow from the first column
1147
- if (targetColumn === 1 && nextPageColumnHeights[1] + overflowHeight <= MAX_COLUMN_HEIGHT) {
1148
- const nextPageContainer = nextPage.querySelector('.block.monster.frame.wide');
1149
- overflowBlocks.forEach(block => {
1150
- nextPageContainer.appendChild(block);
1151
- block.setAttribute('data-page-id', nextPage.getAttribute('data-page-id'));
1152
- });
1153
- return;
1154
- }
1155
- }
1156
-
1157
- // Otherwise, create a new page and move the overflowing blocks there
1158
- const newPage = createNewPage();
1159
- if (!newPage) {
1160
- console.error('Failed to create a new page');
1161
- return;
1162
- }
1163
- const newMonsterFrame = newPage.querySelector('.block.monster.frame.wide');
1164
- if (!newMonsterFrame) {
1165
- console.error('New monster frame not found in the new page');
1166
- return;
1167
- }
1168
-
1169
-
1170
- overflowBlocks.forEach(block => {
1171
- newMonsterFrame.appendChild(block);
1172
- });
1173
- console.log(`Moved overflowing blocks to new page with ID: ${newPage.getAttribute('data-page-id')}`);
1174
- }
1175
-
1176
- // Utility function to get the next page element
1177
- function getNextPage(currentPage) {
1178
- const nextPageId = parseInt(currentPage.getAttribute('data-page-id').split('-')[1]) + 1;
1179
- return document.querySelector(`[data-page-id="page-${nextPageId}"]`);
1180
- }
1181
-
1182
- function moveBlockToPage(block, newPageId) {
1183
- block.setAttribute('data-page-id', newPageId);
1184
- const newPage = document.querySelector(`[data-page-id="${newPageId}"] .block-container`);
1185
- newPage.appendChild(block);
1186
- }
1187
-
1188
- // Handle the drop event on the trash area
1189
- function handleTrashDrop(e) {
1190
- e.preventDefault();
1191
- const innerHTML = e.dataTransfer.getData('text/plain');
1192
- const blockId = e.dataTransfer.getData('block-id');
1193
- console.log('Trash Drop event:', e);
1194
- console.log('Dragged block ID to trash:', blockId);
1195
-
1196
- if (innerHTML && blockId) {
1197
- // Find the dragged element and remove it from the DOM
1198
- let draggedElement = document.querySelector(`[data-block-id="${blockId}"].block-content`);
1199
- if (!draggedElement) {
1200
- draggedElement = document.querySelector(`[data-block-id="${blockId}"].block-item`);
1201
- }
1202
- if (draggedElement && draggedElement.parentElement) {
1203
- draggedElement.parentElement.removeChild(draggedElement);
1204
- console.log(`Removed block with ID: ${blockId} from the page`);
1205
- }
1206
-
1207
- // Check if the block already exists in the block-container and remove it if it does
1208
- let existingBlock = blockContainer.querySelector(`[data-block-id="${blockId}"].block-content`);
1209
- if (!existingBlock) {
1210
- existingBlock = blockContainer.querySelector(`[data-block-id="${blockId}"].block-item`);
1211
- }
1212
- if (existingBlock && existingBlock.parentElement) {
1213
- existingBlock.parentElement.removeChild(existingBlock);
1214
- console.log(`Removed duplicate block with ID: ${blockId} from block-container`);
1215
- }
1216
-
1217
- // Create a new block-item to be placed back in the block-container
1218
- const newBlock = document.createElement('div');
1219
- newBlock.classList.add('block-item');
1220
- newBlock.setAttribute('data-block-id', blockId);
1221
- newBlock.setAttribute('data-page-id', 'block-container');
1222
- newBlock.innerHTML = innerHTML;
1223
- newBlock.setAttribute('draggable', true);
1224
- newBlock.addEventListener('dragstart', handleDragStart);
1225
- newBlock.addEventListener('dragend', handleDragEnd);
1226
-
1227
- // Ensure the block is appended to the page wrapper inside blockContainer
1228
- let pageWrapper = blockContainer.querySelector('.page');
1229
- if (!pageWrapper) {
1230
- pageWrapper = document.createElement('div');
1231
- pageWrapper.classList.add('page');
1232
- pageWrapper.setAttribute('data-page-id', 'block-container');
1233
- blockContainer.appendChild(pageWrapper);
1234
- }
1235
-
1236
- // Debugging output
1237
- console.log('Page wrapper:', pageWrapper);
1238
- console.log('New block:', newBlock);
1239
-
1240
- // Find the original position to insert the new block
1241
- const originalPosition = initialPositions.find(pos => pos.id === blockId);
1242
- console.log('Original position:', originalPosition);
1243
-
1244
- if (originalPosition) {
1245
- const blocks = pageWrapper.querySelectorAll('.block-item');
1246
- console.log('Blocks in pageWrapper:', blocks);
1247
- console.log('Inserting at position:', originalPosition.index);
1248
-
1249
- if (originalPosition.index < blocks.length) {
1250
- const referenceNode = blocks[originalPosition.index];
1251
- if (referenceNode && referenceNode.parentNode === pageWrapper) {
1252
- console.log('Inserting before block at index:', originalPosition.index);
1253
- pageWrapper.insertBefore(newBlock, referenceNode);
1254
- console.log(`Moved block back to original position ${originalPosition.index} in block-container`);
1255
- } else {
1256
- console.warn('Reference node does not belong to pageWrapper, appending to the end');
1257
- pageWrapper.appendChild(newBlock);
1258
- console.log('Appended block to the end of block-container');
1259
- }
1260
- } else {
1261
- console.log('Appending block to the end of pageWrapper');
1262
- pageWrapper.appendChild(newBlock);
1263
- console.log('Appended block to the end of block-container');
1264
- }
1265
- } else {
1266
- console.log('Original position not found, appending block to the end of pageWrapper');
1267
- pageWrapper.appendChild(newBlock);
1268
- console.log('Appended block to the end of block-container');
1269
- }
1270
-
1271
- console.log(`Restored block with ID: ${blockId}`);
1272
- } else {
1273
- console.log('No data transferred');
1274
- }
1275
-
1276
- // Remove the "over" class and reset the background image
1277
- trashArea.classList.remove('over');
1278
- trashArea.style.backgroundImage = "url('./closed-mimic-trashcan.png')";
1279
- initializeTextareaResizing();
1280
- }
1281
-
1282
- function handleTrashOver(e) {
1283
- e.preventDefault();
1284
- e.dataTransfer.dropEffect = 'move';
1285
- trashArea.classList.add('over');
1286
- trashArea.style.backgroundImage = "url('./mimic_trashcan.png')";
1287
- console.log('Trash over event');
1288
- }
1289
-
1290
- function handleTrashLeave(e) {
1291
- trashArea.classList.remove('over');
1292
- trashArea.style.backgroundImage = "url('./closed-mimic-trashcan.png')";
1293
- console.log('Trash leave event');
1294
- }
1295
-
1296
- function handleReset() {
1297
- console.log('Reset button clicked');
1298
-
1299
- // Collect all blocks from all pages
1300
- const allBlocks = [];
1301
- const pages = document.querySelectorAll('.page');
1302
- pages.forEach(page => {
1303
- const blocksOnPage = page.querySelectorAll('[data-block-id]');
1304
- blocksOnPage.forEach(block => {
1305
- const blockId = block.getAttribute('data-block-id');
1306
- allBlocks.push({
1307
- id: blockId,
1308
- innerHTML: block.innerHTML
1309
- });
1310
- block.remove();
1311
- console.log(`Removed block with ID: ${blockId} from page ID: ${page.getAttribute('data-page-id')}`);
1312
- });
1313
- });
1314
-
1315
- // Clear all pages
1316
- pages.forEach(page => page.remove());
1317
-
1318
- // Clear blockContainer before reinserting blocks
1319
- blockContainer.innerHTML = '';
1320
-
1321
- // Reinsert blocks back into the blockContainer in their original order
1322
- let pageWrapper = blockContainer.querySelector('.page');
1323
- if (!pageWrapper) {
1324
- pageWrapper = document.createElement('div');
1325
- pageWrapper.classList.add('page');
1326
- pageWrapper.setAttribute('id', 'block-page');
1327
- blockContainer.appendChild(pageWrapper);
1328
- }
1329
- // Reassign blockContainerPage to the newly created block-page element
1330
- blockContainerPage = document.getElementById('block-page');
1331
-
1332
- initialPositions.forEach(pos => {
1333
- const blockData = allBlocks.find(block => block.id === pos.id);
1334
- if (blockData) {
1335
- const newBlock = document.createElement('div');
1336
- newBlock.classList.add('block-item');
1337
- newBlock.setAttribute('data-block-id', blockData.id);
1338
- newBlock.setAttribute('data-page-id', 'block-container');
1339
- newBlock.innerHTML = blockData.innerHTML;
1340
- newBlock.setAttribute('draggable', true);
1341
- newBlock.addEventListener('dragstart', handleDragStart);
1342
- newBlock.addEventListener('dragend', handleDragEnd);
1343
-
1344
- const blocks = pageWrapper.querySelectorAll('.block-item');
1345
- if (pos.index < blocks.length) {
1346
- pageWrapper.insertBefore(newBlock, blocks[pos.index]);
1347
- console.log(`Moved block back to original position ${pos.index} in block-container`);
1348
- } else {
1349
- pageWrapper.appendChild(newBlock);
1350
- console.log('Appended block to the end of block-container');
1351
- }
1352
- }
1353
- });
1354
- createNewPage();
1355
-
1356
- console.log('Reset complete, all blocks moved back to block-container');
1357
- initializeTextareaResizing();
1358
- }
1359
-
1360
- pageContainer.addEventListener('dragover', handleDragOver);
1361
- pageContainer.addEventListener('drop', handleDrop);
1362
-
1363
- trashArea.addEventListener('dragover', handleTrashOver);
1364
- trashArea.addEventListener('dragleave', handleTrashLeave);
1365
- trashArea.addEventListener('drop', handleTrashDrop);
1366
- resetButton.addEventListener('click', handleReset);
1367
- extractBlocks();
1368
- });
1369
 
1370
  </script>
1371
  </body>
 
8
  <link href='./dependencies/bundle.css' rel='stylesheet' />
9
  <link href="./dependencies/style.css" rel='stylesheet' />
10
  <link href="./dependencies/5ePHBstyle.css" rel='stylesheet' />
11
+ <link href="./storeUI.css" rel='stylesheet' />
12
  <title>DnD Stat Block</title>
13
  <link rel="stylesheet" href="styles.css">
14
  <script src="https://unpkg.com/[email protected]/dist/htmx.min.js"></script>
15
  </head>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  <body>
18
  <div class="grid-container">
19
  <div class="block-container" id="blockContainer" >
 
51
  <img class="modal-content" id="modalImage">
52
  <div id="caption"></div>
53
  </div>
54
+ <script src="scripts.js"></script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  </script>
57
  </body>