feat(biochem): skeleton loaders for async fetches

Replace plain "Загрузка..." placeholders with shimmer-animated skeletons
matching the actual layout shape:
- library: 12 placeholder cards (canvas + 2 lines)
- reactions: 6 row skeletons (stripe + title + 2 text lines)
- properties: 10 sidebar row shimmers (thumb + 2 lines)
- biochem editor: 4-5 row skeletons for saved-molecules and challenges lists

No existing skeleton classes in ls.css; added local .bc-sk-* helpers per page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-20 19:49:54 +03:00
parent d3b1cd75a0
commit 29ef974e35
4 changed files with 139 additions and 21 deletions
+31 -8
View File
@@ -209,6 +209,26 @@
}
.detail-open-btn:hover { background: linear-gradient(135deg, rgba(155,93,229,.4), rgba(6,214,224,.25)); border-color: rgba(6,214,224,.5); color: #fff; }
/* ── Shimmer skeleton ── */
@keyframes bc-shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
.bc-sk {
background: linear-gradient(90deg,
rgba(255,255,255,0.04) 0%,
rgba(255,255,255,0.10) 50%,
rgba(255,255,255,0.04) 100%);
background-size: 200% 100%;
animation: bc-shimmer 1.6s infinite;
border-radius: 8px;
}
.bc-sk-square { aspect-ratio: 1; }
.bc-sk-line { height: 12px; margin: 6px 0; }
.bc-sk-line.sm { width: 60%; }
.bc-sk-line.md { width: 80%; }
.bc-sk-card { padding: 12px; border: 1px solid rgba(255,255,255,.06); border-radius: 10px; }
/* Empty state */
.lib-empty {
grid-column: 1/-1;
@@ -294,14 +314,7 @@
<!-- Content -->
<div class="lib-main">
<div class="lib-scroll" id="lib-scroll">
<div class="lib-grid" id="lib-grid">
<div class="lib-empty">
<svg width="56" height="56" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.3">
<circle cx="12" cy="12" r="3"/><path d="M2 12h3M19 12h3M12 2v3M12 19v3"/>
</svg>
<p>Загрузка молекул…</p>
</div>
</div>
<div class="lib-grid" id="lib-grid"></div>
</div>
<!-- Detail panel -->
@@ -470,7 +483,17 @@ let selectedId = null;
const CAT_LABELS = { inorganic:'Неорганика', organic:'Органика', biomolecule:'Биомолекулы' };
const DIFF_STARS = ['', '<svg class="ic" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>', '<svg class="ic" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg><svg class="ic" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>', '<svg class="ic" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg><svg class="ic" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg><svg class="ic" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>'];
function bcSkLibrary(n = 12) {
return Array.from({length: n}, () => `
<div class="bc-sk-card">
<div class="bc-sk bc-sk-square" style="margin-bottom:8px"></div>
<div class="bc-sk bc-sk-line md"></div>
<div class="bc-sk bc-sk-line sm"></div>
</div>`).join('');
}
async function init() {
document.getElementById('lib-grid').innerHTML = bcSkLibrary(12);
try {
[allMols, allReactions] = await Promise.all([
LS.biochemGetMolecules(),