Files
prestashop-icons/preview.html
myprestarocks d694f9f21f Fix source file naming, rebuild sprites, add dev tools
- Fix bank_transfer -> bank naming in icon/square shapes
- Fix quote_la -> quote_lm in light-mode directories
- Fix rectangle naming (amazon_pay, bacs, naverpay, p24)
- Fix case sensitivity (LinkedIn -> linkedin, Bancontact -> bancontact, etc.)
- Add _lm suffix to rectangle/light-mode files
- Copy X icon to full-logo and text-only (same symbol)
- Add preview.html for visual testing
- Add .htaccess restricting access to dev IP
- Update README with correct lowercase brand names

All 38 payment brands and 12 social brands now complete.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 11:27:17 +00:00

326 lines
14 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PrestaShop Icons Preview</title>
<style>
* { box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
margin: 0; padding: 20px;
background: #f5f5f5;
color: #333;
transition: background 0.3s, color 0.3s;
}
body.dark-theme {
background: #1a1a1a;
color: #eee;
}
h1 { margin: 0 0 20px; }
h2 { margin: 30px 0 10px; padding: 10px; background: #333; color: #fff; border-radius: 4px; }
body.dark-theme h2 { background: #444; }
h3 { margin: 20px 0 10px; color: #666; border-bottom: 1px solid #ddd; padding-bottom: 5px; }
body.dark-theme h3 { color: #aaa; border-color: #444; }
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.theme-switch {
display: flex;
align-items: center;
gap: 10px;
}
.switch {
position: relative;
width: 60px;
height: 30px;
}
.switch input { opacity: 0; width: 0; height: 0; }
.slider {
position: absolute;
cursor: pointer;
top: 0; left: 0; right: 0; bottom: 0;
background: #ccc;
border-radius: 30px;
transition: 0.3s;
}
.slider:before {
position: absolute;
content: "";
height: 22px;
width: 22px;
left: 4px;
bottom: 4px;
background: white;
border-radius: 50%;
transition: 0.3s;
}
input:checked + .slider { background: #333; }
input:checked + .slider:before { transform: translateX(30px); }
.theme-label { font-size: 14px; }
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.icon-box {
background: #fff;
border: 1px solid #ddd;
border-radius: 8px;
padding: 15px;
text-align: center;
transition: all 0.3s;
}
body.dark-theme .icon-box {
background: #2a2a2a;
border-color: #444;
}
.icon-box:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
body.dark-theme .icon-box:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.5); }
.icon-box.dark { background: #1a1a1a; border-color: #333; }
body.dark-theme .icon-box.dark { background: #0a0a0a; border-color: #222; }
.icon-box svg { display: block; margin: 0 auto 10px; }
.icon-box span { font-size: 11px; color: #666; word-break: break-all; }
body.dark-theme .icon-box span { color: #999; }
.icon-box.dark span { color: #999; }
.tabs { display: flex; gap: 5px; margin-bottom: 20px; flex-wrap: wrap; }
.tab {
padding: 8px 16px;
background: #ddd;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
body.dark-theme .tab { background: #444; color: #eee; }
.tab.active { background: #333; color: #fff; }
body.dark-theme .tab.active { background: #666; }
.section { display: none; }
.section.active { display: block; }
</style>
</head>
<body>
<div class="header">
<h1>PrestaShop Icons Preview</h1>
<div class="theme-switch">
<span class="theme-label">Light</span>
<label class="switch">
<input type="checkbox" id="themeToggle" onchange="toggleTheme()">
<span class="slider"></span>
</label>
<span class="theme-label">Dark</span>
</div>
</div>
<div class="tabs">
<button class="tab active" onclick="showSection('payments')">Payment Icons</button>
<button class="tab" onclick="showSection('socials')">Social Icons</button>
</div>
<div id="payments" class="section active">
<h2>Payment Icons</h2>
<h3>Icon Shape - Light Accent (la)</h3>
<div class="grid" id="payments-icon-la"></div>
<h3>Icon Shape - Dark Accent (da) - Dark Background</h3>
<div class="grid" id="payments-icon-da"></div>
<h3>Icon Shape - Light Mode (lm)</h3>
<div class="grid" id="payments-icon-lm"></div>
<h3>Icon Shape - Dark Mode (dm) - Dark Background</h3>
<div class="grid" id="payments-icon-dm"></div>
<h3>Square Shape - Light Accent (la)</h3>
<div class="grid" id="payments-square-la"></div>
<h3>Rectangle Shape - Light Accent (la)</h3>
<div class="grid" id="payments-rectangle-la"></div>
</div>
<div id="socials" class="section">
<h2>Social Icons</h2>
<h3>Icon Shape - Light Accent (la)</h3>
<div class="grid" id="socials-icon-la"></div>
<h3>Icon Shape - Dark Accent (da) - Dark Background</h3>
<div class="grid" id="socials-icon-da"></div>
<h3>Full Logo - Light Accent (la)</h3>
<div class="grid" id="socials-full-logo-la"></div>
</div>
<script>
const paymentBrands = [
'afterpay', 'alipay', 'alma', 'amazon_pay', 'american_express', 'apple_pay',
'bacs', 'bancontact', 'bank', 'billie', 'blik', 'cartes_bancaires', 'cod',
'credit_pay', 'eps', 'google_pay', 'ideal', 'jcb', 'kakao_pay', 'klarna',
'link', 'mastercard', 'mobilepay', 'multibanco', 'naverpay', 'p24', 'payco',
'paypal', 'pickup', 'point_of_sale', 'quote', 'revolut', 'samsung_pay', 'satispay',
'sepa', 'twint', 'visa', 'wechat_pay'
];
const socialBrands = [
'amazon', 'apple', 'facebook', 'google', 'linkedin', 'microsoft',
'outlook', 'paypal', 'reddit', 'tiktok', 'x', 'yahoo'
];
function renderIcons(containerId, brands, spriteFile, suffix, size, isDark = false) {
const container = document.getElementById(containerId);
if (!container) return;
console.log(`[${containerId}] Loading sprite: ${spriteFile}`);
// Load sprite
fetch(spriteFile)
.then(r => {
console.log(`[${containerId}] Fetch status: ${r.status}`);
return r.text();
})
.then(svg => {
// Insert hidden sprite with unique ID
// Use position:absolute + clip instead of display:none to keep gradients/clipPaths working
const spriteId = `sprite-${containerId}`;
const div = document.createElement('div');
div.id = spriteId;
div.style.cssText = 'position:absolute;width:0;height:0;overflow:hidden;';
div.innerHTML = svg;
document.body.appendChild(div);
// Find all symbols in this sprite
const symbols = div.querySelectorAll('symbol');
const symbolIds = Array.from(symbols).map(s => s.id);
console.log(`[${containerId}] Found ${symbols.length} symbols:`, symbolIds);
// Render icons
brands.forEach(brand => {
const id = `${brand}_${suffix}`;
const exists = symbolIds.includes(id);
if (!exists) {
console.warn(`[${containerId}] MISSING symbol: #${id}`);
}
const box = document.createElement('div');
box.className = 'icon-box' + (isDark ? ' dark' : '') + (exists ? '' : ' missing');
box.innerHTML = `
<svg width="${size}" height="${size}" style="${exists ? '' : 'border: 2px dashed red;'}">
<use href="#${id}"></use>
</svg>
<span>${brand}${exists ? '' : ' (MISSING)'}</span>
`;
container.appendChild(box);
// Check if symbol has content
if (exists) {
const symbol = div.querySelector(`#${id}`);
const content = symbol ? symbol.innerHTML.trim() : '';
if (!content) {
console.warn(`[${containerId}] EMPTY symbol: #${id}`);
} else {
// Check for references in the symbol
const urls = content.match(/url\(#([^)]+)\)/g) || [];
const hrefs = content.match(/href="#([^"]+)"/g) || [];
if (urls.length || hrefs.length) {
console.log(`[${containerId}] ${id} references:`, [...urls, ...hrefs]);
// Check if references exist
[...urls, ...hrefs].forEach(ref => {
const refId = ref.match(/#([^)"]+)/)?.[1];
if (refId && !document.getElementById(refId)) {
console.error(`[${containerId}] BROKEN REF in ${id}: #${refId} not found in DOM`);
}
});
}
}
}
});
})
.catch(e => {
console.error(`[${containerId}] Error:`, e);
container.innerHTML = `<p>Error loading ${spriteFile}: ${e.message}</p>`;
});
}
// Debug: Check for invisible icons after render
function debugInvisibleIcons() {
document.querySelectorAll('.icon-box').forEach(box => {
const svg = box.querySelector('svg');
const use = box.querySelector('use');
const label = box.querySelector('span')?.textContent || 'unknown';
if (!use) return;
const href = use.getAttribute('href');
const symbolId = href?.replace('#', '');
const symbol = document.getElementById(symbolId);
if (symbol) {
// Check if symbol has visible paths
const paths = symbol.querySelectorAll('path, rect, circle, polygon, g');
const hasVisibleContent = paths.length > 0;
// Check if any path has fill or stroke
let hasColor = false;
paths.forEach(p => {
const fill = p.getAttribute('fill') || p.style.fill;
const stroke = p.getAttribute('stroke') || p.style.stroke;
if ((fill && fill !== 'none') || (stroke && stroke !== 'none')) {
hasColor = true;
}
});
if (!hasVisibleContent) {
console.error(`NO CONTENT: ${label} (${symbolId}) - no paths/shapes found`);
} else if (!hasColor) {
console.warn(`NO COLOR: ${label} (${symbolId}) - shapes exist but no fill/stroke`);
}
}
});
console.log('Debug check complete. Look for NO CONTENT or NO COLOR warnings above.');
}
// Run debug after all sprites loaded
setTimeout(debugInvisibleIcons, 2000);
// Payment icons
renderIcons('payments-icon-la', paymentBrands, 'sprites/payments/icon-la.svg', 'la', 45);
renderIcons('payments-icon-da', paymentBrands, 'sprites/payments/icon-da.svg', 'da', 45, true);
renderIcons('payments-icon-lm', paymentBrands, 'sprites/payments/icon-lm.svg', 'lm', 45);
renderIcons('payments-icon-dm', paymentBrands, 'sprites/payments/icon-dm.svg', 'dm', 45, true);
renderIcons('payments-square-la', paymentBrands, 'sprites/payments/square-la.svg', 'la', 45);
renderIcons('payments-rectangle-la', paymentBrands, 'sprites/payments/rectangle-la.svg', 'la', 60);
// Social icons
renderIcons('socials-icon-la', socialBrands, 'sprites/socials/icon-la.svg', 'la', 45);
renderIcons('socials-icon-da', socialBrands, 'sprites/socials/icon-da.svg', 'da', 45, true);
renderIcons('socials-full-logo-la', socialBrands, 'sprites/socials/full-logo-la.svg', 'la', 80);
function showSection(name) {
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.getElementById(name).classList.add('active');
event.target.classList.add('active');
}
function toggleTheme() {
document.body.classList.toggle('dark-theme');
localStorage.setItem('theme', document.body.classList.contains('dark-theme') ? 'dark' : 'light');
}
// Load saved theme
if (localStorage.getItem('theme') === 'dark') {
document.body.classList.add('dark-theme');
document.getElementById('themeToggle').checked = true;
}
</script>
</body>
</html>