refactor: Remove SmoothScroll component from LayoutDefault (#21)
All checks were successful
Update Memento Dev on VPS / deploy (push) Successful in 38s

Reviewed-on: #21
Co-authored-by: GauthierWebDev <gauthier@gauthierdaniels.fr>
Co-committed-by: GauthierWebDev <gauthier@gauthierdaniels.fr>
This commit is contained in:
Gauthier Daniels 2025-04-23 11:11:34 +00:00 committed by Gauthier Daniels
parent e31401b403
commit 9eab26ba47
3 changed files with 54 additions and 191 deletions

View File

@ -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>
);
}

View File

@ -1,7 +1,6 @@
import type { JSXElement } from "solid-js";
import { usePageContext } from "vike-solid/usePageContext";
import { SmoothScroll } from "@/components/SmoothScroll";
import { HeroSection } from "@/partials/HeroSection";
import { clientOnly } from "vike-solid/clientOnly";
import { Navigation } from "@/partials/Navigation";
@ -12,44 +11,39 @@ import { Toaster } from "solid-toast";
import "./tailwind.css";
const ReadProgressBar = clientOnly(
async () => (await import("@/partials/ReadProgressBar")).ReadProgressBar,
);
const ReadProgressBar = clientOnly(async () => (await import("@/partials/ReadProgressBar")).ReadProgressBar);
type DefaultLayoutProps = {
children: JSXElement;
children: JSXElement;
};
export default function DefaultLayout(props: DefaultLayoutProps) {
const pageContext = usePageContext();
const pageContext = usePageContext();
return (
<>
<SmoothScroll class="flex w-full flex-col font-sans">
<Header />
<ReadProgressBar />
return (
<>
<Header />
<ReadProgressBar />
{pageContext.urlPathname === "/" && <HeroSection />}
{pageContext.urlPathname === "/" && <HeroSection />}
<div class="relative mx-auto w-full flex max-w-8xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12">
<div class="hidden lg:relative lg:block lg:flex-none">
<div class="absolute inset-y-0 right-0 w-[50vw] bg-slate-50" />
<div class="absolute top-16 right-0 bottom-0 hidden h-12 w-px bg-linear-to-t from-slate-800" />
<div class="absolute top-28 right-0 bottom-0 hidden w-px bg-slate-800" />
<div class="sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64 overflow-x-hidden overflow-y-auto py-16 pr-8 pl-0.5 xl:w-72 xl:pr-16">
<Navigation />
</div>
</div>
<div class="relative mx-auto w-full flex max-w-8xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12">
<div class="hidden lg:relative lg:block lg:flex-none">
<div class="absolute inset-y-0 right-0 w-[50vw] bg-slate-50" />
<div class="absolute top-16 right-0 bottom-0 hidden h-12 w-px bg-linear-to-t from-slate-800" />
<div class="absolute top-28 right-0 bottom-0 hidden w-px bg-slate-800" />
<div class="sticky top-[4.75rem] -ml-0.5 h-[calc(100vh-4.75rem)] w-64 overflow-x-hidden overflow-y-auto py-16 pr-8 pl-0.5 xl:w-72 xl:pr-16">
<Navigation />
</div>
</div>
<div class="flex flex-col">
<DocsLayout>{props.children}</DocsLayout>
</div>
</div>
<div class="flex flex-col">
<DocsLayout>{props.children}</DocsLayout>
</div>
</div>
<Footer />
</SmoothScroll>
<Toaster />
</>
);
<Footer />
<Toaster />
</>
);
}

View File

@ -15,53 +15,38 @@ import path from "node:path";
type RemoveCommentRules = (root: Root) => void;
const removeCommentRules: RemoveCommentRules = (root) => {
root.walkComments((comment) => {
comment.remove();
});
root.walkComments((comment) => {
comment.remove();
});
};
const __dirname = path.resolve();
export default defineConfig({
plugins: [
prismjsVitePlugin({
languages: [
"javascript",
"typescript",
"tsx",
"jsx",
"css",
"html",
"bash",
"nginx",
],
}),
vike(),
vikeSolid(),
mdx({
jsxImportSource: "solid-jsx",
remarkPlugins: [
remarkFrontmatter,
remarkHeadingId,
remarkExtractFrontmatter,
],
}),
tailwindcss(),
telefunc(),
],
css: {
postcss: {
plugins: [
...(process.env.NODE_ENV === "production" ? [removeCommentRules] : []),
],
},
},
build: {
target: "es2022",
},
resolve: {
alias: {
"@": __dirname,
},
},
plugins: [
prismjsVitePlugin({
languages: ["javascript", "typescript", "tsx", "jsx", "css", "html", "bash", "nginx", "sql"],
}),
vike(),
vikeSolid(),
mdx({
jsxImportSource: "solid-jsx",
remarkPlugins: [remarkFrontmatter, remarkHeadingId, remarkExtractFrontmatter],
}),
tailwindcss(),
telefunc(),
],
css: {
postcss: {
plugins: [...(process.env.NODE_ENV === "production" ? [removeCommentRules] : [])],
},
},
build: {
target: "es2022",
},
resolve: {
alias: {
"@": __dirname,
},
},
});