Mission Control Dashboard - Initial implementation
This commit is contained in:
84
node_modules/framer-motion/dist/es/components/Reorder/Group.mjs
generated
vendored
Normal file
84
node_modules/framer-motion/dist/es/components/Reorder/Group.mjs
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
"use client";
|
||||
import { jsx } from 'react/jsx-runtime';
|
||||
import { invariant } from 'motion-utils';
|
||||
import { forwardRef, useRef, useEffect } from 'react';
|
||||
import { ReorderContext } from '../../context/ReorderContext.mjs';
|
||||
import { motion } from '../../render/components/motion/proxy.mjs';
|
||||
import { useConstant } from '../../utils/use-constant.mjs';
|
||||
import { checkReorder } from './utils/check-reorder.mjs';
|
||||
|
||||
function ReorderGroupComponent({ children, as = "ul", axis = "y", onReorder, values, ...props }, externalRef) {
|
||||
const Component = useConstant(() => motion[as]);
|
||||
const order = [];
|
||||
const isReordering = useRef(false);
|
||||
const groupRef = useRef(null);
|
||||
invariant(Boolean(values), "Reorder.Group must be provided a values prop", "reorder-values");
|
||||
const context = {
|
||||
axis,
|
||||
groupRef,
|
||||
registerItem: (value, layout) => {
|
||||
// If the entry was already added, update it rather than adding it again
|
||||
const idx = order.findIndex((entry) => value === entry.value);
|
||||
if (idx !== -1) {
|
||||
order[idx].layout = layout[axis];
|
||||
}
|
||||
else {
|
||||
order.push({ value: value, layout: layout[axis] });
|
||||
}
|
||||
order.sort(compareMin);
|
||||
},
|
||||
updateOrder: (item, offset, velocity) => {
|
||||
if (isReordering.current)
|
||||
return;
|
||||
const newOrder = checkReorder(order, item, offset, velocity);
|
||||
if (order !== newOrder) {
|
||||
isReordering.current = true;
|
||||
// Find which two values swapped and apply that swap
|
||||
// to the full values array. This preserves unmeasured
|
||||
// items (e.g. in virtualized lists).
|
||||
const newValues = [...values];
|
||||
for (let i = 0; i < newOrder.length; i++) {
|
||||
if (order[i].value !== newOrder[i].value) {
|
||||
const a = values.indexOf(order[i].value);
|
||||
const b = values.indexOf(newOrder[i].value);
|
||||
if (a !== -1 && b !== -1) {
|
||||
[newValues[a], newValues[b]] = [newValues[b], newValues[a]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
onReorder(newValues);
|
||||
}
|
||||
},
|
||||
};
|
||||
useEffect(() => {
|
||||
isReordering.current = false;
|
||||
});
|
||||
// Combine refs if external ref is provided
|
||||
const setRef = (element) => {
|
||||
groupRef.current = element;
|
||||
if (typeof externalRef === "function") {
|
||||
externalRef(element);
|
||||
}
|
||||
else if (externalRef) {
|
||||
externalRef.current = element;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Disable browser scroll anchoring on the group container.
|
||||
* When items reorder, scroll anchoring can cause the browser to adjust
|
||||
* the scroll position, which interferes with drag position calculations.
|
||||
*/
|
||||
const groupStyle = {
|
||||
overflowAnchor: "none",
|
||||
...props.style,
|
||||
};
|
||||
return (jsx(Component, { ...props, style: groupStyle, ref: setRef, ignoreStrict: true, children: jsx(ReorderContext.Provider, { value: context, children: children }) }));
|
||||
}
|
||||
const ReorderGroup = /*@__PURE__*/ forwardRef(ReorderGroupComponent);
|
||||
function compareMin(a, b) {
|
||||
return a.layout.min - b.layout.min;
|
||||
}
|
||||
|
||||
export { ReorderGroup, ReorderGroupComponent };
|
||||
//# sourceMappingURL=Group.mjs.map
|
||||
1
node_modules/framer-motion/dist/es/components/Reorder/Group.mjs.map
generated
vendored
Normal file
1
node_modules/framer-motion/dist/es/components/Reorder/Group.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
43
node_modules/framer-motion/dist/es/components/Reorder/Item.mjs
generated
vendored
Normal file
43
node_modules/framer-motion/dist/es/components/Reorder/Item.mjs
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
"use client";
|
||||
import { jsx } from 'react/jsx-runtime';
|
||||
import { isMotionValue } from 'motion-dom';
|
||||
import { invariant } from 'motion-utils';
|
||||
import { forwardRef, useContext } from 'react';
|
||||
import { ReorderContext } from '../../context/ReorderContext.mjs';
|
||||
import { motion } from '../../render/components/motion/proxy.mjs';
|
||||
import { useConstant } from '../../utils/use-constant.mjs';
|
||||
import { useMotionValue } from '../../value/use-motion-value.mjs';
|
||||
import { useTransform } from '../../value/use-transform.mjs';
|
||||
import { autoScrollIfNeeded, resetAutoScrollState } from './utils/auto-scroll.mjs';
|
||||
|
||||
function useDefaultMotionValue(value, defaultValue = 0) {
|
||||
return isMotionValue(value) ? value : useMotionValue(defaultValue);
|
||||
}
|
||||
function ReorderItemComponent({ children, style = {}, value, as = "li", onDrag, onDragEnd, layout = true, ...props }, externalRef) {
|
||||
const Component = useConstant(() => motion[as]);
|
||||
const context = useContext(ReorderContext);
|
||||
const point = {
|
||||
x: useDefaultMotionValue(style.x),
|
||||
y: useDefaultMotionValue(style.y),
|
||||
};
|
||||
const zIndex = useTransform([point.x, point.y], ([latestX, latestY]) => latestX || latestY ? 1 : "unset");
|
||||
invariant(Boolean(context), "Reorder.Item must be a child of Reorder.Group", "reorder-item-child");
|
||||
const { axis, registerItem, updateOrder, groupRef } = context;
|
||||
return (jsx(Component, { drag: axis, ...props, dragSnapToOrigin: true, style: { ...style, x: point.x, y: point.y, zIndex }, layout: layout, onDrag: (event, gesturePoint) => {
|
||||
const { velocity, point: pointerPoint } = gesturePoint;
|
||||
const offset = point[axis].get();
|
||||
// Always attempt to update order - checkReorder handles the logic
|
||||
updateOrder(value, offset, velocity[axis]);
|
||||
autoScrollIfNeeded(groupRef.current, pointerPoint[axis], axis, velocity[axis]);
|
||||
onDrag && onDrag(event, gesturePoint);
|
||||
}, onDragEnd: (event, gesturePoint) => {
|
||||
resetAutoScrollState();
|
||||
onDragEnd && onDragEnd(event, gesturePoint);
|
||||
}, onLayoutMeasure: (measured) => {
|
||||
registerItem(value, measured);
|
||||
}, ref: externalRef, ignoreStrict: true, children: children }));
|
||||
}
|
||||
const ReorderItem = /*@__PURE__*/ forwardRef(ReorderItemComponent);
|
||||
|
||||
export { ReorderItem, ReorderItemComponent };
|
||||
//# sourceMappingURL=Item.mjs.map
|
||||
1
node_modules/framer-motion/dist/es/components/Reorder/Item.mjs.map
generated
vendored
Normal file
1
node_modules/framer-motion/dist/es/components/Reorder/Item.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"Item.mjs","sources":["../../../../src/components/Reorder/Item.tsx"],"sourcesContent":["\"use client\"\n\nimport { isMotionValue } from \"motion-dom\"\nimport { invariant } from \"motion-utils\"\nimport * as React from \"react\"\nimport { forwardRef, FunctionComponent, useContext } from \"react\"\nimport { ReorderContext } from \"../../context/ReorderContext\"\nimport { motion } from \"../../render/components/motion/proxy\"\nimport { HTMLMotionProps } from \"../../render/html/types\"\nimport { useConstant } from \"../../utils/use-constant\"\nimport { useMotionValue } from \"../../value/use-motion-value\"\nimport { useTransform } from \"../../value/use-transform\"\n\nimport { DefaultItemElement, ReorderElementTag } from \"./types\"\nimport {\n autoScrollIfNeeded,\n resetAutoScrollState,\n} from \"./utils/auto-scroll\"\n\nexport interface Props<\n V,\n TagName extends ReorderElementTag = DefaultItemElement\n> {\n /**\n * A HTML element to render this component as. Defaults to `\"li\"`.\n *\n * @public\n */\n as?: TagName\n\n /**\n * The value in the list that this component represents.\n *\n * @public\n */\n value: V\n\n /**\n * A subset of layout options primarily used to disable layout=\"size\"\n *\n * @public\n * @default true\n */\n layout?: true | \"position\"\n}\n\nfunction useDefaultMotionValue(value: any, defaultValue: number = 0) {\n return isMotionValue(value) ? value : useMotionValue(defaultValue)\n}\n\ntype ReorderItemProps<\n V,\n TagName extends ReorderElementTag = DefaultItemElement\n> = Props<V, TagName> &\n Omit<HTMLMotionProps<TagName>, \"value\" | \"layout\"> &\n React.PropsWithChildren<{}>\n\nexport function ReorderItemComponent<\n V,\n TagName extends ReorderElementTag = DefaultItemElement\n>(\n {\n children,\n style = {},\n value,\n as = \"li\" as TagName,\n onDrag,\n onDragEnd,\n layout = true,\n ...props\n }: ReorderItemProps<V, TagName>,\n externalRef?: React.ForwardedRef<any>\n): React.JSX.Element {\n const Component = useConstant(\n () => motion[as as keyof typeof motion]\n ) as FunctionComponent<\n React.PropsWithChildren<HTMLMotionProps<any> & { ref?: React.Ref<any> }>\n >\n\n const context = useContext(ReorderContext)\n const point = {\n x: useDefaultMotionValue(style.x),\n y: useDefaultMotionValue(style.y),\n }\n\n const zIndex = useTransform([point.x, point.y], ([latestX, latestY]) =>\n latestX || latestY ? 1 : \"unset\"\n )\n\n invariant(\n Boolean(context),\n \"Reorder.Item must be a child of Reorder.Group\",\n \"reorder-item-child\"\n )\n\n const { axis, registerItem, updateOrder, groupRef } = context!\n\n return (\n <Component\n drag={axis}\n {...props}\n dragSnapToOrigin\n style={{ ...style, x: point.x, y: point.y, zIndex }}\n layout={layout}\n onDrag={(event, gesturePoint) => {\n const { velocity, point: pointerPoint } = gesturePoint\n const offset = point[axis].get()\n\n // Always attempt to update order - checkReorder handles the logic\n updateOrder(value, offset, velocity[axis])\n\n autoScrollIfNeeded(\n groupRef.current,\n pointerPoint[axis],\n axis,\n velocity[axis]\n )\n\n onDrag && onDrag(event, gesturePoint)\n }}\n onDragEnd={(event, gesturePoint) => {\n resetAutoScrollState()\n onDragEnd && onDragEnd(event, gesturePoint)\n }}\n onLayoutMeasure={(measured) => {\n registerItem(value, measured)\n }}\n ref={externalRef}\n ignoreStrict\n >\n {children}\n </Component>\n )\n}\n\nexport const ReorderItem = /*@__PURE__*/ forwardRef(ReorderItemComponent) as <\n V,\n TagName extends ReorderElementTag = DefaultItemElement\n>(\n props: ReorderItemProps<V, TagName> & { ref?: React.ForwardedRef<any> }\n) => ReturnType<typeof ReorderItemComponent>\n"],"names":[],"mappings":";;;;;;;;;;;;AA8CA;AACI;AACJ;AASM;AAgBF;AAMA;AACA;AACI;AACA;;AAGJ;;;;;;;;AA0BY;AAOA;;AAGA;AACA;AACJ;AAEI;;AAQhB;AAEO;;"}
|
||||
3
node_modules/framer-motion/dist/es/components/Reorder/namespace.mjs
generated
vendored
Normal file
3
node_modules/framer-motion/dist/es/components/Reorder/namespace.mjs
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export { ReorderGroup as Group } from './Group.mjs';
|
||||
export { ReorderItem as Item } from './Item.mjs';
|
||||
//# sourceMappingURL=namespace.mjs.map
|
||||
1
node_modules/framer-motion/dist/es/components/Reorder/namespace.mjs.map
generated
vendored
Normal file
1
node_modules/framer-motion/dist/es/components/Reorder/namespace.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"namespace.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
||||
124
node_modules/framer-motion/dist/es/components/Reorder/utils/auto-scroll.mjs
generated
vendored
Normal file
124
node_modules/framer-motion/dist/es/components/Reorder/utils/auto-scroll.mjs
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
const threshold = 50;
|
||||
const maxSpeed = 25;
|
||||
const overflowStyles = new Set(["auto", "scroll"]);
|
||||
// Track initial scroll limits per scrollable element (Bug 1 fix)
|
||||
const initialScrollLimits = new WeakMap();
|
||||
const activeScrollEdge = new WeakMap();
|
||||
// Track which group element is currently dragging to clear state on end
|
||||
let currentGroupElement = null;
|
||||
function resetAutoScrollState() {
|
||||
if (currentGroupElement) {
|
||||
const scrollableAncestor = findScrollableAncestor(currentGroupElement, "y");
|
||||
if (scrollableAncestor) {
|
||||
activeScrollEdge.delete(scrollableAncestor);
|
||||
initialScrollLimits.delete(scrollableAncestor);
|
||||
}
|
||||
// Also try x axis
|
||||
const scrollableAncestorX = findScrollableAncestor(currentGroupElement, "x");
|
||||
if (scrollableAncestorX && scrollableAncestorX !== scrollableAncestor) {
|
||||
activeScrollEdge.delete(scrollableAncestorX);
|
||||
initialScrollLimits.delete(scrollableAncestorX);
|
||||
}
|
||||
currentGroupElement = null;
|
||||
}
|
||||
}
|
||||
function isScrollableElement(element, axis) {
|
||||
const style = getComputedStyle(element);
|
||||
const overflow = axis === "x" ? style.overflowX : style.overflowY;
|
||||
const isDocumentScroll = element === document.body ||
|
||||
element === document.documentElement;
|
||||
return overflowStyles.has(overflow) || isDocumentScroll;
|
||||
}
|
||||
function findScrollableAncestor(element, axis) {
|
||||
let current = element?.parentElement;
|
||||
while (current) {
|
||||
if (isScrollableElement(current, axis)) {
|
||||
return current;
|
||||
}
|
||||
current = current.parentElement;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function getScrollAmount(pointerPosition, scrollElement, axis) {
|
||||
const rect = scrollElement.getBoundingClientRect();
|
||||
const start = axis === "x" ? Math.max(0, rect.left) : Math.max(0, rect.top);
|
||||
const end = axis === "x" ? Math.min(window.innerWidth, rect.right) : Math.min(window.innerHeight, rect.bottom);
|
||||
const distanceFromStart = pointerPosition - start;
|
||||
const distanceFromEnd = end - pointerPosition;
|
||||
if (distanceFromStart < threshold) {
|
||||
const intensity = 1 - distanceFromStart / threshold;
|
||||
return { amount: -maxSpeed * intensity * intensity, edge: "start" };
|
||||
}
|
||||
else if (distanceFromEnd < threshold) {
|
||||
const intensity = 1 - distanceFromEnd / threshold;
|
||||
return { amount: maxSpeed * intensity * intensity, edge: "end" };
|
||||
}
|
||||
return { amount: 0, edge: null };
|
||||
}
|
||||
function autoScrollIfNeeded(groupElement, pointerPosition, axis, velocity) {
|
||||
if (!groupElement)
|
||||
return;
|
||||
// Track the group element for cleanup
|
||||
currentGroupElement = groupElement;
|
||||
const scrollableAncestor = findScrollableAncestor(groupElement, axis);
|
||||
if (!scrollableAncestor)
|
||||
return;
|
||||
// Convert pointer position from page coordinates to viewport coordinates.
|
||||
// The gesture system uses pageX/pageY but getBoundingClientRect() returns
|
||||
// viewport-relative coordinates, so we need to account for page scroll.
|
||||
const viewportPointerPosition = pointerPosition - (axis === "x" ? window.scrollX : window.scrollY);
|
||||
const { amount: scrollAmount, edge } = getScrollAmount(viewportPointerPosition, scrollableAncestor, axis);
|
||||
// If not in any threshold zone, clear all state
|
||||
if (edge === null) {
|
||||
activeScrollEdge.delete(scrollableAncestor);
|
||||
initialScrollLimits.delete(scrollableAncestor);
|
||||
return;
|
||||
}
|
||||
const currentActiveEdge = activeScrollEdge.get(scrollableAncestor);
|
||||
const isDocumentScroll = scrollableAncestor === document.body ||
|
||||
scrollableAncestor === document.documentElement;
|
||||
// If not currently scrolling this edge, check velocity to see if we should start
|
||||
if (currentActiveEdge !== edge) {
|
||||
// Only start scrolling if velocity is towards the edge
|
||||
const shouldStart = (edge === "start" && velocity < 0) ||
|
||||
(edge === "end" && velocity > 0);
|
||||
if (!shouldStart)
|
||||
return;
|
||||
// Activate this edge
|
||||
activeScrollEdge.set(scrollableAncestor, edge);
|
||||
// Record initial scroll limit (prevents infinite scroll)
|
||||
const maxScroll = axis === "x"
|
||||
? scrollableAncestor.scrollWidth - (isDocumentScroll ? window.innerWidth : scrollableAncestor.clientWidth)
|
||||
: scrollableAncestor.scrollHeight - (isDocumentScroll ? window.innerHeight : scrollableAncestor.clientHeight);
|
||||
initialScrollLimits.set(scrollableAncestor, maxScroll);
|
||||
}
|
||||
// Cap scrolling at initial limit (prevents infinite scroll)
|
||||
if (scrollAmount > 0) {
|
||||
const initialLimit = initialScrollLimits.get(scrollableAncestor);
|
||||
const currentScroll = axis === "x"
|
||||
? (isDocumentScroll ? window.scrollX : scrollableAncestor.scrollLeft)
|
||||
: (isDocumentScroll ? window.scrollY : scrollableAncestor.scrollTop);
|
||||
if (currentScroll >= initialLimit)
|
||||
return;
|
||||
}
|
||||
// Apply scroll
|
||||
if (axis === "x") {
|
||||
if (isDocumentScroll) {
|
||||
window.scrollBy({ left: scrollAmount });
|
||||
}
|
||||
else {
|
||||
scrollableAncestor.scrollLeft += scrollAmount;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isDocumentScroll) {
|
||||
window.scrollBy({ top: scrollAmount });
|
||||
}
|
||||
else {
|
||||
scrollableAncestor.scrollTop += scrollAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { autoScrollIfNeeded, resetAutoScrollState };
|
||||
//# sourceMappingURL=auto-scroll.mjs.map
|
||||
1
node_modules/framer-motion/dist/es/components/Reorder/utils/auto-scroll.mjs.map
generated
vendored
Normal file
1
node_modules/framer-motion/dist/es/components/Reorder/utils/auto-scroll.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
25
node_modules/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs
generated
vendored
Normal file
25
node_modules/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { mixNumber } from 'motion-dom';
|
||||
import { moveItem } from 'motion-utils';
|
||||
|
||||
function checkReorder(order, value, offset, velocity) {
|
||||
if (!velocity)
|
||||
return order;
|
||||
const index = order.findIndex((item) => item.value === value);
|
||||
if (index === -1)
|
||||
return order;
|
||||
const nextOffset = velocity > 0 ? 1 : -1;
|
||||
const nextItem = order[index + nextOffset];
|
||||
if (!nextItem)
|
||||
return order;
|
||||
const item = order[index];
|
||||
const nextLayout = nextItem.layout;
|
||||
const nextItemCenter = mixNumber(nextLayout.min, nextLayout.max, 0.5);
|
||||
if ((nextOffset === 1 && item.layout.max + offset > nextItemCenter) ||
|
||||
(nextOffset === -1 && item.layout.min + offset < nextItemCenter)) {
|
||||
return moveItem(order, index, index + nextOffset);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
|
||||
export { checkReorder };
|
||||
//# sourceMappingURL=check-reorder.mjs.map
|
||||
1
node_modules/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs.map
generated
vendored
Normal file
1
node_modules/framer-motion/dist/es/components/Reorder/utils/check-reorder.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"check-reorder.mjs","sources":["../../../../../src/components/Reorder/utils/check-reorder.ts"],"sourcesContent":["import { mixNumber } from \"motion-dom\"\nimport { moveItem } from \"motion-utils\"\nimport { ItemData } from \"../types\"\n\nexport function checkReorder<T>(\n order: ItemData<T>[],\n value: T,\n offset: number,\n velocity: number\n): ItemData<T>[] {\n if (!velocity) return order\n\n const index = order.findIndex((item) => item.value === value)\n\n if (index === -1) return order\n\n const nextOffset = velocity > 0 ? 1 : -1\n const nextItem = order[index + nextOffset]\n\n if (!nextItem) return order\n\n const item = order[index]\n const nextLayout = nextItem.layout\n const nextItemCenter = mixNumber(nextLayout.min, nextLayout.max, 0.5)\n\n if (\n (nextOffset === 1 && item.layout.max + offset > nextItemCenter) ||\n (nextOffset === -1 && item.layout.min + offset < nextItemCenter)\n ) {\n return moveItem(order, index, index + nextOffset)\n }\n\n return order\n}\n"],"names":[],"mappings":";;;AAIM,SAAU,YAAY,CACxB,KAAoB,EACpB,KAAQ,EACR,MAAc,EACd,QAAgB,EAAA;AAEhB,IAAA,IAAI,CAAC,QAAQ;AAAE,QAAA,OAAO,KAAK;AAE3B,IAAA,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC;IAE7D,IAAI,KAAK,KAAK,EAAE;AAAE,QAAA,OAAO,KAAK;AAE9B,IAAA,MAAM,UAAU,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,GAAG,UAAU,CAAC;AAE1C,IAAA,IAAI,CAAC,QAAQ;AAAE,QAAA,OAAO,KAAK;AAE3B,IAAA,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC;AACzB,IAAA,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM;AAClC,IAAA,MAAM,cAAc,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;AAErE,IAAA,IACI,CAAC,UAAU,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,GAAG,cAAc;AAC9D,SAAC,UAAU,KAAK,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,GAAG,MAAM,GAAG,cAAc,CAAC,EAClE;QACE,OAAO,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,UAAU,CAAC;IACrD;AAEA,IAAA,OAAO,KAAK;AAChB;;;;"}
|
||||
Reference in New Issue
Block a user