Add Library theme with user images + fix theme system

New Library Theme Feature:
- Added 'Library (Random)' option to theme dropdown
- Uses random images from user's linked directories
- Fresh random selection on each page load/theme change
- Displays 10 random images from personal collection on home screen

 Theme System Improvements:
- Updated applyTheme() to handle async library theme loading
- Added applyLibraryTheme() function with proper error handling
- Fixed CSS loading to skip image-based themes (library, hentai, etc.)
- Improved file path handling for Electron environment
- Added fallback to hentai theme when no library images found

 Enhanced Dropdown:
- Added BBC and feet themes with proper image mappings
- Added Library theme with folder icon
- All 6 theme options now fully functional

 Result: Personalized home screen using user's own image collection!
This commit is contained in:
dilgenfritz 2025-11-11 20:54:26 -06:00
parent 37ec5f0f1e
commit 9d94fb8695
2 changed files with 179 additions and 18 deletions

View File

@ -256,6 +256,9 @@
<select id="theme-dropdown" class="theme-dropdown"> <select id="theme-dropdown" class="theme-dropdown">
<option value="hentai" selected>🎭 Hentai</option> <option value="hentai" selected>🎭 Hentai</option>
<option value="pornstars">⭐ Pornstars</option> <option value="pornstars">⭐ Pornstars</option>
<option value="BBC">🔥 BBC</option>
<option value="feet">👣 Feet</option>
<option value="library">📂 Library (Random)</option>
<option value="none">🚫 None</option> <option value="none">🚫 None</option>
</select> </select>
</div> </div>
@ -1307,24 +1310,69 @@
<script src="src/core/game.js"></script> <script src="src/core/game.js"></script>
<script> <script>
// Theme switching functionality // Theme switching functionality
function applyTheme(theme) { async function applyTheme(theme) {
console.log('Applying theme:', theme); console.log('Applying theme:', theme);
const characterSides = document.querySelectorAll('.character-side'); const characterSides = document.querySelectorAll('.character-side');
characterSides.forEach((element, index) => { if (theme === 'none') {
if (theme === 'none') { characterSides.forEach(element => {
element.style.display = 'none'; element.style.display = 'none';
} else { });
element.style.display = 'block'; localStorage.setItem('selectedTheme', theme);
return;
// Map element positions to image numbers }
if (theme === 'library') {
// Use random images from user's library
await applyLibraryTheme(characterSides);
localStorage.setItem('selectedTheme', theme);
return;
}
// Handle static themes (hentai, pornstars, BBC, feet)
characterSides.forEach((element, index) => {
element.style.display = 'block';
// Define image mappings for different themes
let imageNames;
if (theme === 'hentai' || theme === 'pornstars') {
// Standard numbering for hentai and pornstars
const imageNumbers = [1, 11, 3, 4, 5, 6, 7, 8, 9, 10]; const imageNumbers = [1, 11, 3, 4, 5, 6, 7, 8, 9, 10];
const imageNumber = imageNumbers[index]; imageNames = imageNumbers.map(num => `${num}.png`);
} else if (theme === 'BBC') {
if (imageNumber) { // BBC directory image names
const imagePath = `assets/${theme}/${imageNumber}.png`; imageNames = [
element.style.backgroundImage = `url('${imagePath}')`; '18808856_035_d374.png',
} '19086746_049_ba0d.png',
'23515083_025_f794.png',
'24163996_041_81d6.png',
'31015308_126_3792.png',
'44141198_113_f31a.png',
'60016759_151_ea2b.png',
'85835876_037_0c84.png',
'99106223_020_819b.png',
'99769898_038_0e86.png'
];
} else if (theme === 'feet') {
// Feet directory image names (using first 10)
imageNames = [
'20931683_001_c8f7.png',
'25674071_097_2016.png',
'29553632_079_53ec.png',
'30818412_002_8cbf.png',
'40352681_083_bec8.png',
'46780885_029_b8a2.png',
'47594084_126_51a7.png',
'67258313_065_60f1.png',
'79150090_035_3c99.png',
'80350346_043_3e8a.png'
];
}
if (imageNames && imageNames[index]) {
const imagePath = `assets/${theme}/${imageNames[index]}`;
element.style.backgroundImage = `url('${imagePath}')`;
} }
}); });
@ -1332,18 +1380,129 @@
localStorage.setItem('selectedTheme', theme); localStorage.setItem('selectedTheme', theme);
} }
async function applyLibraryTheme(characterSides) {
console.log('Applying library theme with random images...');
try {
// Get images from user's linked directories (same way as lib-image-gallery)
const linkedDirs = JSON.parse(localStorage.getItem('linkedImageDirectories') || '[]');
let allImages = [];
if (window.electronAPI && linkedDirs.length > 0) {
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp)$/i;
// Load images from all linked directories
for (const dir of linkedDirs) {
try {
let files = [];
if (window.electronAPI.readDirectory) {
const filesPromise = window.electronAPI.readDirectory(dir.path);
if (filesPromise && typeof filesPromise.then === 'function') {
files = await filesPromise;
} else if (Array.isArray(filesPromise)) {
files = filesPromise;
}
if (files && files.length > 0) {
const imageFiles = files.filter(file => {
const fileName = typeof file === 'object' ? file.name : file;
return imageExtensions.test(fileName);
});
const dirImages = imageFiles.map(file => {
if (typeof file === 'object' && file.name && file.path) {
return { path: file.path, name: file.name };
} else {
const fileName = typeof file === 'object' ? file.name : file;
const fullPath = window.electronAPI.pathJoin ?
window.electronAPI.pathJoin(dir.path, fileName) :
`${dir.path}\\${fileName}`;
return { path: fullPath, name: fileName };
}
});
allImages = allImages.concat(dirImages);
}
}
} catch (error) {
console.warn(`Error loading images from ${dir.path}:`, error);
}
}
}
console.log(`📂 Found ${allImages.length} images in user library`);
if (allImages.length === 0) {
// No images available - show placeholder or fall back to hentai theme
console.log('No library images found, falling back to hentai theme');
characterSides.forEach((element, index) => {
element.style.display = 'block';
// Fallback to hentai theme
const imageNumbers = [1, 11, 3, 4, 5, 6, 7, 8, 9, 10];
const imageNumber = imageNumbers[index];
if (imageNumber) {
const imagePath = `assets/hentai/${imageNumber}.png`;
element.style.backgroundImage = `url('${imagePath}')`;
}
});
return;
}
// Randomly select images for each character panel
characterSides.forEach((element, index) => {
element.style.display = 'block';
// Get a random image
const randomIndex = Math.floor(Math.random() * allImages.length);
const randomImage = allImages[randomIndex];
if (randomImage) {
// Use different approaches for file paths based on environment
let imageUrl;
if (window.electronAPI) {
// In Electron, use the path as-is (Electron handles file protocol internally)
imageUrl = randomImage.path;
} else {
// In browser, use file protocol (though this may not work due to security restrictions)
const cleanPath = randomImage.path.replace(/\\/g, '/');
imageUrl = `file:///${cleanPath}`;
}
element.style.backgroundImage = `url('${imageUrl}')`;
console.log(`📸 Panel ${index + 1}: Using ${randomImage.name} from ${imageUrl}`);
}
});
} catch (error) {
console.error('Error applying library theme:', error);
// Fallback to hentai theme on error
characterSides.forEach((element, index) => {
element.style.display = 'block';
const imageNumbers = [1, 11, 3, 4, 5, 6, 7, 8, 9, 10];
const imageNumber = imageNumbers[index];
if (imageNumber) {
const imagePath = `assets/hentai/${imageNumber}.png`;
element.style.backgroundImage = `url('${imagePath}')`;
}
});
}
}
// Initialize theme dropdown functionality // Initialize theme dropdown functionality
function initializeThemeDropdown() { async function initializeThemeDropdown() {
const themeDropdown = document.getElementById('theme-dropdown'); const themeDropdown = document.getElementById('theme-dropdown');
if (themeDropdown) { if (themeDropdown) {
// Load saved theme preference // Load saved theme preference
const savedTheme = localStorage.getItem('selectedTheme') || 'hentai'; const savedTheme = localStorage.getItem('selectedTheme') || 'hentai';
themeDropdown.value = savedTheme; themeDropdown.value = savedTheme;
applyTheme(savedTheme);
// Apply the saved theme (refreshes library theme with new random images)
await applyTheme(savedTheme);
// Handle theme changes // Handle theme changes
themeDropdown.addEventListener('change', (e) => { themeDropdown.addEventListener('change', async (e) => {
applyTheme(e.target.value); await applyTheme(e.target.value);
}); });
} }
} }

View File

@ -2990,7 +2990,9 @@ class TaskChallengeGame {
document.body.classList.remove(...oldThemeClasses); document.body.classList.remove(...oldThemeClasses);
// Load the appropriate theme CSS file // Load the appropriate theme CSS file
if (themeName && themeName !== 'balanced-purple') { // Skip CSS loading for themes that only change background images
const imageBGThemes = ['library', 'hentai', 'pornstars', 'BBC', 'feet', 'none'];
if (themeName && themeName !== 'balanced-purple' && !imageBGThemes.includes(themeName)) {
const themeLink = document.createElement('link'); const themeLink = document.createElement('link');
themeLink.id = 'dynamic-theme'; themeLink.id = 'dynamic-theme';
themeLink.rel = 'stylesheet'; themeLink.rel = 'stylesheet';