Implement comprehensive theme system and modernize UI

- Add 8 themes: Gruvbox (default), Basic Blue, Dark, Gruvbox Dark, Dracula, Nord, Solarized, Arc
- Replace emoji icons with clean SVG icons for search, reverse, and share buttons
- Add Rolling Stone Magazine's supertitle to header
- Implement theme selector in header with localStorage persistence
- Simplify jump-to-rank placeholder text to "Jump to..."
- Update all UI elements to use CSS custom properties for consistent theming
- Improve mobile responsiveness for theme selector and controls

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Johan Lundberg 2025-07-02 00:17:36 +02:00
parent ed8ad3c02a
commit fce2c6ff1e
3 changed files with 401 additions and 52 deletions

View file

@ -14,6 +14,7 @@ const sortBy = document.getElementById('sortBy');
const reverseButton = document.getElementById('reverseButton');
const jumpToRank = document.getElementById('jumpToRank');
const jumpButton = document.getElementById('jumpButton');
const themeSelect = document.getElementById('themeSelect');
const loading = document.getElementById('loading');
const error = document.getElementById('error');
const stats = document.getElementById('stats');
@ -23,6 +24,7 @@ document.addEventListener('DOMContentLoaded', function() {
loadWikipediaMapping();
loadAlbumsData();
setupEventListeners();
loadTheme();
handleUrlParams();
});
@ -46,6 +48,7 @@ function setupEventListeners() {
reverseButton.addEventListener('click', handleReverse);
jumpButton.addEventListener('click', handleJumpToRank);
jumpToRank.addEventListener('keypress', handleRankKeypress);
themeSelect.addEventListener('change', handleThemeChange);
// Add scroll listener for infinite scroll
window.addEventListener('scroll', handleScroll);
@ -98,6 +101,41 @@ function handleStatsCardClick(filterValue) {
albumsGrid.scrollIntoView({ behavior: 'smooth' });
}
// Theme handling functions
function handleThemeChange(event) {
const theme = event.target.value;
setTheme(theme);
saveTheme(theme);
}
function setTheme(theme) {
if (theme) {
document.documentElement.setAttribute('data-theme', theme);
} else {
document.documentElement.removeAttribute('data-theme');
}
}
function saveTheme(theme) {
try {
localStorage.setItem('selectedTheme', theme);
} catch (e) {
console.warn('Could not save theme to localStorage:', e);
}
}
function loadTheme() {
try {
const savedTheme = localStorage.getItem('selectedTheme');
if (savedTheme !== null) {
setTheme(savedTheme);
themeSelect.value = savedTheme;
}
} catch (e) {
console.warn('Could not load theme from localStorage:', e);
}
}
// Load albums data from CSV
async function loadAlbumsData() {
try {
@ -238,7 +276,13 @@ function createAlbumCard(album) {
View on Wikipedia
</a>
</div>
<button class="album-share" title="Share this album" data-rank="${album.Rank}">🔗</button>
<button class="album-share" title="Share this album" data-rank="${album.Rank}">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"></path>
<polyline points="16,6 12,2 8,6"></polyline>
<line x1="12" y1="2" x2="12" y2="15"></line>
</svg>
</button>
`;
// Description is now always fully visible