mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-12 22:53:27 +00:00
Add dynamic mouse-tracking liquid glass effect (JS + CSS)
Co-authored-by: orange-cpp <59374393+orange-cpp@users.noreply.github.com>
This commit is contained in:
76
docs/javascripts/liquid-glass.js
Normal file
76
docs/javascripts/liquid-glass.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Dynamic Liquid Glass — mouse-tracking specular highlight
|
||||
*
|
||||
* Creates a radial-gradient light spot that follows the cursor across
|
||||
* glass-styled elements, giving them an interactive "liquid glass"
|
||||
* refraction/reflection feel inspired by Apple's Liquid Glass design.
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var SELECTORS = [
|
||||
".md-header",
|
||||
".md-content",
|
||||
".md-sidebar__scrollwrap",
|
||||
".highlight",
|
||||
".md-search__form",
|
||||
".md-footer"
|
||||
];
|
||||
|
||||
/** Apply the radial highlight via CSS custom properties. */
|
||||
function applyHighlight(el, x, y) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
var px = x - rect.left;
|
||||
var py = y - rect.top;
|
||||
el.style.setProperty("--glass-x", px + "px");
|
||||
el.style.setProperty("--glass-y", py + "px");
|
||||
el.classList.add("glass-active");
|
||||
}
|
||||
|
||||
function clearHighlight(el) {
|
||||
el.classList.remove("glass-active");
|
||||
}
|
||||
|
||||
/** Bind events once the DOM is ready. */
|
||||
function init() {
|
||||
var elements = [];
|
||||
SELECTORS.forEach(function (sel) {
|
||||
var nodes = document.querySelectorAll(sel);
|
||||
for (var i = 0; i < nodes.length; i++) {
|
||||
elements.push(nodes[i]);
|
||||
}
|
||||
});
|
||||
|
||||
var ticking = false;
|
||||
document.addEventListener("mousemove", function (e) {
|
||||
if (ticking) return;
|
||||
ticking = true;
|
||||
requestAnimationFrame(function () {
|
||||
elements.forEach(function (el) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
if (
|
||||
e.clientX >= rect.left &&
|
||||
e.clientX <= rect.right &&
|
||||
e.clientY >= rect.top &&
|
||||
e.clientY <= rect.bottom
|
||||
) {
|
||||
applyHighlight(el, e.clientX, e.clientY);
|
||||
} else {
|
||||
clearHighlight(el);
|
||||
}
|
||||
});
|
||||
ticking = false;
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("mouseleave", function () {
|
||||
elements.forEach(clearHighlight);
|
||||
});
|
||||
}
|
||||
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
@@ -177,3 +177,70 @@
|
||||
.md-typeset img {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Dynamic Liquid Glass — mouse-tracking specular highlight
|
||||
============================================================ */
|
||||
|
||||
/* Shared: every glass surface gets a hidden radial-light overlay
|
||||
that becomes visible when JS adds the .glass-active class and
|
||||
sets --glass-x / --glass-y custom properties. */
|
||||
.md-header,
|
||||
.md-content,
|
||||
.md-sidebar__scrollwrap,
|
||||
.highlight,
|
||||
.md-search__form,
|
||||
.md-footer {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.md-header::after,
|
||||
.md-content::after,
|
||||
.md-sidebar__scrollwrap::after,
|
||||
.highlight::after,
|
||||
.md-search__form::after,
|
||||
.md-footer::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
background: radial-gradient(
|
||||
circle 220px at var(--glass-x, 50%) var(--glass-y, 50%),
|
||||
rgba(255, 200, 120, 0.10) 0%,
|
||||
rgba(255, 152, 0, 0.04) 40%,
|
||||
transparent 70%
|
||||
);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.md-header.glass-active::after,
|
||||
.md-content.glass-active::after,
|
||||
.md-sidebar__scrollwrap.glass-active::after,
|
||||
.highlight.glass-active::after,
|
||||
.md-search__form.glass-active::after,
|
||||
.md-footer.glass-active::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Keep header text / nav icons above the overlay */
|
||||
.md-header > *,
|
||||
.md-content > *,
|
||||
.md-sidebar__scrollwrap > *,
|
||||
.md-search__form > *,
|
||||
.md-footer > * {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* Highlight code blocks get a slightly brighter spot */
|
||||
.highlight.glass-active::after {
|
||||
background: radial-gradient(
|
||||
circle 180px at var(--glass-x, 50%) var(--glass-y, 50%),
|
||||
rgba(255, 200, 120, 0.12) 0%,
|
||||
rgba(255, 152, 0, 0.05) 35%,
|
||||
transparent 65%
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,4 +14,6 @@ markdown_extensions:
|
||||
extra_css:
|
||||
- styles/fonts.css
|
||||
- styles/center.css
|
||||
- styles/liquid-glass.css
|
||||
- styles/liquid-glass.css
|
||||
extra_javascript:
|
||||
- javascripts/liquid-glass.js
|
||||
Reference in New Issue
Block a user