Updated UI style to be more modern

Updated headless browser to get images, videos and gifs!
This commit is contained in:
2025-11-20 14:25:23 -05:00
parent 6ddc45b989
commit aa5ac304bd
8 changed files with 850 additions and 327 deletions

View File

@@ -2,323 +2,195 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self' https://cdn.tailwindcss.com;
style-src 'self' https://cdn.tailwindcss.com 'unsafe-inline';
img-src 'self' https: data:;
connect-src 'self' https:;
" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Waifu Board</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
font-family: 'Inter', sans-serif;
background-color: #111827;
}
::-webkit-scrollbar {
width: 10px;
}
::-webkit-scrollbar-track {
background: #1f2937;
}
::-webkit-scrollbar-thumb {
background: #4b5563;
border-radius: 5px;
border: 2px solid #1f2937;
}
::-webkit-scrollbar-thumb:hover {
background: #6b7280;
}
.hidden {
display: none;
}
.dark-focus-ring:focus {
outline: 2px solid #4f46e5;
outline-offset: 2px;
}
.source-button.active {
background-color: #4f46e5;
color: white;
outline: 2px solid #4f46e5;
outline-offset: 2px;
}
.image-entry:hover .image-buttons {
opacity: 1;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1rem;
}
.gallery-masonry {
column-count: 2;
column-gap: 1rem;
}
@media (min-width: 768px) {
.gallery-masonry {
column-count: 3;
}
}
@media (min-width: 1024px) {
.gallery-masonry {
column-count: 4;
}
}
.gallery-masonry .image-entry {
display: inline-block;
width: 100%;
margin-bottom: 1rem;
break-inside: avoid;
}
.toast {
position: fixed;
bottom: 20px;
right: 20px;
padding: 15px;
border-radius: 5px;
color: white;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
display: flex;
align-items: flex-start;
min-width: 350px;
z-index: 1000;
transition: opacity 0.3s ease-in-out;
}
.toast-content {
flex-grow: 1;
}
.toast p {
margin: 0 0 5px 0;
}
.toast.update-available {
background-color: #e53935;
}
.toast.hidden {
opacity: 0;
pointer-events: none;
}
</style>
<meta charset="UTF-8" />
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' https: data:; connect-src 'self' https:;" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Waifu Board</title>
<link rel="stylesheet" href="./styles/home.css">
</head>
<body class="text-gray-200 flex h-screen overflow-hidden">
<nav class="w-20 bg-gray-900 flex flex-col items-center flex-shrink-0 p-4 space-y-6">
<button id="browse-button" class="nav-button p-3 rounded-xl bg-indigo-600 text-white" title="Browse">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
</svg>
</button>
<button id="favorites-button" class="nav-button p-3 rounded-xl text-gray-400 hover:bg-gray-700 hover:text-white"
title="Favorites">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.31h5.518a.562.562 0 01.31.95l-4.203 3.03a.563.563 0 00-.182.53l1.501 4.87a.562.562 0 01-.82.624l-4.204-3.03a.563.563 0 00-.576 0l-4.204 3.03a.562.562 0 01-.82-.624l1.501-4.87a.563.563 0 00-.182-.53L2.498 9.87a.562.562 0 01.31-.95h5.518a.563.563 0 00.475-.31L11.48 3.5z" />
</svg>
</button>
<button id="search-icon-button" class="nav-button p-3 rounded-xl text-gray-400 hover:bg-gray-700 hover:text-white"
title="Search">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
</svg>
</button>
<body>
<button id="settings-button" class="nav-button p-3 rounded-xl text-gray-400 hover:bg-gray-700 hover:text-white"
title="Settings">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9.594 3.94c.09-.542.56-1.003 1.114-1.114.554-.111 1.085-.111 1.64 0 .554.111 1.023.571 1.114 1.114.09.542.09 1.12 0 1.662-.09.542-.56 1.003-1.114 1.114a3.49 3.49 0 01-1.64 0c-.554-.111-1.023-.571-1.114-1.114-.09-.542-.09-1.12 0-1.662zM21 12a9 9 0 11-18 0 9 9 0 0118 0zM7.16 14.969c.09-.542.56-1.003 1.114-1.114.554-.111 1.085-.111 1.64 0 .554.111 1.023.571 1.114 1.114.09.542.09 1.12 0 1.662-.09.542-.56 1.003-1.114 1.114a3.49 3.49 0 01-1.64 0c-.554-.111-1.023-.571-1.114-1.114-.09-.542-.09-1.12 0-1.662zM14.969 7.16c.09-.542.56-1.003 1.114-1.114.554-.111 1.085-.111 1.64 0 .554.111 1.023.571 1.114 1.114.09.542.09 1.12 0 1.662-.09.542-.56 1.003-1.114 1.114a3.49 3.49 0 01-1.64 0c-.554-.111-1.023-.571-1.114-1.114-.09-.542-.09-1.12 0-1.662z" />
</svg>
</button>
<aside class="sidebar">
<br>
<nav style="display: flex; flex-direction: column; gap: 0.5rem;">
<button id="browse-button" class="nav-button active" title="Browse">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="7" height="7"></rect>
<rect x="14" y="3" width="7" height="7"></rect>
<rect x="14" y="14" width="7" height="7"></rect>
<rect x="3" y="14" width="7" height="7"></rect>
</svg>
<span>Browse</span>
</button>
<div class="h-px w-10 bg-gray-700"></div>
<button id="favorites-button" class="nav-button" title="Favorites">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path
d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z">
</path>
</svg>
<span>Favorites</span>
</button>
</nav>
<div id="source-list" class="flex flex-col items-center space-y-4" aria-label="Sources">
</div>
</nav>
<nav style="display: flex; flex-direction: column; gap: 0.5rem; margin-top: auto;">
<button id="settings-button" class="nav-button" title="Settings">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"></circle>
<path
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z">
</path>
</svg>
<span>Settings</span>
</button>
</nav>
</aside>
<div class="flex-1 flex flex-col overflow-hidden">
<header class="bg-gray-800 flex-shrink-0 flex items-center justify-between p-4 border-b border-gray-700 h-[69px]">
<h1 id="page-title" class="text-xl font-bold text-gray-100">Browse</h1>
<div id="header-context" class="text-sm text-gray-400"></div>
</header>
<div class="main-wrapper">
<header class="top-header">
<div style="position: relative;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
style="position: absolute; left: 15px; top: 50%; transform: translateY(-50%); pointer-events: none; color: var(--text-tertiary);">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<input type="text" id="search-input" placeholder="Search across sources..."
style="padding-left: 2.5rem;" />
</div>
<button id="search-button" class="hidden"></button>
<button id="search-icon-button" class="hidden"></button>
<button id="search-close-button" class="hidden"></button>
<div id="header-context" class="hidden"></div>
<h1 id="page-title" class="hidden">Home</h1>
</header>
<div class="content-view">
<div id="browse-page" class="page">
<h3
style="color: var(--text-tertiary); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 1rem;">
Sources</h3>
<div id="source-list">
</div>
<h3
style="color: var(--text-tertiary); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 1px; margin: 2rem 0 1rem 0;">
Library</h3>
<main id="content-gallery" class="gallery-masonry">
<div id="gallery-placeholder" class="loading-state" style="width: 100%; grid-column: 1 / -1;">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#52525b" stroke-width="1">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<circle cx="8.5" cy="8.5" r="1.5"></circle>
<polyline points="21 15 16 10 5 21"></polyline>
</svg>
<p>Select a source above to load content</p>
</div>
<div id="loading-spinner" class="hidden loading-state" style="width: 100%; grid-column: 1 / -1;">
<svg style="width:32px; height:32px; color: var(--accent); animation: spin 1s linear infinite;"
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path
d="M12 2v4m0 12v4M4.93 4.93l2.83 2.83m8.48 8.48l2.83 2.83M2 12h4m12 0h4M4.93 19.07l2.83-2.83m8.48-8.48l2.83-2.83">
</path>
</svg>
<p>Fetching images...</p>
</div>
<div id="infinite-loading-spinner" class="hidden loading-state"
style="width: 100%; grid-column: 1 / -1;">
<p>Loading more...</p>
</div>
</main>
</div>
<div id="favorites-page" class="page hidden">
<div style="margin-bottom: 2rem;">
<h2 style="margin-bottom: 0.5rem;">Your Favorites</h2>
<p style="color: var(--text-secondary);">Your personally curated collection.</p>
</div>
<main id="favorites-gallery" class="gallery-masonry"></main>
</div>
<div id="settings-page" class="page hidden">
<div style="margin-bottom: 2rem;">
<h2>Settings</h2>
<p style="color: var(--text-secondary);">Customize your viewing experience.</p>
</div>
<div class="settings-grid">
<div class="settings-card">
<h3>Layout Style</h3>
<fieldset>
<label>
<input type="radio" name="layout" value="scroll" id="layout-scroll">
<div>
<strong>Scroll View</strong>
<div style="font-size: 0.8rem; color: var(--text-tertiary);">Single column feed
</div>
</div>
</label>
<label>
<input type="radio" name="layout" value="grid" id="layout-grid">
<div>
<strong>Masonry Grid</strong>
<div style="font-size: 0.8rem; color: var(--text-tertiary);">Staggered dynamic
heights</div>
</div>
</label>
<label>
<input type="radio" name="layout" value="compact" id="layout-compact">
<div>
<strong>Compact Grid</strong>
<div style="font-size: 0.8rem; color: var(--text-tertiary);">Uniform square tiles
</div>
</div>
</label>
</fieldset>
</div>
</div>
</div>
<div id="browse-page" class="page flex-1 overflow-y-auto">
<main id="content-gallery" class="p-4 w-full" aria-live="polite">
<div id="loading-spinner" class="hidden text-center p-10 text-gray-400">
<svg class="animate-spin h-8 w-8 text-indigo-400 mx-auto" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
</path>
</svg>
<p class="mt-2">Loading...</p>
</div>
<p id="gallery-placeholder" class="text-gray-400 text-center text-lg">
Select a source and click the search icon to browse.
</p>
</div>
<div id="infinite-loading-spinner" class="hidden text-center p-10 text-gray-400">
<svg class="animate-spin h-8 w-8 text-indigo-400 mx-auto" xmlns="http://www.w3.org/2000/svg" fill="none"
viewBox="0 0 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z">
</path>
</svg>
<p class="mt-2">Loading more...</p>
<div id="tag-info-modal" class="hidden">
<div>
<button id="tag-info-close-button">&times;</button>
<h3 style="margin-top:0; margin-bottom: 1rem;">Tags</h3>
<div id="tag-info-content" class="tag-cloud"></div>
</div>
</main>
</div>
<div id="favorites-page" class="page hidden flex-1 overflow-y-auto">
<main id="favorites-gallery" class="p-4 w-full">
</main>
<div id="search-modal" class="hidden"></div>
<div id="message-bar" class="toast hidden">Message</div>
<div id="updateToast" class="toast hidden" style="border-left-color: #eab308;">
<p>Update Available: <span id="latestVersionDisplay">v1.x</span></p>
</div>
<div id="settings-page" class="page hidden flex-1 overflow-y-auto p-8">
<div class="max-w-2xl mx-auto space-y-8">
<h2 class="text-2xl font-bold text-white">Settings</h2>
<style>
@keyframes spin {
to {
transform: rotate(360deg);
}
}
</style>
<div class="bg-gray-800 rounded-lg p-6">
<h3 class="text-lg font-semibold text-gray-100 mb-4">
Gallery Layout
</h3>
<fieldset class="space-y-4">
<label for="layout-scroll" class="flex items-center p-4 bg-gray-700 rounded-lg cursor-pointer">
<input type="radio" id="layout-scroll" name="layout" value="scroll"
class="h-5 w-5 text-indigo-600 border-gray-500 focus:ring-indigo-500" />
<span class="ml-3 flex flex-col">
<span class="font-medium text-gray-200">Scroll</span>
<span class="text-sm text-gray-400">A single, vertical column of large images.</span>
</span>
</label>
<label for="layout-grid" class="flex items-center p-4 bg-gray-700 rounded-lg cursor-pointer">
<input type="radio" id="layout-grid" name="layout" value="grid"
class="h-5 w-5 text-indigo-600 border-gray-500 focus:ring-indigo-500" />
<span class="ml-3 flex flex-col">
<span class="font-medium text-gray-200">Grid</span>
<span class="text-sm text-gray-400">A "Masonry" layout that adapts to image height.</span>
</span>
</label>
<label for="layout-compact" class="flex items-center p-4 bg-gray-700 rounded-lg cursor-pointer">
<input type="radio" id="layout-compact" name="layout" value="compact"
class="h-5 w-5 text-indigo-600 border-gray-500 focus:ring-indigo-500" />
<span class="ml-3 flex flex-col">
<span class="font-medium text-gray-200">Compact</span>
<span class="text-sm text-gray-400">A responsive grid of static-sized cards.</span>
</span>
</label>
</fieldset>
</div>
</div>
</div>
</div>
<div id="search-modal"
class="hidden fixed inset-0 z-30 bg-black/70 backdrop-blur-md flex items-start justify-center p-8">
<div class="bg-gray-800 p-4 rounded-lg shadow-xl w-full max-w-lg relative">
<button id="search-close-button" class="absolute top-3 right-3 p-2 text-gray-400 hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<h2 class="text-xl font-semibold mb-4">Search</h2>
<div class="flex space-x-2">
<input type="search" id="search-input" placeholder="Search tags..."
class="flex-1 p-3 rounded-lg bg-gray-700 border border-gray-600 text-white placeholder-gray-400 dark-focus-ring" />
<button id="search-button"
class="px-5 py-3 rounded-lg bg-indigo-600 font-semibold text-white hover:bg-indigo-700 dark-focus-ring">
Search
</button>
</div>
</div>
</div>
<div id="tag-info-modal"
class="hidden fixed inset-0 z-30 bg-black/70 backdrop-blur-md flex items-start justify-center p-8"
aria-modal="true">
<div class="bg-gray-800 p-6 rounded-lg shadow-xl w-full max-w-lg relative">
<button id="tag-info-close-button" class="absolute top-3 right-3 p-2 text-gray-400 hover:text-white">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
class="w-6 h-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<h2 class="text-xl font-semibold mb-4">Image Tags</h2>
<div id="tag-info-content" class="flex flex-wrap gap-2 max-h-[60vh] overflow-y-auto">
</div>
</div>
</div>
<div id="message-bar"
class="hidden fixed bottom-4 right-4 bg-green-600 text-white px-6 py-3 rounded-lg shadow-xl transition-all duration-300 transform translate-y-16">
Message
</div>
<div id="updateToast" class="toast hidden">
<p>An update is required for Waifu Board! newest version - <span id="latestVersionDisplay"></span></p>
</div>
<script type="module" src="../src/renderer.js"></script>
<script src="../src/updateNotification.js"></script>
<script type="module" src="../src/renderer.js"></script>
<script type="module" src="../scripts/main.js"></script>
<script src="../src/updateNotification.js"></script>
<script>
// Simple Enter key handler for search
const searchInput = document.getElementById('search-input');
const searchBtn = document.getElementById('search-button');
searchInput.addEventListener('keydown', (e) => {
if (e.key === 'Enter') searchBtn.click();
});
</script>
</body>
</html>