diff --git a/assets/css/desktop-dock.css b/assets/css/desktop-dock.css index 972d53a..c69e6d5 100644 --- a/assets/css/desktop-dock.css +++ b/assets/css/desktop-dock.css @@ -5,6 +5,8 @@ :root { --dock-height: 4rem; + --bevel-light: rgba(255, 255, 255, 0.75); + --bevel-dark: rgba(0, 0, 0, 0.35); } body { @@ -37,18 +39,17 @@ body { gap: 0.15rem; width: 4.25rem; padding: 0.35rem 0.25rem; - border: 1px solid var(--ld-border); - border-radius: 0.5rem; + border-width: 2px; + border-style: solid; + border-color: var(--bevel-light) var(--bevel-dark) var(--bevel-dark) var(--bevel-light); + border-radius: 0; background: var(--ld-bg); color: var(--ld-muted); cursor: pointer; - box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.6), - 0 1px 2px rgba(0, 0, 0, 0.06); + box-shadow: 2px 2px 0 rgba(0, 0, 0, 0.15); transition: transform 0.1s ease, - color 0.15s ease, - border-color 0.15s ease; + color 0.15s ease; } .dock__item svg { @@ -58,15 +59,14 @@ body { .dock__item:hover { color: var(--ld-accent); - border-color: var(--ld-accent); } .dock__item:active, .dock__item[aria-pressed="true"] { - transform: translateY(1px); + transform: translate(2px, 2px); color: var(--ld-accent); - border-color: var(--ld-accent); - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.15); + border-color: var(--bevel-dark) var(--bevel-light) var(--bevel-light) var(--bevel-dark); + box-shadow: none; } .dock__label { @@ -75,20 +75,44 @@ body { white-space: nowrap; } -/* Janelas flutuantes () */ +/* Janelas flutuantes () — visual "pixel art" (cantos retos, bevel + 3D, sombra dura sem blur) inspirado em UI de desktop do fim dos anos 2000 */ .dock-window { position: fixed; + z-index: 50; width: min(22rem, calc(100vw - 2rem)); max-height: min(28rem, calc(100vh - var(--dock-height) - 3rem)); margin: 0; padding: 0; display: flex; flex-direction: column; - border: 1px solid var(--ld-border); - border-radius: 0.5rem; + border-width: 2px; + border-style: solid; + border-color: var(--bevel-light) var(--bevel-dark) var(--bevel-dark) var(--bevel-light); + border-radius: 0; background: var(--ld-bg); color: var(--ld-fg); - box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18); + box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.25); + animation: dock-window-in 0.12s ease; +} + +/* Garante que a janela fechada some de vez (clique/hit-test incluídos). + Sem isso, a regra "display: flex" acima ganha do "display: none" nativo + do fechado e a janela "fechada" continua invisível-mas-clicável + por cima do que estiver atrás dela. */ +.dock-window:not([open]) { + display: none; +} + +@keyframes dock-window-in { + from { + transform: scale(0.94); + opacity: 0; + } + to { + transform: scale(1); + opacity: 1; + } } .dock-window::backdrop { @@ -101,12 +125,15 @@ body { align-items: center; justify-content: space-between; gap: 0.5rem; - padding: 0.5rem 0.75rem; - background: var(--ld-bg-soft); - border-bottom: 1px solid var(--ld-border); - border-radius: 0.5rem 0.5rem 0 0; - font-size: 0.8rem; + padding: 0.4rem 0.5rem; + background: var(--ld-accent); + color: var(--ld-bg); + border-bottom: 2px solid var(--bevel-dark); + font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; + font-size: 0.75rem; font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; cursor: grab; user-select: none; } @@ -117,23 +144,29 @@ body { .dock-window__close { flex: 0 0 auto; - width: 1.5rem; - height: 1.5rem; + width: 1.25rem; + height: 1.25rem; display: inline-flex; align-items: center; justify-content: center; - border: 1px solid var(--ld-border); - border-radius: 0.25rem; - background: var(--ld-bg); - color: var(--ld-muted); - font-size: 0.9rem; + border-width: 2px; + border-style: solid; + border-color: var(--bevel-light) var(--bevel-dark) var(--bevel-dark) var(--bevel-light); + border-radius: 0; + background: var(--ld-bg-soft); + color: var(--ld-fg); + font-size: 0.8rem; line-height: 1; cursor: pointer; } .dock-window__close:hover { color: var(--ld-accent); - border-color: var(--ld-accent); +} + +.dock-window__close:active { + border-color: var(--bevel-dark) var(--bevel-light) var(--bevel-light) var(--bevel-dark); + transform: translate(1px, 1px); } .dock-window__body { @@ -151,12 +184,17 @@ body { font-size: 0.875rem; } -/* Player Spotify (carregado sob demanda) */ +/* Player Spotify (carregado sob demanda). min-height no wrapper garante que + a altura da janela já nasça correta, mesmo antes do iframe existir — + evita a janela "crescer" (e cobrir a doca) depois de posicionada. */ +.dock-window__embed [data-embed-src] { + min-height: 152px; +} + .dock-window__embed iframe { width: 100%; height: 152px; border: 0; - border-radius: 0.5rem; } .dock-window__spotify-link { diff --git a/assets/js/desktop-dock.js b/assets/js/desktop-dock.js index c84ea94..8c11271 100644 --- a/assets/js/desktop-dock.js +++ b/assets/js/desktop-dock.js @@ -3,18 +3,43 @@ if (!dock) return; var openOffset = 0; + var topZ = 50; - function placeWindow(win) { + function navbarHeight() { + var nav = document.querySelector(".hextra-nav-container"); + return nav ? nav.offsetHeight : 0; + } + + function raiseWindow(win) { + topZ += 1; + win.style.zIndex = topZ; + } + + function placeWindow(win, anchorBtn) { var margin = 16; + var gapAboveDock = 12; + var dockHeight = dock.offsetHeight; var width = win.offsetWidth || 352; var height = win.offsetHeight || 280; + + // Ancora perto do ícone clicado, horizontalmente; verticalmente sempre + // colada acima da doca (nunca perto do cabeçalho). + var left = margin + openOffset; + if (anchorBtn) { + var rect = anchorBtn.getBoundingClientRect(); + left = rect.left + rect.width / 2 - width / 2 + openOffset; + } + var top = window.innerHeight - dockHeight - gapAboveDock - height - openOffset; + var maxLeft = window.innerWidth - width - margin; - var maxTop = window.innerHeight - height - margin; - var left = Math.min(maxLeft, margin + openOffset); - var top = Math.min(maxTop, margin + openOffset); - win.style.left = Math.max(margin, left) + "px"; - win.style.top = Math.max(margin, top) + "px"; - openOffset = (openOffset + 24) % 96; + var maxTop = window.innerHeight - dockHeight - gapAboveDock - height; + var minTop = navbarHeight() + margin; + left = Math.min(maxLeft, Math.max(margin, left)); + top = Math.min(maxTop, Math.max(minTop, top)); + + win.style.left = left + "px"; + win.style.top = top + "px"; + openOffset = (openOffset + 40) % 120; } function loadEmbed(win) { @@ -28,11 +53,12 @@ body.dataset.loaded = "true"; } - function openWindow(win) { + function openWindow(win, anchorBtn) { if (win.open) return; win.show(); - placeWindow(win); loadEmbed(win); + placeWindow(win, anchorBtn); + raiseWindow(win); } function closeWindow(win) { @@ -49,7 +75,7 @@ closeWindow(win); btn.setAttribute("aria-pressed", "false"); } else { - openWindow(win); + openWindow(win, btn); btn.setAttribute("aria-pressed", "true"); } }); @@ -63,6 +89,10 @@ if (btn) btn.setAttribute("aria-pressed", "false"); }); + win.addEventListener("pointerdown", function () { + raiseWindow(win); + }); + var closeBtn = win.querySelector("[data-dock-close]"); if (closeBtn) { closeBtn.addEventListener("click", function () { @@ -92,10 +122,11 @@ bar.addEventListener("pointermove", function (event) { if (!dragging) return; + var minTop = navbarHeight(); var left = startLeft + (event.clientX - startX); var top = startTop + (event.clientY - startY); win.style.left = Math.max(0, left) + "px"; - win.style.top = Math.max(0, top) + "px"; + win.style.top = Math.max(minTop, top) + "px"; }); function stopDrag(event) { diff --git a/hugo.yaml b/hugo.yaml index 901c209..160b766 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -54,6 +54,10 @@ params: theme: default: light + # O toggle de tema já vive no menu (item "Tema", type: theme-toggle). + # Isso desliga só as instâncias extras que o Hextra mostra sozinho + # (rodapé / fundo da sidebar) quando a sidebar esquerda está oculta. + displayToggle: false navbar: displayTitle: true @@ -61,7 +65,7 @@ params: footer: displayCopyright: false - displayPoweredBy: true + displayPoweredBy: false editURL: enable: false