Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 68 additions & 30 deletions assets/css/desktop-dock.css
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -75,20 +75,44 @@ body {
white-space: nowrap;
}

/* Janelas flutuantes (<dialog>) */
/* Janelas flutuantes (<dialog>) — 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 <dialog> 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 {
Expand All @@ -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;
}
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
53 changes: 42 additions & 11 deletions assets/js/desktop-dock.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -49,7 +75,7 @@
closeWindow(win);
btn.setAttribute("aria-pressed", "false");
} else {
openWindow(win);
openWindow(win, btn);
btn.setAttribute("aria-pressed", "true");
}
});
Expand All @@ -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 () {
Expand Down Expand Up @@ -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) {
Expand Down
6 changes: 5 additions & 1 deletion hugo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,18 @@ 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
displayLogo: false

footer:
displayCopyright: false
displayPoweredBy: true
displayPoweredBy: false

editURL:
enable: false
Loading