diff --git a/index.html b/index.html
index fe97e2b5..cf9151c7 100644
--- a/index.html
+++ b/index.html
@@ -1245,7 +1245,7 @@
function renderChips(containerId, values, filterKey, initialLimit = null) {
const container = document.getElementById(containerId);
- container.innerHTML = '';
+ container.replaceChildren();
const toShow = initialLimit ? values.slice(0, initialLimit) : values;
const rest = initialLimit ? values.slice(initialLimit) : [];
@@ -1309,13 +1309,18 @@
// ── Rendering ──────────────────────────────────────
function renderGrid() {
- gridEl.innerHTML = '';
+ gridEl.replaceChildren();
const slice = state.filtered.slice(0, state.pageSize);
if (slice.length === 0) {
const empty = document.createElement('div');
empty.className = 'empty-state';
- empty.innerHTML = '🔍
No exercises found
';
+ const icon = document.createElement('p');
+ icon.textContent = '🔍';
+ const message = document.createElement('p');
+ message.textContent = 'No exercises found';
+ empty.appendChild(icon);
+ empty.appendChild(message);
gridEl.appendChild(empty);
spinnerEl.classList.remove('visible');
return;
@@ -1397,17 +1402,24 @@
}
function renderSkeletons(count) {
- gridEl.innerHTML = '';
+ gridEl.replaceChildren();
const frag = document.createDocumentFragment();
for (let i = 0; i < count; i++) {
const card = document.createElement('div');
card.className = 'skeleton-card';
- card.innerHTML = `
-
- `;
+ const media = document.createElement('div');
+ media.className = 'skeleton-media';
+ const body = document.createElement('div');
+ body.className = 'skeleton-body';
+ const line = document.createElement('div');
+ line.className = 'skeleton-line';
+ const shortLine = document.createElement('div');
+ shortLine.className = 'skeleton-line short';
+
+ body.appendChild(line);
+ body.appendChild(shortLine);
+ card.appendChild(media);
+ card.appendChild(body);
frag.appendChild(card);
}
gridEl.appendChild(frag);
@@ -1423,7 +1435,7 @@
}
function updateActiveBadges() {
- activeFilEl.innerHTML = '';
+ activeFilEl.replaceChildren();
const { category, equipment, target } = state.filters;
let hasAny = false;
@@ -1432,7 +1444,15 @@
hasAny = true;
const badge = document.createElement('span');
badge.className = 'active-badge';
- badge.innerHTML = `${val}`;
+ const removeBtn = document.createElement('button');
+ removeBtn.className = 'active-badge-remove';
+ removeBtn.dataset.filter = key;
+ removeBtn.dataset.value = val;
+ removeBtn.setAttribute('aria-label', `Remove ${val}`);
+ removeBtn.textContent = '×';
+
+ badge.appendChild(document.createTextNode(val));
+ badge.appendChild(removeBtn);
activeFilEl.appendChild(badge);
});
};
@@ -1473,7 +1493,7 @@
modalGif.alt = ex.name;
// Meta chips
- modalMeta.innerHTML = '';
+ modalMeta.replaceChildren();
const metaItems = [
{ label: 'Body Part', value: ex.body_part || ex.category },
{ label: 'Equipment', value: ex.equipment },
@@ -1482,12 +1502,20 @@
metaItems.forEach(({ label, value }) => {
const chip = document.createElement('div');
chip.className = 'meta-chip';
- chip.innerHTML = `${label}${value}`;
+ const labelEl = document.createElement('span');
+ labelEl.className = 'meta-chip-label';
+ labelEl.textContent = label;
+ const valueEl = document.createElement('span');
+ valueEl.className = 'meta-chip-value';
+ valueEl.textContent = value;
+
+ chip.appendChild(labelEl);
+ chip.appendChild(valueEl);
modalMeta.appendChild(chip);
});
// Muscles
- modalMuscles.innerHTML = '';
+ modalMuscles.replaceChildren();
const primaryMuscles = ex.target ? [ex.target] : [];
const secondaryRaw = ex.secondary_muscles || (ex.muscle_group ? [ex.muscle_group] : []);
const secondaryMuscles = secondaryRaw.filter(m => m !== ex.target);
@@ -1524,7 +1552,7 @@
if (primaryMuscles.length > 0 || secondaryMuscles.length > 0) modalMuscles.appendChild(musclesGrid);
// Instructions — format is always { en: [...], es: [...], it: [...], tr: [...], ru: [...] }
- modalInstr.innerHTML = '';
+ modalInstr.replaceChildren();
const LANG_LABELS = { en: 'English', es: 'Español', it: 'Italiano', tr: 'Türkçe', ru: 'Русский', zh: '简体中文' };
const langs = ['en', 'es', 'it', 'tr', 'ru', 'zh']
.map(code => ({ code, steps: ex.instruction_steps?.[code] ?? [] }))
@@ -1540,11 +1568,19 @@
list.className = 'instructions-list';
function renderSteps(steps) {
- list.innerHTML = '';
+ list.replaceChildren();
steps.forEach((step, i) => {
const li = document.createElement('li');
li.className = 'instruction-step';
- li.innerHTML = `${i + 1}${step}`;
+ const stepNum = document.createElement('span');
+ stepNum.className = 'step-num';
+ stepNum.textContent = String(i + 1);
+ const stepText = document.createElement('span');
+ stepText.className = 'step-text';
+ stepText.textContent = step;
+
+ li.appendChild(stepNum);
+ li.appendChild(stepText);
list.appendChild(li);
});
}
diff --git a/setup.html b/setup.html
index 7a5b82d9..69fe13bd 100644
--- a/setup.html
+++ b/setup.html
@@ -1638,6 +1638,32 @@ Ask Your LLM
const llmPromptBox = document.getElementById('llm-prompt');
const copyPromptBtn = document.getElementById('copy-prompt-btn');
+function setCopyPromptButtonDefault() {
+ const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ svg.setAttribute('width', '14');
+ svg.setAttribute('height', '14');
+ svg.setAttribute('viewBox', '0 0 16 16');
+ svg.setAttribute('fill', 'none');
+ svg.setAttribute('stroke', 'currentColor');
+ svg.setAttribute('stroke-width', '1.8');
+ svg.setAttribute('stroke-linecap', 'round');
+ svg.setAttribute('stroke-linejoin', 'round');
+
+ const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
+ rect.setAttribute('x', '4');
+ rect.setAttribute('y', '4');
+ rect.setAttribute('width', '9');
+ rect.setAttribute('height', '11');
+ rect.setAttribute('rx', '1.5');
+
+ const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+ path.setAttribute('d', 'M11 4V3a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h1');
+
+ svg.appendChild(rect);
+ svg.appendChild(path);
+ copyPromptBtn.replaceChildren(svg, document.createTextNode(' Copy Prompt'));
+}
+
function renderLlmPrompt() {
llmPromptBox.value = buildLlmPrompt(currentFw, currentLlmDb);
}
@@ -1665,7 +1691,7 @@ Ask Your LLM
copyPromptBtn.textContent = '✓ Copied!';
copyPromptBtn.classList.add('copied');
setTimeout(() => {
- copyPromptBtn.innerHTML = ` Copy Prompt`;
+ setCopyPromptButtonDefault();
copyPromptBtn.classList.remove('copied');
}, 2500);
});