feat(blog): add file-based blog with dynamic slugs, MDX content and layout shell
- Introduced blog routing using Next.js App Router - Implemented dynamic [slug] pages for blog posts - Added MDX-based content loading via lib/posts - Integrated shared TopBar layout with navigation - Established clear content, lib and component separation
This commit is contained in:
98
apps/public-web/node_modules/next/dist/esm/client/use-intersection.js
generated
vendored
Normal file
98
apps/public-web/node_modules/next/dist/esm/client/use-intersection.js
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { requestIdleCallback, cancelIdleCallback } from './request-idle-callback';
|
||||
const hasIntersectionObserver = typeof IntersectionObserver === 'function';
|
||||
const observers = new Map();
|
||||
const idList = [];
|
||||
function createObserver(options) {
|
||||
const id = {
|
||||
root: options.root || null,
|
||||
margin: options.rootMargin || ''
|
||||
};
|
||||
const existing = idList.find((obj)=>obj.root === id.root && obj.margin === id.margin);
|
||||
let instance;
|
||||
if (existing) {
|
||||
instance = observers.get(existing);
|
||||
if (instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
const elements = new Map();
|
||||
const observer = new IntersectionObserver((entries)=>{
|
||||
entries.forEach((entry)=>{
|
||||
const callback = elements.get(entry.target);
|
||||
const isVisible = entry.isIntersecting || entry.intersectionRatio > 0;
|
||||
if (callback && isVisible) {
|
||||
callback(isVisible);
|
||||
}
|
||||
});
|
||||
}, options);
|
||||
instance = {
|
||||
id,
|
||||
observer,
|
||||
elements
|
||||
};
|
||||
idList.push(id);
|
||||
observers.set(id, instance);
|
||||
return instance;
|
||||
}
|
||||
function observe(element, callback, options) {
|
||||
const { id, observer, elements } = createObserver(options);
|
||||
elements.set(element, callback);
|
||||
observer.observe(element);
|
||||
return function unobserve() {
|
||||
elements.delete(element);
|
||||
observer.unobserve(element);
|
||||
// Destroy observer when there's nothing left to watch:
|
||||
if (elements.size === 0) {
|
||||
observer.disconnect();
|
||||
observers.delete(id);
|
||||
const index = idList.findIndex((obj)=>obj.root === id.root && obj.margin === id.margin);
|
||||
if (index > -1) {
|
||||
idList.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
export function useIntersection({ rootRef, rootMargin, disabled }) {
|
||||
const isDisabled = disabled || !hasIntersectionObserver;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const elementRef = useRef(null);
|
||||
const setElement = useCallback((element)=>{
|
||||
elementRef.current = element;
|
||||
}, []);
|
||||
useEffect(()=>{
|
||||
if (hasIntersectionObserver) {
|
||||
if (isDisabled || visible) return;
|
||||
const element = elementRef.current;
|
||||
if (element && element.tagName) {
|
||||
const unobserve = observe(element, (isVisible)=>isVisible && setVisible(isVisible), {
|
||||
root: rootRef?.current,
|
||||
rootMargin
|
||||
});
|
||||
return unobserve;
|
||||
}
|
||||
} else {
|
||||
if (!visible) {
|
||||
const idleCallback = requestIdleCallback(()=>setVisible(true));
|
||||
return ()=>cancelIdleCallback(idleCallback);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
isDisabled,
|
||||
rootMargin,
|
||||
rootRef,
|
||||
visible,
|
||||
elementRef.current
|
||||
]);
|
||||
const resetVisible = useCallback(()=>{
|
||||
setVisible(false);
|
||||
}, []);
|
||||
return [
|
||||
setElement,
|
||||
visible,
|
||||
resetVisible
|
||||
];
|
||||
}
|
||||
|
||||
//# sourceMappingURL=use-intersection.js.map
|
||||
Reference in New Issue
Block a user