🚧 add modal

This commit is contained in:
yanyongyu
2021-12-31 02:06:20 +08:00
parent 21a958ffd9
commit ab2c73856d
8 changed files with 286 additions and 5 deletions

View File

@ -0,0 +1,67 @@
import { useLayoutEffect, useRef } from "react";
import ResizeObserver from "resize-observer-polyfill";
export function useResizeNotifier(
element: HTMLElement | undefined,
callback: () => void
) {
const callBackRef = useRef(callback);
useLayoutEffect(() => {
callBackRef.current = callback;
}, [callback]);
useLayoutEffect(() => {
if (!element) return;
const resizeObserver = new ResizeObserver(
withResizeLoopDetection(() => {
callBackRef.current!();
})
);
resizeObserver.observe(element);
return () => {
resizeObserver.disconnect();
};
}, [element]);
}
function withResizeLoopDetection(callback: () => void) {
return (entries: ResizeObserverEntry[], resizeObserver: ResizeObserver) => {
const elements = entries.map((entry) => entry.target);
const rectsBefore = elements.map((element) =>
element.getBoundingClientRect()
);
callback();
const rectsAfter = elements.map((element) =>
element.getBoundingClientRect()
);
const changedElements = elements.filter(
(_, i) => !areRectSizesEqual(rectsBefore[i], rectsAfter[i])
);
changedElements.forEach((element) =>
unobserveUntilNextFrame(element, resizeObserver)
);
};
}
function unobserveUntilNextFrame(
element: Element,
resizeObserver: ResizeObserver
) {
resizeObserver.unobserve(element);
requestAnimationFrame(() => {
resizeObserver.observe(element);
});
}
function areRectSizesEqual(rect1: DOMRect, rect2: DOMRect) {
return rect1.width === rect2.width && rect1.height === rect2.height;
}

View File

@ -23,7 +23,8 @@ export function filterObjs(filter: string, objs: Obj[]): Obj[] {
o.project_link?.indexOf(filter) != -1 ||
o.name.indexOf(filter) != -1 ||
o.desc.indexOf(filter) != -1 ||
o.author.indexOf(filter) != -1
o.author.indexOf(filter) != -1 ||
o.tags.filter((t) => t.label.indexOf(filter) != -1).length > 0
);
});
}

64
website/src/libs/width.ts Normal file
View File

@ -0,0 +1,64 @@
import { useLayoutEffect, useState } from "react";
import { useResizeNotifier } from "./resize";
export function getElementWidth(element: HTMLElement) {
const style = getComputedStyle(element);
return (
styleMetricToInt(style.marginLeft) +
getWidth(element) +
styleMetricToInt(style.marginRight)
);
}
export function getContentWidth(element: HTMLElement) {
const style = getComputedStyle(element);
return (
element.getBoundingClientRect().width -
styleMetricToInt(style.borderLeftWidth) -
styleMetricToInt(style.paddingLeft) -
styleMetricToInt(style.paddingRight) -
styleMetricToInt(style.borderRightWidth)
);
}
export function getNonContentWidth(element: HTMLElement) {
const style = getComputedStyle(element);
return (
styleMetricToInt(style.marginLeft) +
styleMetricToInt(style.borderLeftWidth) +
styleMetricToInt(style.paddingLeft) +
styleMetricToInt(style.paddingRight) +
styleMetricToInt(style.borderRightWidth) +
styleMetricToInt(style.marginRight)
);
}
export function getWidth(element: HTMLElement) {
return element.getBoundingClientRect().width;
}
function styleMetricToInt(styleAttribute: string | null) {
return styleAttribute ? parseInt(styleAttribute) : 0;
}
export function useContentWidth(element: HTMLElement | undefined) {
const [width, setWidth] = useState<number>();
function syncWidth() {
const newWidth = element ? getContentWidth(element) : undefined;
if (width !== newWidth) {
setWidth(newWidth);
}
}
useResizeNotifier(element, syncWidth);
useLayoutEffect(syncWidth);
return width;
}