diff --git a/desktop/src/scripts/auth-guard.js b/desktop/src/scripts/auth-guard.js index 965f91e..ee3f277 100644 --- a/desktop/src/scripts/auth-guard.js +++ b/desktop/src/scripts/auth-guard.js @@ -116,6 +116,56 @@ function setupDropdown() { } loadMeUI() + +const mobileToggle = document.getElementById('mobile-menu-toggle'); +const navCenter = document.querySelector('.nav-center'); + +let overlay = document.querySelector('.menu-overlay'); +if (!overlay) { + overlay = document.createElement('div'); + overlay.className = 'menu-overlay'; + document.body.appendChild(overlay); +} + +function toggleMenu() { + navCenter.classList.toggle('open'); + overlay.classList.toggle('active'); + + const isOpen = navCenter.classList.contains('open'); + mobileToggle.innerHTML = isOpen + ? '' + : ''; +} + +mobileToggle.addEventListener('click', toggleMenu); + +overlay.addEventListener('click', () => { + if (navCenter.classList.contains('open')) toggleMenu(); +}); + +navCenter.querySelectorAll('.nav-button').forEach(btn => { + btn.addEventListener('click', () => { + if (navCenter.classList.contains('open')) toggleMenu(); + }); +}); + +const searchWrapper = document.querySelector('.search-wrapper'); +const searchInput = document.getElementById('search-input'); + +searchWrapper.addEventListener('click', (e) => { + if (window.innerWidth <= 768) { + searchWrapper.classList.add('active-mobile'); + searchInput.focus(); + } +}); + +// Cerrar el buscador si se hace clic fuera +document.addEventListener('click', (e) => { + if (!searchWrapper.contains(e.target)) { + searchWrapper.classList.remove('active-mobile'); + } +}); + const createRoomModal = new CreateRoomModal(); const createBtn = document.getElementById('nav-create-party'); diff --git a/desktop/views/components/navbar.html b/desktop/views/components/navbar.html index 8dd9a4c..129dca9 100644 --- a/desktop/views/components/navbar.html +++ b/desktop/views/components/navbar.html @@ -78,5 +78,10 @@ + \ No newline at end of file diff --git a/desktop/views/css/components/anilist-modal.css b/desktop/views/css/components/anilist-modal.css index 8cf918b..aa49348 100644 --- a/desktop/views/css/components/anilist-modal.css +++ b/desktop/views/css/components/anilist-modal.css @@ -122,12 +122,23 @@ background: var(--input-bg); border: 1px solid var(--border-subtle); color: white; - padding: 0.9rem 1rem; border-radius: 10px; font-family: inherit; font-size: 0.95rem; font-weight: 500; transition: all 0.2s ease; + height: 45px; + padding: 0 1rem; + display: flex; + align-items: center; + width: 100%; + box-sizing: border-box; +} + +textarea.form-input { + height: auto; + padding: 1rem; + min-height: 100px; } .form-input:focus { @@ -137,13 +148,33 @@ box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15); } -.form-group.notes-group { grid-column: 1 / span 2; } -.form-group.checkbox-group { grid-column: 3 / 4; align-self: end; margin-bottom: 0.8rem; } +.form-group.notes-group { + grid-column: 1 / -1; + order: 10; +} +.form-group.checkbox-group { + grid-column: 3 / 4; + align-self: end; + margin-bottom: 0.8rem; + order: 5; +} .form-group.full-width { grid-column: 1 / -1; } .notes-textarea { resize: vertical; min-height: 100px; line-height: 1.5; } -.date-group { display: flex; gap: 1.5rem; } -.date-input-pair { flex: 1; display: flex; flex-direction: column; gap: 0.6rem; } +/* Cambia de 3 columnas a 2 columnas para que Start y End llenen el espacio */ +.date-group { + display: grid; + grid-template-columns: 1fr 1fr; /* Antes era 1fr 1fr 1fr */ + gap: 2rem; + width: 100%; +} + +.date-input-pair { + display: flex; + flex-direction: column; + gap: 0.6rem; + width: 100%; +} .checkbox-group { flex-direction: row; @@ -276,4 +307,10 @@ .btn-primary { order: 1; } .btn-secondary { order: 2; } .btn-danger { order: 3; margin-top: 0.5rem; } +} + +input[type="date"].form-input { + display: block; /* Elimina el comportamiento flex */ + text-align: left; /* Asegura alineación a la izquierda */ + padding-top: 10px; /* Ajuste pequeño para centrar verticalmente si es necesario */ } \ No newline at end of file diff --git a/desktop/views/css/components/navbar.css b/desktop/views/css/components/navbar.css index 048eb64..84a1871 100644 --- a/desktop/views/css/components/navbar.css +++ b/desktop/views/css/components/navbar.css @@ -8,7 +8,11 @@ align-items: center; justify-content: space-between; padding: 0 3rem; - background: linear-gradient(to bottom, rgba(9, 9, 11, 0.9) 0%, rgba(9, 9, 11, 0) 100%); + background: linear-gradient( + to bottom, + rgba(9, 9, 11, 0.9) 0%, + rgba(9, 9, 11, 0) 100% + ); transition: background 0.3s; } @@ -211,7 +215,9 @@ min-width: 260px; display: none; flex-direction: column; - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(139, 92, 246, 0.1); + box-shadow: + 0 20px 40px rgba(0, 0, 0, 0.6), + 0 0 0 1px rgba(139, 92, 246, 0.1); z-index: 9999; overflow: hidden; animation: dropdownSlide 0.2s ease-out; @@ -415,4 +421,178 @@ .search-results::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 3px; +} + +.mobile-menu-toggle { + display: none; + justify-content: center; + align-items: center; + width: 44px; + height: 44px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + color: white; + z-index: 2001; + cursor: pointer; + transition: all 0.2s; +} + +@media (max-width: 768px) { + + .navbar { + height: 70px; + padding: 0 1.5rem; + background: rgba(9, 9, 11, 0.8); + backdrop-filter: blur(15px); + border-bottom: 1px solid rgba(255,255,255,0.05); + } + + .nav-brand span { display: none; } + .brand-icon { width: 40px; height: 40px; } + + .mobile-menu-toggle { + display: flex; + } + .mobile-menu-toggle:active { transform: scale(0.95); } + + .nav-center { + + position: fixed; + top: 0; + right: -100%; + width: 85%; + max-width: 320px; + height: 100vh; + + border-radius: 0; + border: none; + + background: linear-gradient(160deg, rgba(20, 20, 25, 0.98) 0%, rgba(10, 10, 12, 0.99) 100%); + box-shadow: -10px 0 40px rgba(0, 0, 0, 0.6); + + border-left: 1px solid rgba(255, 255, 255, 0.08); + + display: flex; + flex-direction: column; + justify-content: center; + padding: 2rem; + gap: 1rem; + z-index: 2000; + + transition: right 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); + } + + .nav-center.open { + right: 0; + } + + .nav-button { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 1.2rem 1.5rem; + + font-size: 1.2rem; + font-weight: 700; + letter-spacing: 0.5px; + color: rgba(255, 255, 255, 0.6); + text-transform: uppercase; + + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.03); + border-radius: 16px; + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); + + opacity: 0; + transform: translateX(20px); + } + + .nav-button:hover { + background: rgba(255, 255, 255, 0.05); + color: white; + padding-left: 2rem; + } + + .nav-button.active { + background: linear-gradient(90deg, rgba(139, 92, 246, 0.2) 0%, transparent 100%); + border-color: rgba(139, 92, 246, 0.4); + color: white; + box-shadow: 0 4px 20px rgba(139, 92, 246, 0.15); + opacity: 1; + transform: translateX(0); + } + + .nav-center.open .nav-button { + opacity: 1; + transform: translateX(0); + } + + .nav-button.active::before { + content: ''; + position: absolute; + left: 0; + height: 50%; + width: 3px; + background: #8b5cf6; + border-radius: 0 4px 4px 0; + box-shadow: 0 0 10px #8b5cf6; + } + + .search-wrapper { + margin-left: 10px; + margin-right: auto; + width: 40px; + height: 40px; + display: flex; + align-items: center; + position: relative; + cursor: pointer; + } + + .search-input { + opacity: 0; + width: 0; + padding: 0; + pointer-events: none; /* No clickable cuando está oculto */ + position: absolute; + left: 0; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 2005; + } + + /* Estado expandido al tocar */ + .search-wrapper:focus-within { + width: 220px; /* Ancho suficiente para escribir */ + } + + .search-wrapper:focus-within .search-input { + opacity: 1; + width: 220px; + padding: 0.6rem 1rem 0.6rem 2.5rem; + background: #18181b; + border: 1px solid var(--color-primary); + border-radius: 99px; + pointer-events: auto; /* Permitir escritura */ + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); + } + + .search-wrapper.active-mobile .search-input { + opacity: 1; + width: 220px; + padding: 0.6rem 1rem 0.6rem 2.5rem; + background: #18181b; + pointer-events: auto; + } + + /* Aseguramos que el icono siempre esté arriba del input expandido */ + .search-icon { + z-index: 2006; + } + + /* Evitar que el menú lateral tape el buscador si ambos intentan estar abiertos */ + .nav-center.open { + z-index: 1999; + } } \ No newline at end of file diff --git a/desktop/views/css/profile.css b/desktop/views/css/profile.css index 9c05817..f95fb56 100644 --- a/desktop/views/css/profile.css +++ b/desktop/views/css/profile.css @@ -283,6 +283,12 @@ background-size: 1rem; } +.minimal-select option { + background-color: var(--color-bg-elevated, #18181b); + color: #e4e4e7; + padding: 10px; +} + .minimal-select:hover { background: rgba(255,255,255,0.1); color: white; } .minimal-select:focus { border-color: var(--color-primary, #8b5cf6); color: white; } diff --git a/desktop/views/css/users.css b/desktop/views/css/users.css index afdefdc..7a42a6d 100644 --- a/desktop/views/css/users.css +++ b/desktop/views/css/users.css @@ -861,23 +861,4 @@ input[type="file"] { .btn-secondary { padding: 1.2rem; } -} - -.anilist-status a.btn-secondary { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.5rem; - transition: all 0.2s; -} - -.anilist-status a.btn-secondary:hover { - border-color: var(--color-primary); - color: white; - background: rgba(139, 92, 246, 0.1); -} - -#manualAniListToken { - font-family: monospace; - font-size: 0.9rem; } \ No newline at end of file diff --git a/docker/server.js b/docker/server.js index ab1207e..f08e5bb 100644 --- a/docker/server.js +++ b/docker/server.js @@ -11,9 +11,6 @@ const { loadExtensions } = require("./dist/shared/extensions"); const {refreshTrendingAnime, refreshTopAiringAnime} = require("./dist/api/anime/anime.service"); const {refreshPopularBooks, refreshTrendingBooks} = require("./dist/api/books/books.service"); const { ensureConfigFile } = require("./dist/shared/config"); -const dotenv = require("dotenv"); - -dotenv.config(); const viewsRoutes = require("./dist/views/views.routes"); const animeRoutes = require("./dist/api/anime/anime.routes"); diff --git a/docker/src/scripts/auth-guard.js b/docker/src/scripts/auth-guard.js index 965f91e..ee3f277 100644 --- a/docker/src/scripts/auth-guard.js +++ b/docker/src/scripts/auth-guard.js @@ -116,6 +116,56 @@ function setupDropdown() { } loadMeUI() + +const mobileToggle = document.getElementById('mobile-menu-toggle'); +const navCenter = document.querySelector('.nav-center'); + +let overlay = document.querySelector('.menu-overlay'); +if (!overlay) { + overlay = document.createElement('div'); + overlay.className = 'menu-overlay'; + document.body.appendChild(overlay); +} + +function toggleMenu() { + navCenter.classList.toggle('open'); + overlay.classList.toggle('active'); + + const isOpen = navCenter.classList.contains('open'); + mobileToggle.innerHTML = isOpen + ? '' + : ''; +} + +mobileToggle.addEventListener('click', toggleMenu); + +overlay.addEventListener('click', () => { + if (navCenter.classList.contains('open')) toggleMenu(); +}); + +navCenter.querySelectorAll('.nav-button').forEach(btn => { + btn.addEventListener('click', () => { + if (navCenter.classList.contains('open')) toggleMenu(); + }); +}); + +const searchWrapper = document.querySelector('.search-wrapper'); +const searchInput = document.getElementById('search-input'); + +searchWrapper.addEventListener('click', (e) => { + if (window.innerWidth <= 768) { + searchWrapper.classList.add('active-mobile'); + searchInput.focus(); + } +}); + +// Cerrar el buscador si se hace clic fuera +document.addEventListener('click', (e) => { + if (!searchWrapper.contains(e.target)) { + searchWrapper.classList.remove('active-mobile'); + } +}); + const createRoomModal = new CreateRoomModal(); const createBtn = document.getElementById('nav-create-party'); diff --git a/docker/views/components/navbar.html b/docker/views/components/navbar.html index 8dd9a4c..129dca9 100644 --- a/docker/views/components/navbar.html +++ b/docker/views/components/navbar.html @@ -78,5 +78,10 @@ + \ No newline at end of file diff --git a/docker/views/css/components/anilist-modal.css b/docker/views/css/components/anilist-modal.css index 8cf918b..78fe1cc 100644 --- a/docker/views/css/components/anilist-modal.css +++ b/docker/views/css/components/anilist-modal.css @@ -122,12 +122,23 @@ background: var(--input-bg); border: 1px solid var(--border-subtle); color: white; - padding: 0.9rem 1rem; border-radius: 10px; font-family: inherit; font-size: 0.95rem; font-weight: 500; transition: all 0.2s ease; + height: 45px; + padding: 0 1rem; + display: flex; + align-items: center; + width: 100%; + box-sizing: border-box; +} + +textarea.form-input { + height: auto; + padding: 1rem; + min-height: 100px; } .form-input:focus { @@ -137,13 +148,32 @@ box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.15); } -.form-group.notes-group { grid-column: 1 / span 2; } -.form-group.checkbox-group { grid-column: 3 / 4; align-self: end; margin-bottom: 0.8rem; } +.form-group.notes-group { + grid-column: 1 / -1; + order: 10; +} +.form-group.checkbox-group { + grid-column: 3 / 4; + align-self: end; + margin-bottom: 0.8rem; + order: 5; +} .form-group.full-width { grid-column: 1 / -1; } .notes-textarea { resize: vertical; min-height: 100px; line-height: 1.5; } -.date-group { display: flex; gap: 1.5rem; } -.date-input-pair { flex: 1; display: flex; flex-direction: column; gap: 0.6rem; } +.date-group { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2rem; + width: 100%; +} + +.date-input-pair { + display: flex; + flex-direction: column; + gap: 0.6rem; + width: 100%; +} .checkbox-group { flex-direction: row; @@ -276,4 +306,10 @@ .btn-primary { order: 1; } .btn-secondary { order: 2; } .btn-danger { order: 3; margin-top: 0.5rem; } +} + +input[type="date"].form-input { + display: block; + text-align: left; + padding-top: 10px; } \ No newline at end of file diff --git a/docker/views/css/components/navbar.css b/docker/views/css/components/navbar.css index 63e82e3..84a1871 100644 --- a/docker/views/css/components/navbar.css +++ b/docker/views/css/components/navbar.css @@ -9,9 +9,9 @@ justify-content: space-between; padding: 0 3rem; background: linear-gradient( - to bottom, - rgba(9, 9, 11, 0.9) 0%, - rgba(9, 9, 11, 0) 100% + to bottom, + rgba(9, 9, 11, 0.9) 0%, + rgba(9, 9, 11, 0) 100% ); transition: background 0.3s; } @@ -216,8 +216,8 @@ display: none; flex-direction: column; box-shadow: - 0 20px 40px rgba(0, 0, 0, 0.6), - 0 0 0 1px rgba(139, 92, 246, 0.1); + 0 20px 40px rgba(0, 0, 0, 0.6), + 0 0 0 1px rgba(139, 92, 246, 0.1); z-index: 9999; overflow: hidden; animation: dropdownSlide 0.2s ease-out; @@ -423,104 +423,176 @@ border-radius: 3px; } +.mobile-menu-toggle { + display: none; + justify-content: center; + align-items: center; + width: 44px; + height: 44px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + color: white; + z-index: 2001; + cursor: pointer; + transition: all 0.2s; +} + @media (max-width: 768px) { + .navbar { - padding: 0 1rem; - height: 60px; - gap: 0.5rem; - - z-index: 1002; - background: rgba(9, 9, 11, 0.95); + height: 70px; + padding: 0 1.5rem; + background: rgba(9, 9, 11, 0.8); + backdrop-filter: blur(15px); + border-bottom: 1px solid rgba(255,255,255,0.05); } - .nav-brand { - min-width: auto; - font-size: 0; - } + .nav-brand span { display: none; } + .brand-icon { width: 40px; height: 40px; } - .brand-icon { - width: 32px; - height: 32px; - } - - .search-wrapper { - flex: 1; - width: auto; - } - - .search-input { - padding: 0.5rem 1rem 0.5rem 2.2rem; - font-size: 0.9rem; - } - - .search-icon { - left: 10px; - } - - #nav-avatar { - width: 32px; - height: 32px; + .mobile-menu-toggle { + display: flex; } + .mobile-menu-toggle:active { transform: scale(0.95); } .nav-center { - position: absolute; - top: 60px; - left: 0; - right: 0; - display: flex; - background: rgba(9, 9, 11, 0.98); - border-bottom: 1px solid rgba(255, 255, 255, 0.05); - padding: 0.5rem 1rem; - - overflow-x: auto; - white-space: nowrap; - justify-content: flex-start; - gap: 0.5rem; - - -ms-overflow-style: none; - scrollbar-width: none; - z-index: 1001; + position: fixed; + top: 0; + right: -100%; + width: 85%; + max-width: 320px; + height: 100vh; border-radius: 0; border: none; - border-bottom: 1px solid rgba(255, 255, 255, 0.05); + + background: linear-gradient(160deg, rgba(20, 20, 25, 0.98) 0%, rgba(10, 10, 12, 0.99) 100%); + box-shadow: -10px 0 40px rgba(0, 0, 0, 0.6); + + border-left: 1px solid rgba(255, 255, 255, 0.08); + + display: flex; + flex-direction: column; + justify-content: center; + padding: 2rem; + gap: 1rem; + z-index: 2000; + + transition: right 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); } - .nav-center::-webkit-scrollbar { - display: none; + .nav-center.open { + right: 0; } .nav-button { - flex-shrink: 0; - padding: 0.4rem 1rem; - font-size: 0.85rem; + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 1.2rem 1.5rem; + + font-size: 1.2rem; + font-weight: 700; + letter-spacing: 0.5px; + color: rgba(255, 255, 255, 0.6); + text-transform: uppercase; + + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.03); + border-radius: 16px; + transition: all 0.3s cubic-bezier(0.25, 0.8, 0.5, 1); + + opacity: 0; + transform: translateX(20px); + } + + .nav-button:hover { background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.05); + color: white; + padding-left: 2rem; } .nav-button.active { - background: var(--color-primary); - border-color: var(--color-primary); + background: linear-gradient(90deg, rgba(139, 92, 246, 0.2) 0%, transparent 100%); + border-color: rgba(139, 92, 246, 0.4); + color: white; + box-shadow: 0 4px 20px rgba(139, 92, 246, 0.15); + opacity: 1; + transform: translateX(0); } - .search-results { - position: fixed; - top: 110px; + .nav-center.open .nav-button { + opacity: 1; + transform: translateX(0); + } + + .nav-button.active::before { + content: ''; + position: absolute; left: 0; - right: 0; - width: 100vw; - border-radius: 0; - max-height: calc(100vh - 120px); + height: 50%; + width: 3px; + background: #8b5cf6; + border-radius: 0 4px 4px 0; + box-shadow: 0 0 10px #8b5cf6; } - .nav-dropdown { - position: fixed; - top: 70px; - right: 1rem; - left: 1rem; - width: auto; - min-width: auto; - z-index: 9999; + .search-wrapper { + margin-left: 10px; + margin-right: auto; + width: 40px; + height: 40px; + display: flex; + align-items: center; + position: relative; + cursor: pointer; + } + + .search-input { + opacity: 0; + width: 0; + padding: 0; + pointer-events: none; /* No clickable cuando está oculto */ + position: absolute; + left: 0; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 2005; + } + + /* Estado expandido al tocar */ + .search-wrapper:focus-within { + width: 220px; /* Ancho suficiente para escribir */ + } + + .search-wrapper:focus-within .search-input { + opacity: 1; + width: 220px; + padding: 0.6rem 1rem 0.6rem 2.5rem; + background: #18181b; + border: 1px solid var(--color-primary); + border-radius: 99px; + pointer-events: auto; /* Permitir escritura */ + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); + } + + .search-wrapper.active-mobile .search-input { + opacity: 1; + width: 220px; + padding: 0.6rem 1rem 0.6rem 2.5rem; + background: #18181b; + pointer-events: auto; + } + + /* Aseguramos que el icono siempre esté arriba del input expandido */ + .search-icon { + z-index: 2006; + } + + /* Evitar que el menú lateral tape el buscador si ambos intentan estar abiertos */ + .nav-center.open { + z-index: 1999; } } \ No newline at end of file diff --git a/docker/views/css/profile.css b/docker/views/css/profile.css index 9c05817..f95fb56 100644 --- a/docker/views/css/profile.css +++ b/docker/views/css/profile.css @@ -283,6 +283,12 @@ background-size: 1rem; } +.minimal-select option { + background-color: var(--color-bg-elevated, #18181b); + color: #e4e4e7; + padding: 10px; +} + .minimal-select:hover { background: rgba(255,255,255,0.1); color: white; } .minimal-select:focus { border-color: var(--color-primary, #8b5cf6); color: white; } diff --git a/docker/views/css/users.css b/docker/views/css/users.css index afdefdc..7a42a6d 100644 --- a/docker/views/css/users.css +++ b/docker/views/css/users.css @@ -861,23 +861,4 @@ input[type="file"] { .btn-secondary { padding: 1.2rem; } -} - -.anilist-status a.btn-secondary { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.5rem; - transition: all 0.2s; -} - -.anilist-status a.btn-secondary:hover { - border-color: var(--color-primary); - color: white; - background: rgba(139, 92, 246, 0.1); -} - -#manualAniListToken { - font-family: monospace; - font-size: 0.9rem; } \ No newline at end of file