- Add .gitignore to exclude node_modules, dist, logs, and system files - Add comprehensive project documentation including README, deployment guide, and development setup - Add .kiro project specifications for amazon-product-bar-extension, appwrite-cloud-storage, appwrite-userid-repair, blacklist-feature, and enhanced-item-management - Add .kiro steering documents for product, structure, styling, and tech guidelines - Add VSCode settings configuration for consistent development environment - Add manifest.json and babel/vite configuration for extension build setup - Add complete source code implementation including AppWrite integration, storage managers, UI components, and services - Add comprehensive test suite with Jest configuration and 30+ test files covering all major modules - Add test HTML files for integration testing and validation - Add coverage reports and build validation scripts - Add AppWrite setup and repair documentation for database schema management - Add migration guides and responsive accessibility implementation documentation - Establish foundation for Amazon product bar extension with full feature set including blacklist management, enhanced item workflows, and real-time synchronization
583 lines
26 KiB
HTML
583 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Enhanced Items - Responsive Accessibility Design</title>
|
|
<link rel="stylesheet" href="src/EnhancedItemsPanel.css">
|
|
<style>
|
|
body {
|
|
margin: 0;
|
|
padding: 20px;
|
|
background: #0a0a0a;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
}
|
|
|
|
/* Breakpoint Indicator for Testing */
|
|
.breakpoint-indicator {
|
|
position: fixed;
|
|
top: 10px;
|
|
right: 10px;
|
|
background: #ff9900;
|
|
color: #000;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 6px;
|
|
font-weight: bold;
|
|
z-index: 10000;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Accessibility Testing Controls */
|
|
.accessibility-controls {
|
|
position: fixed;
|
|
top: 10px;
|
|
left: 10px;
|
|
background: rgba(0, 0, 0, 0.9);
|
|
padding: 1rem;
|
|
border-radius: 8px;
|
|
border: 1px solid #333;
|
|
z-index: 9999;
|
|
}
|
|
|
|
.accessibility-controls h3 {
|
|
color: #ff9900;
|
|
margin: 0 0 1rem 0;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.accessibility-controls button {
|
|
display: block;
|
|
width: 100%;
|
|
margin-bottom: 0.5rem;
|
|
padding: 0.5rem;
|
|
background: #333;
|
|
color: white;
|
|
border: 1px solid #555;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.accessibility-controls button:hover {
|
|
background: #555;
|
|
}
|
|
|
|
.accessibility-controls button.active {
|
|
background: #ff9900;
|
|
color: #000;
|
|
}
|
|
|
|
/* High Contrast Mode Simulation */
|
|
.high-contrast {
|
|
filter: contrast(200%) brightness(150%);
|
|
}
|
|
|
|
/* Reduced Motion Simulation */
|
|
.reduced-motion * {
|
|
animation: none !important;
|
|
transition: none !important;
|
|
}
|
|
|
|
/* Large Text Simulation */
|
|
.large-text {
|
|
font-size: 1.25em !important;
|
|
}
|
|
|
|
.large-text * {
|
|
font-size: inherit !important;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- Skip Link for Accessibility -->
|
|
<a href="#main-content" class="skip-link">Zum Hauptinhalt springen</a>
|
|
|
|
<!-- Breakpoint Indicator -->
|
|
<div class="breakpoint-indicator" id="breakpoint-indicator">
|
|
Desktop (≥769px)
|
|
</div>
|
|
|
|
<!-- Accessibility Testing Controls -->
|
|
<div class="accessibility-controls">
|
|
<h3>Barrierefreiheit Tests</h3>
|
|
<button onclick="toggleHighContrast()" id="contrast-btn">Hoher Kontrast</button>
|
|
<button onclick="toggleReducedMotion()" id="motion-btn">Reduzierte Bewegung</button>
|
|
<button onclick="toggleLargeText()" id="text-btn">Große Schrift</button>
|
|
<button onclick="testKeyboardNav()" id="keyboard-btn">Tastatur Navigation</button>
|
|
<button onclick="testScreenReader()" id="reader-btn">Screenreader Test</button>
|
|
</div>
|
|
|
|
<main id="main-content">
|
|
<!-- Enhanced Items Content with Full Responsive Accessibility -->
|
|
<div class="amazon-ext-enhanced-items-content" role="main" aria-labelledby="enhanced-items-heading">
|
|
|
|
<!-- Enhanced Header with Responsive Typography -->
|
|
<div class="enhanced-items-header">
|
|
<h2 id="enhanced-items-heading">Enhanced Items</h2>
|
|
</div>
|
|
|
|
<!-- Enhanced Add Item Form with Full Accessibility -->
|
|
<div class="add-enhanced-item-form" role="search" aria-label="Neues Enhanced Item hinzufügen" style="position: relative;">
|
|
<input
|
|
type="url"
|
|
class="enhanced-url-input"
|
|
placeholder="Amazon-URL eingeben für automatische Extraktion..."
|
|
aria-label="Amazon Produkt URL"
|
|
aria-describedby="url-validation-feedback url-help-text"
|
|
aria-invalid="false"
|
|
tabindex="1"
|
|
required
|
|
autocomplete="url">
|
|
|
|
<!-- Enhanced URL Validation Container -->
|
|
<div class="url-validation-container">
|
|
<div class="validation-feedback" id="url-validation-feedback" role="status" aria-live="polite">
|
|
<div class="validation-icon" aria-hidden="true"></div>
|
|
<div class="validation-message"></div>
|
|
</div>
|
|
<div class="input-guidance" id="url-help-text" style="display: none;">
|
|
<div class="guidance-content">
|
|
<div class="guidance-title">💡 Tipp</div>
|
|
<div class="guidance-text">Fügen Sie eine Amazon-Produktseite-URL ein</div>
|
|
<div class="guidance-examples">
|
|
<div class="example-title">Beispiele:</div>
|
|
<div class="example-url">amazon.de/dp/B08N5WRWNW</div>
|
|
<div class="example-url">amazon.com/gp/product/B08N5WRWNW</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
class="extract-btn"
|
|
type="button"
|
|
aria-label="Produktdaten aus URL extrahieren und KI-Titelvorschläge generieren"
|
|
tabindex="2"
|
|
aria-describedby="extract-btn-help">
|
|
Extrahieren & Hinzufügen
|
|
</button>
|
|
|
|
<button
|
|
class="help-button"
|
|
aria-label="Hilfe für Amazon-URL eingeben"
|
|
type="button"
|
|
tabindex="3"
|
|
style="position: absolute; right: 8px; top: 50%; transform: translateY(-50%);"
|
|
onclick="toggleHelp()">
|
|
❓
|
|
</button>
|
|
|
|
<div id="extract-btn-help" class="sr-only">
|
|
Extrahiert Produktdaten aus der eingegebenen URL und generiert KI-Titelvorschläge.
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Enhanced Progress Indicator with Full Accessibility -->
|
|
<div class="extraction-progress" style="display: none;" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="5" aria-labelledby="progress-heading">
|
|
<div class="progress-header">
|
|
<h4 id="progress-heading">Verarbeitung läuft...</h4>
|
|
</div>
|
|
<div class="progress-steps" role="list">
|
|
<div class="progress-step" data-step="validate" role="listitem">
|
|
<span class="step-icon" aria-hidden="true">🔍</span>
|
|
<span class="step-text">URL validieren...</span>
|
|
<span class="step-status" aria-label="Wartend"></span>
|
|
</div>
|
|
<div class="progress-step" data-step="extract" role="listitem">
|
|
<span class="step-icon" aria-hidden="true">📦</span>
|
|
<span class="step-text">Produktdaten extrahieren...</span>
|
|
<span class="step-status" aria-label="Wartend"></span>
|
|
</div>
|
|
<div class="progress-step" data-step="ai" role="listitem">
|
|
<span class="step-icon" aria-hidden="true">🤖</span>
|
|
<span class="step-text">KI-Titelvorschläge generieren...</span>
|
|
<span class="step-status" aria-label="Wartend"></span>
|
|
</div>
|
|
<div class="progress-step" data-step="select" role="listitem">
|
|
<span class="step-icon" aria-hidden="true">✏️</span>
|
|
<span class="step-text">Titel auswählen...</span>
|
|
<span class="step-status" aria-label="Wartend"></span>
|
|
</div>
|
|
<div class="progress-step" data-step="save" role="listitem">
|
|
<span class="step-icon" aria-hidden="true">💾</span>
|
|
<span class="step-text">Item speichern...</span>
|
|
<span class="step-status" aria-label="Wartend"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Enhanced Messages with Full Accessibility -->
|
|
<div class="error-message" style="display: none;" role="alert" aria-live="assertive"></div>
|
|
<div class="success-message" style="display: none;" role="status" aria-live="polite"></div>
|
|
|
|
<!-- Enhanced Item List with Full Responsive Accessibility -->
|
|
<div class="enhanced-item-list" role="region" aria-label="Enhanced Items Liste" aria-describedby="items-description">
|
|
<div id="items-description" class="sr-only">
|
|
Liste der gespeicherten Enhanced Items mit Produktinformationen und Aktionen
|
|
</div>
|
|
|
|
<!-- Enhanced Item Card with Full Accessibility -->
|
|
<div class="enhanced-item"
|
|
data-item-id="B08WX56W96"
|
|
role="article"
|
|
aria-labelledby="item-title-1"
|
|
aria-describedby="item-desc-1"
|
|
tabindex="0">
|
|
|
|
<div class="item-main-content">
|
|
<div class="item-header">
|
|
<h3 class="item-custom-title" id="item-title-1">
|
|
ROCKBROS Sturmhaube Herbst/Winter Thermo Balaclava für Outdoorsports Radfahren Skifahren Snowboard Reflektierend Winddicht Anti-Staub Atmungsaktiv für Damen Herren 2 PCS
|
|
</h3>
|
|
<div class="item-price-display">
|
|
<span class="price" aria-label="Preis: 12 Euro">12.00 EUR</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="item-details">
|
|
<div class="item-url-section">
|
|
<a href="https://www.amazon.de/ROCKBROS-Outdoorsports-Reflektierend-Atmungsaktiv-Einheitsgr%C3%B6%C3%9Fe/dp/B08WX56W96/ref=sr_1_7"
|
|
target="_blank"
|
|
class="item-url"
|
|
rel="noopener noreferrer"
|
|
aria-label="Produkt auf Amazon anzeigen (öffnet in neuem Tab)">
|
|
<span class="url-icon" aria-hidden="true">🔗</span>
|
|
https://www.amazon.de/ROCKBROS-Outdoorsports-Reflektieren...
|
|
</a>
|
|
</div>
|
|
|
|
<div class="item-meta">
|
|
<span class="created-date" aria-label="Erstellt am 11. Januar 2026 um 16:14 Uhr">
|
|
Erstellt: 11.01.2026, 16:14
|
|
</span>
|
|
<span class="manual-badge" aria-label="Manuell erstellter Titel">Manuell</span>
|
|
</div>
|
|
|
|
<!-- Enhanced Original Title Section -->
|
|
<div class="original-title-section" style="display: none;" aria-labelledby="original-title-label-1">
|
|
<div class="original-title-label" id="original-title-label-1">Original-Titel:</div>
|
|
<div class="original-title-text">
|
|
ROCKBROS Sturmhaube Herbst/Winter Thermo Balaclava für Outdoorsports Radfahren Skifahren Snowboard Reflektierend Winddicht Anti-Staub Atmungsaktiv für Damen Herren 2 PCS
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Enhanced Item Actions with Full Accessibility -->
|
|
<div class="item-actions" role="group" aria-label="Item Aktionen">
|
|
<button class="toggle-original-btn"
|
|
data-item-id="B08WX56W96"
|
|
type="button"
|
|
aria-pressed="false"
|
|
aria-describedby="original-help"
|
|
title="Original-Titel anzeigen/verbergen">
|
|
<span class="btn-icon" aria-hidden="true">👁️</span>
|
|
<span class="btn-text">Original</span>
|
|
<span class="keyboard-shortcut">
|
|
<span class="kbd">O</span>
|
|
</span>
|
|
</button>
|
|
|
|
<button class="edit-item-btn"
|
|
data-item-id="B08WX56W96"
|
|
type="button"
|
|
aria-describedby="edit-help"
|
|
title="Item bearbeiten">
|
|
<span class="btn-icon" aria-hidden="true">✏️</span>
|
|
<span class="btn-text">Bearbeiten</span>
|
|
<span class="keyboard-shortcut">
|
|
<span class="kbd">E</span>
|
|
</span>
|
|
</button>
|
|
|
|
<button class="delete-item-btn"
|
|
data-item-id="B08WX56W96"
|
|
type="button"
|
|
aria-describedby="delete-help"
|
|
title="Item löschen">
|
|
<span class="btn-icon" aria-hidden="true">🗑️</span>
|
|
<span class="btn-text">Löschen</span>
|
|
<span class="keyboard-shortcut">
|
|
<span class="kbd">Del</span>
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Enhanced Screen Reader Description -->
|
|
<div id="item-desc-1" class="sr-only">
|
|
Produkt: ROCKBROS Sturmhaube Herbst/Winter Thermo Balaclava für Outdoorsports Radfahren Skifahren Snowboard Reflektierend Winddicht Anti-Staub Atmungsaktiv für Damen Herren 2 PCS.
|
|
Preis: 12.00 EUR.
|
|
Erstellt: 11. Januar 2026, 16:14.
|
|
Manueller Titel.
|
|
Verfügbare Aktionen: Original-Titel anzeigen, Bearbeiten, Löschen.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Hidden elements for screen reader testing -->
|
|
<div class="sr-only" aria-live="polite" id="screen-reader-announcements"></div>
|
|
|
|
<!-- Help text for keyboard shortcuts -->
|
|
<div id="original-help" class="sr-only">Drücken Sie O um die Sichtbarkeit des Original-Titels umzuschalten</div>
|
|
<div id="edit-help" class="sr-only">Drücken Sie E um dieses Item zu bearbeiten</div>
|
|
<div id="delete-help" class="sr-only">Drücken Sie Entf um dieses Item zu löschen</div>
|
|
|
|
<script>
|
|
// Breakpoint Detection
|
|
function updateBreakpointIndicator() {
|
|
const indicator = document.getElementById('breakpoint-indicator');
|
|
const width = window.innerWidth;
|
|
|
|
if (width <= 480) {
|
|
indicator.textContent = 'Mobile (≤480px)';
|
|
indicator.style.background = '#dc3545';
|
|
} else if (width <= 768) {
|
|
indicator.textContent = 'Tablet (481px-768px)';
|
|
indicator.style.background = '#ffc107';
|
|
indicator.style.color = '#000';
|
|
} else {
|
|
indicator.textContent = 'Desktop (≥769px)';
|
|
indicator.style.background = '#28a745';
|
|
}
|
|
}
|
|
|
|
// Accessibility Testing Functions
|
|
function toggleHighContrast() {
|
|
const body = document.body;
|
|
const btn = document.getElementById('contrast-btn');
|
|
|
|
body.classList.toggle('high-contrast');
|
|
btn.classList.toggle('active');
|
|
|
|
announceToScreenReader(
|
|
body.classList.contains('high-contrast')
|
|
? 'Hoher Kontrast Modus aktiviert'
|
|
: 'Hoher Kontrast Modus deaktiviert'
|
|
);
|
|
}
|
|
|
|
function toggleReducedMotion() {
|
|
const body = document.body;
|
|
const btn = document.getElementById('motion-btn');
|
|
|
|
body.classList.toggle('reduced-motion');
|
|
btn.classList.toggle('active');
|
|
|
|
announceToScreenReader(
|
|
body.classList.contains('reduced-motion')
|
|
? 'Reduzierte Bewegung Modus aktiviert'
|
|
: 'Reduzierte Bewegung Modus deaktiviert'
|
|
);
|
|
}
|
|
|
|
function toggleLargeText() {
|
|
const body = document.body;
|
|
const btn = document.getElementById('text-btn');
|
|
|
|
body.classList.toggle('large-text');
|
|
btn.classList.toggle('active');
|
|
|
|
announceToScreenReader(
|
|
body.classList.contains('large-text')
|
|
? 'Große Schrift Modus aktiviert'
|
|
: 'Große Schrift Modus deaktiviert'
|
|
);
|
|
}
|
|
|
|
function testKeyboardNav() {
|
|
announceToScreenReader('Tastatur Navigation Test gestartet. Verwenden Sie Tab zum Navigieren, Enter zum Aktivieren, Pfeiltasten für Radiogruppen.');
|
|
|
|
// Focus first interactive element
|
|
const firstButton = document.querySelector('.extract-btn');
|
|
if (firstButton) {
|
|
firstButton.focus();
|
|
}
|
|
}
|
|
|
|
function testScreenReader() {
|
|
announceToScreenReader('Screenreader Test: Diese Seite enthält Enhanced Item Management Interface mit responsivem Design und Barrierefreiheit Features. Navigieren Sie mit Überschriften, Landmarks und interaktiven Elementen.');
|
|
}
|
|
|
|
function announceToScreenReader(message) {
|
|
const announcer = document.getElementById('screen-reader-announcements');
|
|
announcer.textContent = message;
|
|
|
|
// Clear after announcement
|
|
setTimeout(() => {
|
|
announcer.textContent = '';
|
|
}, 1000);
|
|
}
|
|
|
|
// Help Toggle Function
|
|
function toggleHelp() {
|
|
const helpText = document.getElementById('url-help-text');
|
|
const isVisible = helpText.style.display !== 'none';
|
|
|
|
helpText.style.display = isVisible ? 'none' : 'block';
|
|
|
|
announceToScreenReader(
|
|
isVisible ? 'Hilfe ausgeblendet' : 'Hilfe eingeblendet'
|
|
);
|
|
}
|
|
|
|
// Enhanced Item Actions with Keyboard Support
|
|
function setupItemActions() {
|
|
// Toggle Original Title
|
|
document.querySelectorAll('.toggle-original-btn').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const itemId = btn.dataset.itemId;
|
|
const originalSection = document.querySelector(`[data-item-id="${itemId}"] .original-title-section`);
|
|
const isPressed = btn.getAttribute('aria-pressed') === 'true';
|
|
|
|
btn.setAttribute('aria-pressed', !isPressed);
|
|
btn.querySelector('.btn-text').textContent = isPressed ? 'Original' : 'Verbergen';
|
|
|
|
if (originalSection) {
|
|
originalSection.style.display = isPressed ? 'none' : 'block';
|
|
}
|
|
|
|
announceToScreenReader(
|
|
isPressed ? 'Original-Titel ausgeblendet' : 'Original-Titel angezeigt'
|
|
);
|
|
});
|
|
});
|
|
|
|
// Edit Item
|
|
document.querySelectorAll('.edit-item-btn').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
announceToScreenReader('Bearbeiten-Dialog würde hier geöffnet werden');
|
|
});
|
|
});
|
|
|
|
// Delete Item
|
|
document.querySelectorAll('.delete-item-btn').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
if (confirm('Sind Sie sicher, dass Sie dieses Item löschen möchten?')) {
|
|
announceToScreenReader('Item würde hier gelöscht werden');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Keyboard Shortcuts
|
|
function setupKeyboardShortcuts() {
|
|
document.addEventListener('keydown', (e) => {
|
|
// Only handle shortcuts when not in input fields
|
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
|
|
return;
|
|
}
|
|
|
|
const focusedItem = document.querySelector('.enhanced-item:focus-within');
|
|
if (!focusedItem) return;
|
|
|
|
const itemId = focusedItem.dataset.itemId;
|
|
|
|
switch(e.key.toLowerCase()) {
|
|
case 'o':
|
|
e.preventDefault();
|
|
const originalBtn = focusedItem.querySelector('.toggle-original-btn');
|
|
if (originalBtn) {
|
|
originalBtn.click();
|
|
}
|
|
break;
|
|
case 'e':
|
|
e.preventDefault();
|
|
const editBtn = focusedItem.querySelector('.edit-item-btn');
|
|
if (editBtn) {
|
|
editBtn.click();
|
|
}
|
|
break;
|
|
case 'Delete':
|
|
e.preventDefault();
|
|
const deleteBtn = focusedItem.querySelector('.delete-item-btn');
|
|
if (deleteBtn) {
|
|
deleteBtn.click();
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Extract Button Behavior
|
|
function setupExtractButton() {
|
|
const extractBtn = document.querySelector('.extract-btn');
|
|
const progressContainer = document.querySelector('.extraction-progress');
|
|
|
|
if (extractBtn) {
|
|
extractBtn.addEventListener('click', () => {
|
|
extractBtn.disabled = true;
|
|
extractBtn.textContent = 'Extrahiere...';
|
|
progressContainer.style.display = 'block';
|
|
|
|
announceToScreenReader('Extraktion gestartet');
|
|
|
|
// Simulate progress
|
|
simulateProgress();
|
|
|
|
setTimeout(() => {
|
|
extractBtn.disabled = false;
|
|
extractBtn.textContent = 'Extrahieren & Hinzufügen';
|
|
progressContainer.style.display = 'none';
|
|
announceToScreenReader('Extraktion abgeschlossen');
|
|
}, 5000);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Simulate Progress Steps
|
|
function simulateProgress() {
|
|
const steps = document.querySelectorAll('.progress-step');
|
|
const progressBar = document.querySelector('.extraction-progress');
|
|
|
|
steps.forEach((step, index) => {
|
|
setTimeout(() => {
|
|
// Remove previous active states
|
|
steps.forEach(s => s.classList.remove('active', 'completed'));
|
|
|
|
// Add completed to previous steps
|
|
for (let i = 0; i < index; i++) {
|
|
steps[i].classList.add('completed');
|
|
steps[i].querySelector('.step-status').textContent = '✓';
|
|
steps[i].querySelector('.step-status').setAttribute('aria-label', 'Abgeschlossen');
|
|
}
|
|
|
|
// Add active to current step
|
|
step.classList.add('active');
|
|
step.querySelector('.step-status').textContent = '⏳';
|
|
step.querySelector('.step-status').setAttribute('aria-label', 'Aktiv');
|
|
|
|
// Update progress bar
|
|
progressBar.setAttribute('aria-valuenow', index + 1);
|
|
|
|
const stepText = step.querySelector('.step-text').textContent;
|
|
announceToScreenReader(`Schritt ${index + 1}: ${stepText}`);
|
|
|
|
// Complete last step
|
|
if (index === steps.length - 1) {
|
|
setTimeout(() => {
|
|
step.classList.remove('active');
|
|
step.classList.add('completed');
|
|
step.querySelector('.step-status').textContent = '✓';
|
|
step.querySelector('.step-status').setAttribute('aria-label', 'Abgeschlossen');
|
|
progressBar.setAttribute('aria-valuenow', steps.length);
|
|
announceToScreenReader('Alle Schritte abgeschlossen');
|
|
}, 800);
|
|
}
|
|
}, index * 800);
|
|
});
|
|
}
|
|
|
|
// Initialize
|
|
window.addEventListener('load', () => {
|
|
updateBreakpointIndicator();
|
|
setupItemActions();
|
|
setupKeyboardShortcuts();
|
|
setupExtractButton();
|
|
});
|
|
|
|
window.addEventListener('resize', updateBreakpointIndicator);
|
|
</script>
|
|
</body>
|
|
</html> |