Spaces:
Running
Running
Update index.html
Browse files- index.html +207 -46
index.html
CHANGED
@@ -45,7 +45,7 @@ body.dark{
|
|
45 |
--desk-bg: #2c2a27;
|
46 |
--desk-dot: #3a3733;
|
47 |
|
48 |
-
--paper-bg: #
|
49 |
--paper-text: #e9e7e2;
|
50 |
--shadow: rgba(0,0,0,.55);
|
51 |
|
@@ -139,12 +139,10 @@ h1{font-family:'Libre Baskerville',serif;margin:0;font-size:28px;letter-spacing:
|
|
139 |
gap:16px;
|
140 |
overflow:visible;
|
141 |
|
142 |
-
/*
|
143 |
align-items:start;
|
144 |
|
145 |
-
/*
|
146 |
-
--cols: 1 -> one column (full width), 2 -> two columns (50/50),
|
147 |
-
else auto-fit with a sensible min width */
|
148 |
grid-template-columns: repeat(var(--cols, auto-fit), minmax(var(--minCol, 220px), 1fr));
|
149 |
}
|
150 |
#board::before{
|
@@ -176,8 +174,7 @@ h1{font-family:'Libre Baskerville',serif;margin:0;font-size:28px;letter-spacing:
|
|
176 |
transform:rotate(var(--tilt,0deg)) scale(1);
|
177 |
transition:transform .12s ease, box-shadow .12s ease, opacity .16s ease;
|
178 |
animation:pop .18s ease-out;
|
179 |
-
|
180 |
-
align-self:start;
|
181 |
}
|
182 |
.sticky:hover{
|
183 |
transform:rotate(var(--tilt,0deg)) translateY(-2px) scale(1.01);
|
@@ -212,8 +209,7 @@ body.dark .badge{background:rgba(255,255,255,.12)}
|
|
212 |
display:block;
|
213 |
border-bottom-left-radius:10px;border-bottom-right-radius:10px;
|
214 |
background: linear-gradient(180deg,rgba(255,255,255,.25),rgba(255,255,255,0));
|
215 |
-
/*
|
216 |
-
max-height:80vh;
|
217 |
}
|
218 |
|
219 |
/* delete button */
|
@@ -245,7 +241,6 @@ body.dark .badge{background:rgba(255,255,255,.12)}
|
|
245 |
@media(max-width:768px){
|
246 |
.container{margin:20px 16px;padding:24px}
|
247 |
h1{font-size:24px}
|
248 |
-
/* CHANGED: still use dynamic columns on mobile, but with a smaller min */
|
249 |
#board{
|
250 |
grid-template-columns: repeat(var(--cols, auto-fit), minmax(180px,1fr));
|
251 |
}
|
@@ -283,21 +278,30 @@ body.dark .badge{background:rgba(255,255,255,.12)}
|
|
283 |
<div class="processing">Processing…</div>
|
284 |
|
285 |
<script>
|
286 |
-
/* =======
|
287 |
const board = document.getElementById('board');
|
288 |
const processingNode = document.querySelector('.processing');
|
289 |
const themeBtn = document.getElementById('themeToggle');
|
290 |
|
291 |
let noteCount = 0;
|
292 |
|
293 |
-
|
294 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
|
|
|
296 |
function removePlaceholder(){
|
297 |
const ph = board.querySelector('.placeholder');
|
298 |
if(ph) ph.remove();
|
299 |
}
|
300 |
-
|
301 |
function ensurePlaceholder(){
|
302 |
if(!board.querySelector('.sticky') && !board.querySelector('.placeholder')){
|
303 |
const ph = document.createElement('div');
|
@@ -307,25 +311,22 @@ function ensurePlaceholder(){
|
|
307 |
}
|
308 |
}
|
309 |
|
310 |
-
/*
|
311 |
function updateLayout(){
|
312 |
const count = board.querySelectorAll('.sticky').length;
|
313 |
if(count === 1){
|
314 |
-
// 1 image → full width (one column)
|
315 |
board.style.setProperty('--cols', '1');
|
316 |
board.style.setProperty('--minCol', '0px');
|
317 |
}else if(count === 2){
|
318 |
-
// 2 images → half/half
|
319 |
board.style.setProperty('--cols', '2');
|
320 |
board.style.setProperty('--minCol', '0px');
|
321 |
}else{
|
322 |
-
// 3+ → responsive, nice min width
|
323 |
board.style.setProperty('--cols', 'auto-fit');
|
324 |
board.style.setProperty('--minCol', '220px');
|
325 |
}
|
326 |
}
|
327 |
|
328 |
-
/* random
|
329 |
function randTilt(){
|
330 |
const d = (Math.random()*4.4 - 2.2).toFixed(2);
|
331 |
return d + 'deg';
|
@@ -334,41 +335,178 @@ function pickColorClass(){
|
|
334 |
const choices = ['note-yellow','note-mint','note-blush','note-blue'];
|
335 |
return choices[Math.floor(Math.random()*choices.length)];
|
336 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
|
338 |
-
/*
|
339 |
-
function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
340 |
removePlaceholder();
|
341 |
noteCount++;
|
342 |
|
343 |
const wrap = document.createElement('div');
|
344 |
-
const
|
345 |
-
|
346 |
-
wrap.
|
|
|
|
|
347 |
|
348 |
-
// header bar
|
349 |
const bar = document.createElement('div');
|
350 |
bar.className = 'bar';
|
351 |
-
bar.innerHTML = `<span class="badge">Q${noteCount}</span><span style="opacity:.7">
|
352 |
|
353 |
-
// image
|
354 |
const img = document.createElement('img');
|
355 |
img.alt = `Question ${noteCount}`;
|
356 |
img.src = src;
|
357 |
|
358 |
-
// delete button
|
359 |
const btn = document.createElement('button');
|
360 |
btn.className = 'btn-del';
|
361 |
btn.setAttribute('aria-label','Delete sticky');
|
362 |
btn.textContent = '×';
|
363 |
|
364 |
-
btn.addEventListener('click',()=>{
|
365 |
wrap.style.opacity = '0';
|
366 |
wrap.style.transform = 'scale(.96)';
|
|
|
|
|
367 |
setTimeout(()=>{
|
368 |
if(isBlobUrl) URL.revokeObjectURL(src);
|
369 |
wrap.remove();
|
370 |
ensurePlaceholder();
|
371 |
-
updateLayout();
|
372 |
},140);
|
373 |
});
|
374 |
|
@@ -376,11 +514,9 @@ function createSticky(src, isBlobUrl=false){
|
|
376 |
wrap.appendChild(img);
|
377 |
wrap.appendChild(btn);
|
378 |
board.prepend(wrap); // newest on top
|
379 |
-
|
380 |
-
updateLayout(); // NEW: update grid after adding
|
381 |
}
|
382 |
|
383 |
-
/* ======= handle pasted images ======= */
|
384 |
function filesFromClipboard(dataTransfer){
|
385 |
const items = dataTransfer?.items || [];
|
386 |
const files = [];
|
@@ -395,16 +531,25 @@ function filesFromClipboard(dataTransfer){
|
|
395 |
|
396 |
async function handleImages(files){
|
397 |
if(!files.length){
|
398 |
-
|
399 |
-
|
400 |
-
processingNode.textContent = 'Processing…';
|
401 |
return;
|
402 |
}
|
403 |
-
showProcessing();
|
404 |
for(const file of files){
|
405 |
-
const
|
406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
}
|
|
|
408 |
hideProcessing();
|
409 |
}
|
410 |
|
@@ -451,15 +596,31 @@ function updateIcon(){
|
|
451 |
themeBtn.textContent = document.body.classList.contains('dark') ? '☀️' : '🌙';
|
452 |
}
|
453 |
|
454 |
-
/* =======
|
455 |
-
document.addEventListener('DOMContentLoaded',()=>{
|
456 |
const sheet=document.querySelector('.container');
|
457 |
sheet.style.opacity='0';
|
458 |
-
setTimeout(()=>{
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
463 |
});
|
464 |
</script>
|
465 |
</body>
|
|
|
45 |
--desk-bg: #2c2a27;
|
46 |
--desk-dot: #3a3733;
|
47 |
|
48 |
+
--paper-bg: #302e2b;
|
49 |
--paper-text: #e9e7e2;
|
50 |
--shadow: rgba(0,0,0,.55);
|
51 |
|
|
|
139 |
gap:16px;
|
140 |
overflow:visible;
|
141 |
|
142 |
+
/* prevent short images from becoming tall boxes */
|
143 |
align-items:start;
|
144 |
|
145 |
+
/* dynamic columns via CSS vars set from JS */
|
|
|
|
|
146 |
grid-template-columns: repeat(var(--cols, auto-fit), minmax(var(--minCol, 220px), 1fr));
|
147 |
}
|
148 |
#board::before{
|
|
|
174 |
transform:rotate(var(--tilt,0deg)) scale(1);
|
175 |
transition:transform .12s ease, box-shadow .12s ease, opacity .16s ease;
|
176 |
animation:pop .18s ease-out;
|
177 |
+
align-self:start; /* don't stretch tile height */
|
|
|
178 |
}
|
179 |
.sticky:hover{
|
180 |
transform:rotate(var(--tilt,0deg)) translateY(-2px) scale(1.01);
|
|
|
209 |
display:block;
|
210 |
border-bottom-left-radius:10px;border-bottom-right-radius:10px;
|
211 |
background: linear-gradient(180deg,rgba(255,255,255,.25),rgba(255,255,255,0));
|
212 |
+
max-height:80vh; /* keep ultra-tall screenshots sane */
|
|
|
213 |
}
|
214 |
|
215 |
/* delete button */
|
|
|
241 |
@media(max-width:768px){
|
242 |
.container{margin:20px 16px;padding:24px}
|
243 |
h1{font-size:24px}
|
|
|
244 |
#board{
|
245 |
grid-template-columns: repeat(var(--cols, auto-fit), minmax(180px,1fr));
|
246 |
}
|
|
|
278 |
<div class="processing">Processing…</div>
|
279 |
|
280 |
<script>
|
281 |
+
/* ======= DOM refs ======= */
|
282 |
const board = document.getElementById('board');
|
283 |
const processingNode = document.querySelector('.processing');
|
284 |
const themeBtn = document.getElementById('themeToggle');
|
285 |
|
286 |
let noteCount = 0;
|
287 |
|
288 |
+
/* ======= processing UI ======= */
|
289 |
+
function showProcessing(text){
|
290 |
+
if(text) processingNode.textContent = text;
|
291 |
+
processingNode.classList.add('show');
|
292 |
+
}
|
293 |
+
function hideProcessing(){
|
294 |
+
setTimeout(()=>{
|
295 |
+
processingNode.classList.remove('show');
|
296 |
+
processingNode.textContent = 'Processing…';
|
297 |
+
},250);
|
298 |
+
}
|
299 |
|
300 |
+
/* ======= placeholder helpers ======= */
|
301 |
function removePlaceholder(){
|
302 |
const ph = board.querySelector('.placeholder');
|
303 |
if(ph) ph.remove();
|
304 |
}
|
|
|
305 |
function ensurePlaceholder(){
|
306 |
if(!board.querySelector('.sticky') && !board.querySelector('.placeholder')){
|
307 |
const ph = document.createElement('div');
|
|
|
311 |
}
|
312 |
}
|
313 |
|
314 |
+
/* ======= layout: 1 image full width, 2 images 50/50, 3+ responsive ======= */
|
315 |
function updateLayout(){
|
316 |
const count = board.querySelectorAll('.sticky').length;
|
317 |
if(count === 1){
|
|
|
318 |
board.style.setProperty('--cols', '1');
|
319 |
board.style.setProperty('--minCol', '0px');
|
320 |
}else if(count === 2){
|
|
|
321 |
board.style.setProperty('--cols', '2');
|
322 |
board.style.setProperty('--minCol', '0px');
|
323 |
}else{
|
|
|
324 |
board.style.setProperty('--cols', 'auto-fit');
|
325 |
board.style.setProperty('--minCol', '220px');
|
326 |
}
|
327 |
}
|
328 |
|
329 |
+
/* ======= random style bits ======= */
|
330 |
function randTilt(){
|
331 |
const d = (Math.random()*4.4 - 2.2).toFixed(2);
|
332 |
return d + 'deg';
|
|
|
335 |
const choices = ['note-yellow','note-mint','note-blush','note-blue'];
|
336 |
return choices[Math.floor(Math.random()*choices.length)];
|
337 |
}
|
338 |
+
function uuid(){
|
339 |
+
return (crypto?.randomUUID?.() || ('id-' + Math.random().toString(16).slice(2) + Date.now()));
|
340 |
+
}
|
341 |
+
|
342 |
+
/* ======= PERSISTENCE (IndexedDB with localStorage fallback) ======= */
|
343 |
+
const PERSIST = { mode: 'idb' };
|
344 |
+
const DB_NAME = 'question-board';
|
345 |
+
const STORE = 'stickies';
|
346 |
+
let dbConn = null;
|
347 |
+
|
348 |
+
function initDB(){
|
349 |
+
return new Promise((resolve, reject)=>{
|
350 |
+
const req = indexedDB.open(DB_NAME, 1);
|
351 |
+
req.onupgradeneeded = () => {
|
352 |
+
const db = req.result;
|
353 |
+
if(!db.objectStoreNames.contains(STORE)){
|
354 |
+
const store = db.createObjectStore(STORE, { keyPath: 'id' });
|
355 |
+
store.createIndex('createdAt', 'createdAt');
|
356 |
+
}
|
357 |
+
};
|
358 |
+
req.onsuccess = () => resolve(req.result);
|
359 |
+
req.onerror = () => reject(req.error);
|
360 |
+
});
|
361 |
+
}
|
362 |
+
async function initPersistence(){
|
363 |
+
if(!('indexedDB' in window)){
|
364 |
+
PERSIST.mode = 'ls';
|
365 |
+
return;
|
366 |
+
}
|
367 |
+
try{
|
368 |
+
dbConn = await initDB();
|
369 |
+
PERSIST.mode = 'idb';
|
370 |
+
}catch(e){
|
371 |
+
console.warn('IndexedDB unavailable, falling back to localStorage', e);
|
372 |
+
PERSIST.mode = 'ls';
|
373 |
+
}
|
374 |
+
}
|
375 |
+
|
376 |
+
/* --- IndexedDB ops --- */
|
377 |
+
function idbAdd(rec){
|
378 |
+
return new Promise((resolve,reject)=>{
|
379 |
+
const tx = dbConn.transaction(STORE,'readwrite');
|
380 |
+
tx.objectStore(STORE).put(rec);
|
381 |
+
tx.oncomplete = ()=> resolve();
|
382 |
+
tx.onerror = ()=> reject(tx.error);
|
383 |
+
});
|
384 |
+
}
|
385 |
+
function idbGetAll(){
|
386 |
+
return new Promise((resolve,reject)=>{
|
387 |
+
const tx = dbConn.transaction(STORE,'readonly');
|
388 |
+
const idx = tx.objectStore(STORE).index('createdAt');
|
389 |
+
const req = idx.getAll();
|
390 |
+
req.onsuccess = ()=> {
|
391 |
+
const arr = req.result || [];
|
392 |
+
arr.sort((a,b)=> a.createdAt - b.createdAt);
|
393 |
+
resolve(arr);
|
394 |
+
};
|
395 |
+
req.onerror = ()=> reject(req.error);
|
396 |
+
});
|
397 |
+
}
|
398 |
+
function idbDelete(id){
|
399 |
+
return new Promise((resolve,reject)=>{
|
400 |
+
const tx = dbConn.transaction(STORE,'readwrite');
|
401 |
+
tx.objectStore(STORE).delete(id);
|
402 |
+
tx.oncomplete = ()=> resolve();
|
403 |
+
tx.onerror = ()=> reject(tx.error);
|
404 |
+
});
|
405 |
+
}
|
406 |
+
|
407 |
+
/* --- localStorage ops (fallback) --- */
|
408 |
+
function lsMeta(){
|
409 |
+
try{
|
410 |
+
return JSON.parse(localStorage.getItem('stickies-meta')||'[]');
|
411 |
+
}catch{ return []; }
|
412 |
+
}
|
413 |
+
function lsSetMeta(arr){
|
414 |
+
localStorage.setItem('stickies-meta', JSON.stringify(arr));
|
415 |
+
}
|
416 |
+
function fileToDataURL(file){
|
417 |
+
return new Promise((resolve,reject)=>{
|
418 |
+
const r = new FileReader();
|
419 |
+
r.onload = ()=> resolve(r.result);
|
420 |
+
r.onerror = reject;
|
421 |
+
r.readAsDataURL(file);
|
422 |
+
});
|
423 |
+
}
|
424 |
+
function lsAdd(rec){
|
425 |
+
const meta = lsMeta();
|
426 |
+
meta.push({ id: rec.id, createdAt: rec.createdAt, color: rec.color, tilt: rec.tilt });
|
427 |
+
lsSetMeta(meta);
|
428 |
+
localStorage.setItem('sticky-img-' + rec.id, rec.dataUrl);
|
429 |
+
}
|
430 |
+
function lsGetAll(){
|
431 |
+
const meta = lsMeta().sort((a,b)=> a.createdAt - b.createdAt);
|
432 |
+
return meta.map(m => ({
|
433 |
+
id: m.id,
|
434 |
+
createdAt: m.createdAt,
|
435 |
+
color: m.color,
|
436 |
+
tilt: m.tilt,
|
437 |
+
dataUrl: localStorage.getItem('sticky-img-' + m.id)
|
438 |
+
})).filter(r => !!r.dataUrl);
|
439 |
+
}
|
440 |
+
function lsDelete(id){
|
441 |
+
const meta = lsMeta().filter(m => m.id !== id);
|
442 |
+
lsSetMeta(meta);
|
443 |
+
localStorage.removeItem('sticky-img-' + id);
|
444 |
+
}
|
445 |
|
446 |
+
/* --- persist a new file and return its record --- */
|
447 |
+
async function persistFile(file, color, tilt){
|
448 |
+
const rec = { id: uuid(), createdAt: Date.now(), color, tilt };
|
449 |
+
if(PERSIST.mode === 'idb'){
|
450 |
+
// store blob directly
|
451 |
+
await idbAdd({ ...rec, blob: file });
|
452 |
+
return { ...rec, blob: file };
|
453 |
+
}else{
|
454 |
+
// fallback: store base64 (size-limited)
|
455 |
+
const dataUrl = await fileToDataURL(file);
|
456 |
+
lsAdd({ ...rec, dataUrl });
|
457 |
+
return { ...rec, dataUrl };
|
458 |
+
}
|
459 |
+
}
|
460 |
+
async function loadPersisted(){
|
461 |
+
if(PERSIST.mode === 'idb'){
|
462 |
+
return await idbGetAll();
|
463 |
+
}else{
|
464 |
+
return lsGetAll();
|
465 |
+
}
|
466 |
+
}
|
467 |
+
async function deletePersisted(id){
|
468 |
+
if(PERSIST.mode === 'idb'){
|
469 |
+
await idbDelete(id);
|
470 |
+
}else{
|
471 |
+
lsDelete(id);
|
472 |
+
}
|
473 |
+
}
|
474 |
+
|
475 |
+
/* ======= create sticky DOM ======= */
|
476 |
+
function createSticky(src, { isBlobUrl=false, id=null, colorClass=null, tilt=null } = {}){
|
477 |
removePlaceholder();
|
478 |
noteCount++;
|
479 |
|
480 |
const wrap = document.createElement('div');
|
481 |
+
const color = colorClass || pickColorClass();
|
482 |
+
const tlt = tilt || randTilt();
|
483 |
+
wrap.className = `sticky ${color}`;
|
484 |
+
wrap.style.setProperty('--tilt', tlt);
|
485 |
+
if(id) wrap.dataset.id = id;
|
486 |
|
|
|
487 |
const bar = document.createElement('div');
|
488 |
bar.className = 'bar';
|
489 |
+
bar.innerHTML = `<span class="badge">Q${noteCount}</span><span style="opacity:.7">saved</span>`;
|
490 |
|
|
|
491 |
const img = document.createElement('img');
|
492 |
img.alt = `Question ${noteCount}`;
|
493 |
img.src = src;
|
494 |
|
|
|
495 |
const btn = document.createElement('button');
|
496 |
btn.className = 'btn-del';
|
497 |
btn.setAttribute('aria-label','Delete sticky');
|
498 |
btn.textContent = '×';
|
499 |
|
500 |
+
btn.addEventListener('click', async ()=>{
|
501 |
wrap.style.opacity = '0';
|
502 |
wrap.style.transform = 'scale(.96)';
|
503 |
+
const stickyId = wrap.dataset.id;
|
504 |
+
try{ if(stickyId) await deletePersisted(stickyId); }catch(e){ console.warn('Delete failed', e); }
|
505 |
setTimeout(()=>{
|
506 |
if(isBlobUrl) URL.revokeObjectURL(src);
|
507 |
wrap.remove();
|
508 |
ensurePlaceholder();
|
509 |
+
updateLayout();
|
510 |
},140);
|
511 |
});
|
512 |
|
|
|
514 |
wrap.appendChild(img);
|
515 |
wrap.appendChild(btn);
|
516 |
board.prepend(wrap); // newest on top
|
|
|
|
|
517 |
}
|
518 |
|
519 |
+
/* ======= handle pasted or dropped images ======= */
|
520 |
function filesFromClipboard(dataTransfer){
|
521 |
const items = dataTransfer?.items || [];
|
522 |
const files = [];
|
|
|
531 |
|
532 |
async function handleImages(files){
|
533 |
if(!files.length){
|
534 |
+
showProcessing('No images found in clipboard');
|
535 |
+
hideProcessing();
|
|
|
536 |
return;
|
537 |
}
|
538 |
+
showProcessing('Saving…');
|
539 |
for(const file of files){
|
540 |
+
const color = pickColorClass();
|
541 |
+
const tilt = randTilt();
|
542 |
+
// persist first to get an id
|
543 |
+
const rec = await persistFile(file, color, tilt);
|
544 |
+
|
545 |
+
if(PERSIST.mode === 'idb'){
|
546 |
+
const url = URL.createObjectURL(file);
|
547 |
+
createSticky(url, { isBlobUrl:true, id: rec.id, colorClass: color, tilt });
|
548 |
+
}else{
|
549 |
+
createSticky(rec.dataUrl, { isBlobUrl:false, id: rec.id, colorClass: color, tilt });
|
550 |
+
}
|
551 |
}
|
552 |
+
updateLayout();
|
553 |
hideProcessing();
|
554 |
}
|
555 |
|
|
|
596 |
themeBtn.textContent = document.body.classList.contains('dark') ? '☀️' : '🌙';
|
597 |
}
|
598 |
|
599 |
+
/* ======= boot: fade in and load saved stickies ======= */
|
600 |
+
document.addEventListener('DOMContentLoaded', async ()=>{
|
601 |
const sheet=document.querySelector('.container');
|
602 |
sheet.style.opacity='0';
|
603 |
+
setTimeout(()=>{sheet.style.transition='opacity .6s ease';sheet.style.opacity='1'},80);
|
604 |
+
|
605 |
+
showProcessing('Loading saved…');
|
606 |
+
await initPersistence();
|
607 |
+
|
608 |
+
try{
|
609 |
+
const saved = await loadPersisted(); // ascending by createdAt
|
610 |
+
for(const rec of saved){
|
611 |
+
if(PERSIST.mode === 'idb'){
|
612 |
+
const url = URL.createObjectURL(rec.blob);
|
613 |
+
createSticky(url, { isBlobUrl:true, id: rec.id, colorClass: rec.color, tilt: rec.tilt });
|
614 |
+
}else{
|
615 |
+
createSticky(rec.dataUrl, { isBlobUrl:false, id: rec.id, colorClass: rec.color, tilt: rec.tilt });
|
616 |
+
}
|
617 |
+
}
|
618 |
+
}catch(e){
|
619 |
+
console.warn('Load failed', e);
|
620 |
+
}
|
621 |
+
|
622 |
+
updateLayout();
|
623 |
+
hideProcessing();
|
624 |
});
|
625 |
</script>
|
626 |
</body>
|