Add AMD CPU support (CSV import + TechPowerUp scraper), fix alternatives accordion, untrack database.db

This commit is contained in:
2026-04-13 11:19:31 +02:00
parent 2afdb15d53
commit eedb96c53a
4 changed files with 408 additions and 13 deletions

View File

@@ -162,6 +162,18 @@
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
/* ── Alternatives ───────────────────────────────────────────── */
.alt-accordion { border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 16px; overflow: hidden; transition: border-color .2s, box-shadow .2s; }
.alt-accordion.has-deal { border-color: #f59e0b; box-shadow: 0 0 0 2px rgba(245,158,11,.18); }
.alt-accordion-hdr { display: flex; align-items: center; gap: 8px; padding: 11px 14px; cursor: pointer; user-select: none; font-weight: 600; font-size: 13px; background: var(--surface); }
.alt-accordion-hdr:hover { background: var(--card); }
.alt-accordion.has-deal .alt-accordion-hdr { background: rgba(245,158,11,.08); }
.alt-accordion-hdr .alt-hdr-icon { font-size: 14px; }
.alt-accordion-hdr .alt-count { background: var(--accent); color: #fff; font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 10px; }
.alt-accordion.has-deal .alt-accordion-hdr .alt-count { background: #f59e0b; }
.alt-accordion-hdr .alt-chevron { margin-left: auto; font-size: 10px; color: var(--muted); transition: transform .2s; }
.alt-accordion.open .alt-chevron { transform: rotate(180deg); }
.alt-accordion-body { display: none; padding: 0 14px 12px; }
.alt-accordion.open .alt-accordion-body { display: block; }
.alt-group-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); margin: 14px 0 6px; }
.alt-card { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; transition: border-color .15s; margin-bottom: 6px; }
.alt-card:hover { border-color: var(--accent); }
@@ -680,6 +692,8 @@ async function loadDetail(id) {
</a>
</div>
<div id="alt-section"></div>
<!-- Display -->
<div class="detail-section">
<h3>Display</h3>
@@ -781,16 +795,15 @@ async function loadDetail(id) {
${specItem('Eco Cert', l.eco_cert)}
</div>
</div>
<div id="alt-section"></div>
`;
$('detail-overlay').classList.add('open');
$('detail-panel').classList.add('open');
loadAlternatives(id);
loadAlternatives(id, l.price_sek);
}
// ── Alternatives panel ───────────────────────────────────────────────────
async function loadAlternatives(id) {
async function loadAlternatives(id, currentPrice) {
const section = $('alt-section');
if (!section) return;
try {
@@ -800,7 +813,13 @@ async function loadAlternatives(id) {
const better = data.better_spec_same_price || [];
if (!cheaper.length && !better.length) return;
const renderCard = (a, type) => {
// Hot deal: any alternative is ≥15% cheaper, or any better-spec alternative exists
const hasDeal = cheaper.some(a => currentPrice && a.price_sek <= currentPrice * 0.85)
|| better.length > 0;
const totalCount = cheaper.length + better.length;
const icon = hasDeal ? '🔥 ' : '✦ ';
const renderAltCard = (a, type) => {
const imgs = Array.isArray(a.image_urls) ? a.image_urls : [];
const thumb = imgs[0]
? `<img class="alt-card-thumb" src="${escHtml(imgs[0])}" loading="lazy">`
@@ -829,17 +848,26 @@ async function loadAlternatives(id) {
</div>`;
};
let html = '<div class="detail-section"><h3>Alternatives</h3>';
let cardsHtml = '';
if (cheaper.length) {
html += `<div class="alt-group-label">Same specs \u2014 lower price</div>`;
html += cheaper.map(a => renderCard(a, 'cheaper')).join('');
cardsHtml += `<div class="alt-group-label">Same specs \u2014 lower price</div>`;
cardsHtml += cheaper.map(a => renderAltCard(a, 'cheaper')).join('');
}
if (better.length) {
html += `<div class="alt-group-label">Same price \u2014 better specs</div>`;
html += better.map(a => renderCard(a, 'better')).join('');
cardsHtml += `<div class="alt-group-label">Same price \u2014 better specs</div>`;
cardsHtml += better.map(a => renderAltCard(a, 'better')).join('');
}
html += '</div>';
section.innerHTML = html;
section.className = 'alt-accordion' + (hasDeal ? ' has-deal open' : '');
section.innerHTML = `
<div class="alt-accordion-hdr" onclick="this.closest('.alt-accordion').classList.toggle('open')">
<span class="alt-hdr-icon">${icon}</span>
<span>Alternatives</span>
<span class="alt-count">${totalCount}</span>
<span class="alt-chevron">▼</span>
</div>
<div class="alt-accordion-body">${cardsHtml}</div>
`;
} catch (e) {
console.error('Failed to load alternatives', e);
}