mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 07:03:25 +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 {
|
.md-typeset img {
|
||||||
border-radius: 10px;
|
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%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,3 +15,5 @@ extra_css:
|
|||||||
- styles/fonts.css
|
- styles/fonts.css
|
||||||
- styles/center.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