better titlebar and fixes
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
;(() => {
|
||||
const token = localStorage.getItem("token")
|
||||
|
||||
if (!token && window.location.pathname !== "/") {
|
||||
window.location.href = "/"
|
||||
}
|
||||
@@ -12,41 +11,61 @@ async function loadMeUI() {
|
||||
|
||||
try {
|
||||
const res = await fetch("/api/me", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
|
||||
if (!res.ok) return
|
||||
|
||||
const user = await res.json()
|
||||
const avatarUrl = user.avatar || "/public/assets/avatar.png"
|
||||
|
||||
const navUser = document.getElementById("nav-user")
|
||||
const navUsername = document.getElementById("nav-username")
|
||||
const navAvatar = document.getElementById("nav-avatar")
|
||||
const dropdownAvatar = document.getElementById("dropdown-avatar")
|
||||
|
||||
if (!navUser || !navUsername || !navAvatar) return
|
||||
if (navUser && navUsername && navAvatar) {
|
||||
navUser.style.display = "flex"
|
||||
navUsername.textContent = user.username
|
||||
navAvatar.src = avatarUrl
|
||||
if (dropdownAvatar) dropdownAvatar.src = avatarUrl
|
||||
}
|
||||
|
||||
navUser.style.display = "flex"
|
||||
navUsername.textContent = user.username
|
||||
const titlebarUserBox = document.getElementById("titlebar-user-box")
|
||||
const titlebarUsername = document.getElementById("titlebar-username")
|
||||
const titlebarAvatar = document.getElementById("titlebar-avatar")
|
||||
const titlebarDropdownAvatar = document.getElementById("titlebar-dropdown-avatar")
|
||||
const titlebarDropdownUsername = document.getElementById("titlebar-dropdown-username")
|
||||
|
||||
const avatarUrl = user.avatar || "/public/assets/avatar.png"
|
||||
navAvatar.src = avatarUrl
|
||||
if (dropdownAvatar) {
|
||||
dropdownAvatar.src = avatarUrl
|
||||
if (titlebarUserBox && titlebarUsername && titlebarAvatar) {
|
||||
titlebarUserBox.style.display = "flex"
|
||||
|
||||
titlebarUsername.textContent = user.username
|
||||
titlebarAvatar.src = avatarUrl
|
||||
|
||||
if (titlebarDropdownAvatar) titlebarDropdownAvatar.src = avatarUrl
|
||||
if (titlebarDropdownUsername) titlebarDropdownUsername.textContent = user.username
|
||||
}
|
||||
|
||||
setupDropdown()
|
||||
|
||||
} catch (e) {
|
||||
console.error("Failed to load user UI:", e)
|
||||
}
|
||||
}
|
||||
|
||||
// Variable para saber si el modal ya fue cargado
|
||||
let settingsModalLoaded = false;
|
||||
|
||||
document.getElementById('nav-settings').addEventListener('click', openSettings)
|
||||
const navSettingsBtn = document.getElementById('nav-settings');
|
||||
const titlebarSettingsBtn = document.getElementById('titlebar-settings');
|
||||
|
||||
if (navSettingsBtn) navSettingsBtn.addEventListener('click', openSettings);
|
||||
if (titlebarSettingsBtn) titlebarSettingsBtn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
openSettings();
|
||||
document.getElementById("titlebar-dropdown")?.classList.remove("active");
|
||||
});
|
||||
|
||||
async function openSettings() {
|
||||
if (!settingsModalLoaded) {
|
||||
@@ -55,63 +74,69 @@ async function openSettings() {
|
||||
const html = await res.text()
|
||||
document.body.insertAdjacentHTML('beforeend', html)
|
||||
settingsModalLoaded = true;
|
||||
|
||||
// Esperar un momento para que el DOM se actualice
|
||||
await new Promise(resolve => setTimeout(resolve, 50));
|
||||
|
||||
// Ahora cargar los settings
|
||||
if (window.toggleSettingsModal) {
|
||||
await window.toggleSettingsModal(false);
|
||||
}
|
||||
if (window.toggleSettingsModal) await window.toggleSettingsModal(false);
|
||||
} catch (err) {
|
||||
console.error('Error loading settings modal:', err);
|
||||
}
|
||||
} else {
|
||||
if (window.toggleSettingsModal) {
|
||||
await window.toggleSettingsModal(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeSettings() {
|
||||
const modal = document.getElementById('settings-modal');
|
||||
if (modal) {
|
||||
modal.classList.add('hidden');
|
||||
if (window.toggleSettingsModal) await window.toggleSettingsModal(false);
|
||||
}
|
||||
}
|
||||
|
||||
function setupDropdown() {
|
||||
|
||||
const userAvatarBtn = document.querySelector(".user-avatar-btn")
|
||||
const navDropdown = document.getElementById("nav-dropdown")
|
||||
const navLogout = document.getElementById("nav-logout")
|
||||
|
||||
if (!userAvatarBtn || !navDropdown || !navLogout) return
|
||||
if (userAvatarBtn && navDropdown) {
|
||||
userAvatarBtn.addEventListener("click", (e) => {
|
||||
e.stopPropagation()
|
||||
navDropdown.classList.toggle("active")
|
||||
|
||||
userAvatarBtn.addEventListener("click", (e) => {
|
||||
e.stopPropagation()
|
||||
navDropdown.classList.toggle("active")
|
||||
})
|
||||
document.getElementById("titlebar-dropdown")?.classList.remove("active")
|
||||
})
|
||||
if (navLogout) {
|
||||
navLogout.addEventListener("click", () => {
|
||||
localStorage.removeItem("token")
|
||||
window.location.href = "/"
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const titlebarUserBox = document.getElementById("titlebar-user-box")
|
||||
const titlebarDropdown = document.getElementById("titlebar-dropdown")
|
||||
const titlebarLogout = document.getElementById("titlebar-logout")
|
||||
|
||||
if (titlebarUserBox && titlebarDropdown) {
|
||||
titlebarUserBox.addEventListener("click", (e) => {
|
||||
e.stopPropagation()
|
||||
titlebarDropdown.classList.toggle("active")
|
||||
|
||||
document.getElementById("nav-dropdown")?.classList.remove("active")
|
||||
})
|
||||
|
||||
if (titlebarLogout) {
|
||||
titlebarLogout.addEventListener("click", (e) => {
|
||||
e.stopPropagation()
|
||||
localStorage.removeItem("token")
|
||||
window.location.href = "/"
|
||||
})
|
||||
}
|
||||
|
||||
titlebarDropdown.addEventListener("click", (e) => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
}
|
||||
|
||||
document.addEventListener("click", (e) => {
|
||||
if (!navDropdown.contains(e.target)) {
|
||||
if (navDropdown && !navDropdown.contains(e.target)) {
|
||||
navDropdown.classList.remove("active")
|
||||
}
|
||||
})
|
||||
|
||||
navDropdown.addEventListener("click", (e) => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
|
||||
navLogout.addEventListener("click", () => {
|
||||
localStorage.removeItem("token")
|
||||
window.location.href = "/"
|
||||
})
|
||||
|
||||
const dropdownLinks = navDropdown.querySelectorAll("a.dropdown-item")
|
||||
dropdownLinks.forEach((link) => {
|
||||
link.addEventListener("click", () => {
|
||||
navDropdown.classList.remove("active")
|
||||
})
|
||||
if (titlebarDropdown && !titlebarDropdown.contains(e.target)) {
|
||||
titlebarDropdown.classList.remove("active")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -159,7 +184,6 @@ searchWrapper.addEventListener('click', (e) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Cerrar el buscador si se hace clic fuera
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!searchWrapper.contains(e.target)) {
|
||||
searchWrapper.classList.remove('active-mobile');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const reader = document.getElementById('reader');
|
||||
const panel = document.getElementById('settings-panel');
|
||||
const overlay = document.getElementById('overlay');
|
||||
const overlay2 = document.getElementById('overlay');
|
||||
const settingsBtn = document.getElementById('settings-btn');
|
||||
const closePanel = document.getElementById('close-panel');
|
||||
const chapterLabel = document.getElementById('chapter-label');
|
||||
@@ -665,14 +665,14 @@ document.getElementById('back-btn').addEventListener('click', () => {
|
||||
// Panel de configuración
|
||||
settingsBtn.addEventListener('click', () => {
|
||||
panel.classList.add('open');
|
||||
overlay.classList.add('active');
|
||||
overlay2.classList.add('active');
|
||||
});
|
||||
closePanel.addEventListener('click', closeSettings);
|
||||
overlay.addEventListener('click', closeSettings);
|
||||
overlay2.addEventListener('click', closeSettings);
|
||||
|
||||
function closeSettings() {
|
||||
panel.classList.remove('open');
|
||||
overlay.classList.remove('active');
|
||||
overlay2.classList.remove('active');
|
||||
}
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape' && panel.classList.contains('open')) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const providerSelector = document.getElementById('provider-selector');
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const searchInput2 = document.getElementById('search-input');
|
||||
const resultsContainer = document.getElementById('gallery-results');
|
||||
|
||||
let currentPage = 1;
|
||||
@@ -231,7 +231,7 @@ function showSkeletons(count, append = false) {
|
||||
async function searchGallery(isLoadMore = false) {
|
||||
if (isLoading) return;
|
||||
|
||||
const query = searchInput.value.trim();
|
||||
const query = searchInput2.value.trim();
|
||||
const provider = providerSelector.value;
|
||||
const page = isLoadMore ? currentPage + 1 : 1;
|
||||
|
||||
@@ -351,22 +351,22 @@ async function loadExtensions() {
|
||||
|
||||
providerSelector.addEventListener('change', () => {
|
||||
if (providerSelector.value === 'favorites') {
|
||||
searchInput.placeholder = "Search in favorites...";
|
||||
searchInput2.placeholder = "Search in favorites...";
|
||||
} else {
|
||||
searchInput.placeholder = "Search in gallery...";
|
||||
searchInput2.placeholder = "Search in gallery...";
|
||||
}
|
||||
searchGallery(false);
|
||||
});
|
||||
|
||||
let searchTimeout;
|
||||
|
||||
searchInput.addEventListener('input', () => {
|
||||
searchInput2.addEventListener('input', () => {
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => {
|
||||
searchGallery(false);
|
||||
}, 500);
|
||||
});
|
||||
searchInput.addEventListener('keydown', e => {
|
||||
searchInput2.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') {
|
||||
clearTimeout(searchTimeout);
|
||||
searchGallery(false);
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
|
||||
import {FastifyInstance, FastifyReply, FastifyRequest} from 'fastify';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
let cachedTitlebar: string | null = null;
|
||||
|
||||
function getTitlebarHTML(): string {
|
||||
if (!cachedTitlebar) {
|
||||
|
||||
const titlebarPath = path.join(__dirname, '..', '..', 'views', 'components', 'titlebar.html');
|
||||
cachedTitlebar = fs.readFileSync(titlebarPath, 'utf-8');
|
||||
}
|
||||
return cachedTitlebar;
|
||||
}
|
||||
|
||||
let cachedNavbar: string | null = null;
|
||||
|
||||
function getNavbarHTML(activePage: string, showSearch: boolean = true): string {
|
||||
@@ -14,6 +25,7 @@ function getNavbarHTML(activePage: string, showSearch: boolean = true): string {
|
||||
|
||||
const pages = ['anime', 'books', 'gallery', 'schedule' , 'marketplace'];
|
||||
pages.forEach(page => {
|
||||
|
||||
const regex = new RegExp(`(<button class="nav-button[^"]*)"\\s+data-page="${page}"`, 'g');
|
||||
if (page === activePage) {
|
||||
navbar = navbar.replace(regex, `$1 active" data-page="${page}"`);
|
||||
@@ -30,10 +42,15 @@ function getNavbarHTML(activePage: string, showSearch: boolean = true): string {
|
||||
return navbar;
|
||||
}
|
||||
|
||||
function injectNavbar(htmlContent: string, activePage: string, showSearch: boolean = true): string {
|
||||
const navbar = getNavbarHTML(activePage, showSearch);
|
||||
function injectLayout(htmlContent: string, activePage: string | null = null, showSearch: boolean = true): string {
|
||||
let contentToInject = getTitlebarHTML();
|
||||
|
||||
return htmlContent.replace(/<body[^>]*>/, `$&\n${navbar}`);
|
||||
if (activePage !== null) {
|
||||
const navbar = getNavbarHTML(activePage, showSearch);
|
||||
contentToInject += `\n${navbar}`;
|
||||
}
|
||||
|
||||
return htmlContent.replace(/<body[^>]*>/, `$&\n${contentToInject}`);
|
||||
}
|
||||
|
||||
async function viewsRoutes(fastify: FastifyInstance) {
|
||||
@@ -41,105 +58,116 @@ async function viewsRoutes(fastify: FastifyInstance) {
|
||||
fastify.get('/', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'users.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/anime', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'anime', 'animes.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'anime', true);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'anime', true);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/profile', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'profile.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, '', false);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, '', false);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/books', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'books', 'books.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'books', true);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'books', true);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/schedule', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'schedule.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'schedule', false);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'schedule', false);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/gallery', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'gallery', 'gallery.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'gallery', true);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'gallery', true);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/marketplace', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'marketplace.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'marketplace', false);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'marketplace', false);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/gallery/:extension/*', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'gallery', 'image.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'gallery', true);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'gallery', true);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/gallery/favorites/*', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'gallery', 'image.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
const htmlWithNavbar = injectNavbar(html, 'gallery', true);
|
||||
reply.type('text/html').send(htmlWithNavbar);
|
||||
const finalHtml = injectLayout(html, 'gallery', true);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/anime/:id', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'anime', 'anime.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/anime/:extension/*', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'anime', 'anime.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/book/:id', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'books', 'book.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/book/:extension/*', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'books', 'book.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/read/:provider/:chapter/*', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'books', 'read.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.get('/room', (req: FastifyRequest, reply: FastifyReply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', 'room.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.type('text/html').send(html);
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.type('text/html').send(finalHtml);
|
||||
});
|
||||
|
||||
fastify.setNotFoundHandler((req, reply) => {
|
||||
const htmlPath = path.join(__dirname, '..', '..', 'views', '404.html');
|
||||
const html = fs.readFileSync(htmlPath, 'utf-8');
|
||||
reply.code(404).type('text/html').send(html);
|
||||
const finalHtml = injectLayout(html, null);
|
||||
reply.code(404).type('text/html').send(finalHtml);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -45,18 +45,6 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">−</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="navbar" id="navbar">
|
||||
<a href="#" class="nav-brand">
|
||||
<div class="brand-icon">
|
||||
|
||||
@@ -15,21 +15,11 @@
|
||||
<link rel="stylesheet" href="/views/css/anime/anime.css" />
|
||||
<link rel="stylesheet" href="/views/css/anime/player.css" />
|
||||
<link rel="stylesheet" href="/views/css/components/match-modal.css">
|
||||
<link rel="stylesheet" href="/views/css/components/titlebar.css">
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
<link rel="stylesheet" href="/views/css/components/titlebar.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">−</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<a href="/anime" class="back-btn">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 12H5"/><path d="M12 19l-7-7 7-7"/>
|
||||
|
||||
@@ -17,18 +17,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">−</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-wrapper">
|
||||
<div class="hero-background">
|
||||
<img id="hero-bg-media" alt="">
|
||||
|
||||
@@ -15,16 +15,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<a href="/books" class="back-btn">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M19 12H5"/><path d="M12 19l-7-7 7-7"/>
|
||||
|
||||
@@ -16,17 +16,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-wrapper">
|
||||
<div class="hero-background">
|
||||
<img id="hero-bg-media" src="" alt="">
|
||||
|
||||
@@ -12,17 +12,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header class="top-bar">
|
||||
<button id="back-btn" class="glass-btn">
|
||||
← Back
|
||||
|
||||
57
desktop/views/components/titlebar.html
Normal file
57
desktop/views/components/titlebar.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<div class="app-icon">
|
||||
<img src="/public/assets/waifuboards.ico" alt="WB"/>
|
||||
</div>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
|
||||
<div class="title-drag-area"></div>
|
||||
|
||||
<div class="title-right">
|
||||
|
||||
<div class="user-box" id="titlebar-user-box" style="display: none;">
|
||||
<img id="titlebar-avatar" src="/public/assets/waifuboards.ico" alt="User" />
|
||||
<span id="titlebar-username">Guest</span>
|
||||
|
||||
<div class="nav-dropdown" id="titlebar-dropdown">
|
||||
<div class="dropdown-header">
|
||||
<img id="titlebar-dropdown-avatar" src="/public/assets/waifuboards.ico" class="dropdown-avatar">
|
||||
<div class="dropdown-user-info">
|
||||
<div class="dropdown-username" id="titlebar-dropdown-username">Guest</div>
|
||||
<div class="dropdown-status">Online</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="/profile" class="dropdown-item">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
|
||||
<button class="dropdown-item" id="titlebar-settings">
|
||||
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06A1.65 1.65 0 0 0 15 19.4a1.65 1.65 0 0 0-1 .6 1.65 1.65 0 0 0-.33 1.82V22a2 2 0 1 1-4 0v-.18a1.65 1.65 0 0 0-.33-1.82 1.65 1.65 0 0 0-1-.6 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.6 15a1.65 1.65 0 0 0-.6-1 1.65 1.65 0 0 0-1.82-.33H2a2 2 0 1 1 0-4h.18a1.65 1.65 0 0 0 1.82-.33 1.65 1.65 0 0 0 .6-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.6c.37 0 .72-.14 1-.6A1.65 1.65 0 0 0 10.33 2.18V2a2 2 0 1 1 4 0v.18a1.65 1.65 0 0 0 .33 1.82c.28.46.63.6 1 .6a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9c0 .37.14.72.6 1 .46.28.6.63.6 1z"/></svg>
|
||||
<span>Settings</span>
|
||||
</button>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<button class="dropdown-item logout-item" id="titlebar-logout">
|
||||
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
|
||||
<span>Logout</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="window-controls">
|
||||
<button class="control-btn min" title="Minimize">
|
||||
<svg width="11" height="1" viewBox="0 0 11 1"><path d="M0 0h11v1H0z" fill="currentColor"/></svg>
|
||||
</button>
|
||||
<button class="control-btn max" title="Maximize">
|
||||
<svg width="10" height="10" viewBox="0 0 10 10"><path d="M1 1v8h8V1H1zm1 1h6v6H2V2z" fill="currentColor"/></svg>
|
||||
</button>
|
||||
<button class="control-btn close" title="Close">
|
||||
<svg width="11" height="11" viewBox="0 0 11 11"><path d="M5.5 4.793L1.854 1.146.646 2.354 4.293 6 .646 9.646l1.208 1.208L5.5 7.207l3.646 3.647 1.208-1.208L6.707 6l3.647-3.646-1.208-1.208L5.5 4.793z" fill="currentColor"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +1,7 @@
|
||||
:root {
|
||||
--titlebar-height: 40px;
|
||||
--primary-glass: rgba(9, 9, 11, 0.95);
|
||||
--border-color: rgba(139, 92, 246, 0.2);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -34,7 +36,7 @@ html.electron .panel-content {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
html.electron .calendar-wrapper{
|
||||
html.electron .calendar-wrapper {
|
||||
margin-top: 4rem;
|
||||
}
|
||||
|
||||
@@ -47,42 +49,46 @@ html.electron .back-btn {
|
||||
}
|
||||
|
||||
#titlebar {
|
||||
display: none;
|
||||
width: calc(100vw - 12px); display: none;
|
||||
|
||||
height: var(--titlebar-height);
|
||||
background: rgba(9, 9, 11, 0.95);
|
||||
background: var(--primary-glass);
|
||||
color: white;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
padding-left: 12px;
|
||||
padding-right: 0;
|
||||
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
font-family: "Inter", system-ui, sans-serif;
|
||||
border-bottom: 1px solid rgba(139, 92, 246, 0.2);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
z-index: 999999;
|
||||
|
||||
font-family: "Inter", system-ui, sans-serif;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
backdrop-filter: blur(12px);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.title-left {
|
||||
display: flex;
|
||||
align-items: center !important;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#titlebar .app-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
background: rgba(139, 92, 246, 0.15);
|
||||
border: 1px solid rgba(139, 92, 246, 0.3);
|
||||
padding: 3px;
|
||||
border-radius: 5px;
|
||||
background: rgba(139, 92, 246, 0.1);
|
||||
border: 1px solid rgba(139, 92, 246, 0.25);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#titlebar .app-icon img {
|
||||
@@ -95,85 +101,19 @@ html.electron .back-btn {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
letter-spacing: -0.2px;
|
||||
letter-spacing: -0.1px;
|
||||
}
|
||||
|
||||
.title-drag-area {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.title-right {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
.title-right button {
|
||||
-webkit-app-region: no-drag;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
width: 46px;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.title-right button svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.title-right button:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.title-right button:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.title-right .min:hover {
|
||||
background: rgba(139, 92, 246, 0.2);
|
||||
}
|
||||
|
||||
.title-right .max:hover {
|
||||
background: rgba(34, 197, 94, 0.2);
|
||||
}
|
||||
|
||||
.title-right .close:hover {
|
||||
background: #e81123;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.title-right button:hover svg {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-track {
|
||||
background: #09090b;
|
||||
margin-top: var(--titlebar-height);
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-thumb {
|
||||
background: rgba(139, 92, 246, 0.3);
|
||||
border-radius: 6px;
|
||||
border: 2px solid #09090b;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(139, 92, 246, 0.5);
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.user-box {
|
||||
@@ -181,18 +121,104 @@ body {
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-right: 12px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
transition: background 0.2s;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.user-box:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.user-box img {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 1px solid rgba(139, 92, 246, 0.3);
|
||||
}
|
||||
|
||||
.user-box span {
|
||||
font-size: 13px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
opacity: 0.9;
|
||||
color: #e4e4e7;
|
||||
}
|
||||
|
||||
.window-controls {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: #a1a1aa;
|
||||
width: 46px;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.control-btn:hover {
|
||||
color: white;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
.control-btn.min:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.control-btn.max:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.control-btn.close:hover {
|
||||
background: #e81123;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.control-btn:active {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
.control-btn.close:active {
|
||||
background: #bf0f1d;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-track {
|
||||
background: #09090b;
|
||||
margin-top: var(--titlebar-height);
|
||||
border-left: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-thumb {
|
||||
background: rgba(139, 92, 246, 0.3);
|
||||
border-radius: 6px;
|
||||
border: 2px solid #09090b;
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(139, 92, 246, 0.5);
|
||||
border: 2px solid #09090b;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
@@ -208,3 +234,151 @@ html.electron #room-view {
|
||||
html.electron #room-view .room-layout {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#titlebar-user-box {
|
||||
position: relative;
|
||||
z-index: 1000000;
|
||||
}
|
||||
|
||||
#titlebar-dropdown {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
right: 0;
|
||||
width: 240px;
|
||||
background: rgba(18, 18, 21, 0.98);
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
|
||||
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
z-index: 1000001;
|
||||
|
||||
transform-origin: top right;
|
||||
animation: titlebarDropdownSlide 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
||||
}
|
||||
|
||||
#titlebar-dropdown.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@keyframes titlebarDropdownSlide {
|
||||
from { opacity: 0; transform: scale(0.95) translateY(-5px); }
|
||||
to { opacity: 1; transform: scale(1) translateY(0); }
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
background: rgba(139, 92, 246, 0.05);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-avatar {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #8b5cf6;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-username {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-status {
|
||||
font-size: 11px;
|
||||
color: #22c55e;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 16px;
|
||||
color: #a1a1aa;
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
background: transparent;
|
||||
border: none;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-item:hover {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: white;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-item svg {
|
||||
color: inherit;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-item:hover svg {
|
||||
color: #8b5cf6;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .dropdown-divider {
|
||||
height: 1px;
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .logout-item {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .logout-item:hover {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
#titlebar-dropdown .logout-item:hover svg {
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
html.electron::-webkit-scrollbar-track {
|
||||
margin-top: var(--titlebar-height);
|
||||
}
|
||||
|
||||
#titlebar .control-btn {
|
||||
width: 46px !important;
|
||||
height: 100% !important;
|
||||
color: #a1a1aa;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
#titlebar .control-btn svg {
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
max-width: 14px;
|
||||
max-height: 14px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#titlebar .app-icon img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
max-width: none;
|
||||
}
|
||||
@@ -10,23 +10,11 @@
|
||||
<link rel="icon" href="/public/assets/waifuboards.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" href="/views/css/components/updateNotifier.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
|
||||
<script src="/src/scripts/room-modal.js"></script>
|
||||
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js" async></script>
|
||||
<link rel="stylesheet" href="/views/css/components/titlebar.css">
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="gallery-main">
|
||||
<div class="gallery-hero-placeholder"></div>
|
||||
|
||||
|
||||
@@ -16,17 +16,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="/gallery" class="back-btn">
|
||||
<svg width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path d="M15 19l-7-7 7-7"/></svg>
|
||||
Back to Gallery
|
||||
|
||||
@@ -14,18 +14,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hero-spacer"></div>
|
||||
|
||||
<main>
|
||||
|
||||
@@ -15,17 +15,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">−</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-wrapper">
|
||||
<section class="profile-header">
|
||||
|
||||
@@ -18,17 +18,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar">
|
||||
<div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">−</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="room-view">
|
||||
<div class="room-layout" id="room-layout">
|
||||
<div class="video-area">
|
||||
|
||||
@@ -17,17 +17,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ambient-bg" id="ambientBg"></div>
|
||||
|
||||
<div class="calendar-wrapper">
|
||||
|
||||
@@ -11,16 +11,6 @@
|
||||
<script src="/src/scripts/titlebar.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="titlebar"> <div class="title-left">
|
||||
<img class="app-icon" src="/public/assets/waifuboards.ico" alt=""/>
|
||||
<span class="app-title">WaifuBoard</span>
|
||||
</div>
|
||||
<div class="title-right">
|
||||
<button class="min">—</button>
|
||||
<button class="max">🗖</button>
|
||||
<button class="close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-wrapper">
|
||||
<div class="background-gradient"></div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const providerSelector = document.getElementById('provider-selector');
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const searchInput2 = document.getElementById('search-input');
|
||||
const resultsContainer = document.getElementById('gallery-results');
|
||||
|
||||
let currentPage = 1;
|
||||
@@ -231,7 +231,7 @@ function showSkeletons(count, append = false) {
|
||||
async function searchGallery(isLoadMore = false) {
|
||||
if (isLoading) return;
|
||||
|
||||
const query = searchInput.value.trim();
|
||||
const query = searchInput2.value.trim();
|
||||
const provider = providerSelector.value;
|
||||
const page = isLoadMore ? currentPage + 1 : 1;
|
||||
|
||||
@@ -351,22 +351,22 @@ async function loadExtensions() {
|
||||
|
||||
providerSelector.addEventListener('change', () => {
|
||||
if (providerSelector.value === 'favorites') {
|
||||
searchInput.placeholder = "Search in favorites...";
|
||||
searchInput2.placeholder = "Search in favorites...";
|
||||
} else {
|
||||
searchInput.placeholder = "Search in gallery...";
|
||||
searchInput2.placeholder = "Search in gallery...";
|
||||
}
|
||||
searchGallery(false);
|
||||
});
|
||||
|
||||
let searchTimeout;
|
||||
|
||||
searchInput.addEventListener('input', () => {
|
||||
searchInput2.addEventListener('input', () => {
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => {
|
||||
searchGallery(false);
|
||||
}, 500);
|
||||
});
|
||||
searchInput.addEventListener('keydown', e => {
|
||||
searchInput2.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') {
|
||||
clearTimeout(searchTimeout);
|
||||
searchGallery(false);
|
||||
|
||||
Reference in New Issue
Block a user