refactor: Remove SmoothScroll component from LayoutDefault #21
@ -1,116 +0,0 @@
|
|||||||
import type { JSX } from "solid-js";
|
|
||||||
import { createSignal, onCleanup } from "solid-js";
|
|
||||||
|
|
||||||
type SmoothScrollProps = JSX.IntrinsicElements["div"] & {
|
|
||||||
children: JSX.Element;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function SmoothScroll(props: SmoothScrollProps) {
|
|
||||||
const [isScrolling, setIsScrolling] = createSignal(false);
|
|
||||||
let animationFrameId: number | null = null;
|
|
||||||
|
|
||||||
const easeOutQuad = (t: number, b: number, c: number, d: number) => {
|
|
||||||
const time = t / d;
|
|
||||||
return -c * time * (time - 2) + b;
|
|
||||||
};
|
|
||||||
|
|
||||||
const smoothScroll = (deltaY: number) => {
|
|
||||||
const scrollSpeed = 3;
|
|
||||||
const currentScroll = window.scrollY;
|
|
||||||
const targetScroll = deltaY * scrollSpeed;
|
|
||||||
const duration = 300;
|
|
||||||
const startTime = performance.now();
|
|
||||||
|
|
||||||
const animateScroll = (currentTime: number) => {
|
|
||||||
const elapsedTime = currentTime - startTime;
|
|
||||||
const ease = easeOutQuad(
|
|
||||||
elapsedTime,
|
|
||||||
currentScroll,
|
|
||||||
targetScroll,
|
|
||||||
duration,
|
|
||||||
);
|
|
||||||
|
|
||||||
window.scrollTo(0, ease);
|
|
||||||
|
|
||||||
if (elapsedTime < duration) {
|
|
||||||
animationFrameId = requestAnimationFrame(animateScroll);
|
|
||||||
} else {
|
|
||||||
setIsScrolling(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
animationFrameId = requestAnimationFrame(animateScroll);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isMobile = () => {
|
|
||||||
const regex =
|
|
||||||
/Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
|
|
||||||
return regex.test(navigator.userAgent);
|
|
||||||
};
|
|
||||||
|
|
||||||
const isElementScrollable = (element: HTMLElement) => {
|
|
||||||
if (!element) return false;
|
|
||||||
|
|
||||||
return (
|
|
||||||
element.scrollHeight > element.clientHeight && element.tagName !== "HTML"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const findScrollableParent = (element: HTMLElement) => {
|
|
||||||
let currentElement: HTMLElement | null = element;
|
|
||||||
|
|
||||||
while (currentElement) {
|
|
||||||
if (isElementScrollable(currentElement)) {
|
|
||||||
return currentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentElement = currentElement.parentElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleWheel = (event: WheelEvent) => {
|
|
||||||
if (isMobile()) return;
|
|
||||||
if (event.ctrlKey) return;
|
|
||||||
if (event.metaKey) return;
|
|
||||||
|
|
||||||
const hoveredElement = document.elementFromPoint(
|
|
||||||
event.clientX,
|
|
||||||
event.clientY,
|
|
||||||
) as HTMLElement;
|
|
||||||
|
|
||||||
if (findScrollableParent(hoveredElement)) {
|
|
||||||
if (animationFrameId !== null) cancelAnimationFrame(animationFrameId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
if (isScrolling()) {
|
|
||||||
if (animationFrameId !== null) {
|
|
||||||
cancelAnimationFrame(animationFrameId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
smoothScroll(event.deltaY);
|
|
||||||
setIsScrolling(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
setIsScrolling(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
onCleanup(() => {
|
|
||||||
if (animationFrameId !== null) {
|
|
||||||
cancelAnimationFrame(animationFrameId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div {...props} onWheel={handleWheel} style={{ "touch-action": "auto" }}>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import type { JSXElement } from "solid-js";
|
import type { JSXElement } from "solid-js";
|
||||||
|
|
||||||
import { usePageContext } from "vike-solid/usePageContext";
|
import { usePageContext } from "vike-solid/usePageContext";
|
||||||
import { SmoothScroll } from "@/components/SmoothScroll";
|
|
||||||
import { HeroSection } from "@/partials/HeroSection";
|
import { HeroSection } from "@/partials/HeroSection";
|
||||||
import { clientOnly } from "vike-solid/clientOnly";
|
import { clientOnly } from "vike-solid/clientOnly";
|
||||||
import { Navigation } from "@/partials/Navigation";
|
import { Navigation } from "@/partials/Navigation";
|
||||||
@ -12,9 +11,7 @@ import { Toaster } from "solid-toast";
|
|||||||
|
|
||||||
import "./tailwind.css";
|
import "./tailwind.css";
|
||||||
|
|
||||||
const ReadProgressBar = clientOnly(
|
const ReadProgressBar = clientOnly(async () => (await import("@/partials/ReadProgressBar")).ReadProgressBar);
|
||||||
async () => (await import("@/partials/ReadProgressBar")).ReadProgressBar,
|
|
||||||
);
|
|
||||||
|
|
||||||
type DefaultLayoutProps = {
|
type DefaultLayoutProps = {
|
||||||
children: JSXElement;
|
children: JSXElement;
|
||||||
@ -25,7 +22,6 @@ export default function DefaultLayout(props: DefaultLayoutProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SmoothScroll class="flex w-full flex-col font-sans">
|
|
||||||
<Header />
|
<Header />
|
||||||
<ReadProgressBar />
|
<ReadProgressBar />
|
||||||
|
|
||||||
@ -47,8 +43,6 @@ export default function DefaultLayout(props: DefaultLayoutProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
</SmoothScroll>
|
|
||||||
|
|
||||||
<Toaster />
|
<Toaster />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,35 +25,20 @@ const __dirname = path.resolve();
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
prismjsVitePlugin({
|
prismjsVitePlugin({
|
||||||
languages: [
|
languages: ["javascript", "typescript", "tsx", "jsx", "css", "html", "bash", "nginx", "sql"],
|
||||||
"javascript",
|
|
||||||
"typescript",
|
|
||||||
"tsx",
|
|
||||||
"jsx",
|
|
||||||
"css",
|
|
||||||
"html",
|
|
||||||
"bash",
|
|
||||||
"nginx",
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
vike(),
|
vike(),
|
||||||
vikeSolid(),
|
vikeSolid(),
|
||||||
mdx({
|
mdx({
|
||||||
jsxImportSource: "solid-jsx",
|
jsxImportSource: "solid-jsx",
|
||||||
remarkPlugins: [
|
remarkPlugins: [remarkFrontmatter, remarkHeadingId, remarkExtractFrontmatter],
|
||||||
remarkFrontmatter,
|
|
||||||
remarkHeadingId,
|
|
||||||
remarkExtractFrontmatter,
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
telefunc(),
|
telefunc(),
|
||||||
],
|
],
|
||||||
css: {
|
css: {
|
||||||
postcss: {
|
postcss: {
|
||||||
plugins: [
|
plugins: [...(process.env.NODE_ENV === "production" ? [removeCommentRules] : [])],
|
||||||
...(process.env.NODE_ENV === "production" ? [removeCommentRules] : []),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user