Fix QC Kak Inno 8 Des

Fix QC Kak Ayu 8 Des
Fix QC Pak Jun 8 Des
This commit is contained in:
2025-12-09 17:27:23 +08:00
parent 9dbe172165
commit ac2fc1a705
44 changed files with 712 additions and 477 deletions

View File

@@ -55,8 +55,8 @@ function APBDesProgress({ apbdesData }: APBDesProgressProps) {
return (
<Box key={label}>
<Text fw={600} fz="sm">{label}</Text>
<Text fw={700} mb="xs">
<Text fw={600} fz={{base: "sm", md: "md"}}>{label}</Text>
<Text fw={700} fz={{base: "sm", md: "md"}} mb="xs">
{formatRupiah(dataset.realisasi)} | {formatRupiah(dataset.anggaran)}
</Text>
<Progress

View File

@@ -39,22 +39,20 @@ function Slider() {
const state = useProxy(penghargaanState);
const router = useTransitionRouter();
// Refs for smooth animation
const containerRef = useRef<HTMLDivElement>(null);
const scrollPositionRef = useRef(0);
const animationFrameRef = useRef<number>(0);
const scrollPosRef = useRef(0);
const animFrameRef = useRef<number>(0);
const isHoveredRef = useRef(false);
// Refs for drag functionality
const isDraggingRef = useRef(false);
const startXRef = useRef(0);
const scrollLeftRef = useRef(0);
const velocityRef = useRef(0);
const lastScrollTimeRef = useRef(0);
const lastScrollRef = useRef(0);
// Speed configuration
const normalSpeed = 1.0; // pixels per frame
const hoverSpeed = 0.5; // slower speed on hover
const SPEED_NORMAL = 1.0;
const SPEED_HOVER = 0.5;
const VELOCITY_DECAY = 0.95;
const SCROLL_THRESHOLD = 100;
useEffect(() => {
state.findMany.load();
@@ -63,120 +61,114 @@ function Slider() {
const data = state.findMany.data || [];
const loading = state.findMany.loading;
// Duplicate slides for seamless infinite loop
const slidesData = [...data, ...data, ...data];
// Triple data untuk infinite loop (desktop only)
const slidesData = mobile ? data : [...data, ...data, ...data];
// Auto-scroll animation untuk desktop
useEffect(() => {
if (loading || !containerRef.current || slidesData.length === 0) return;
if (loading || !containerRef.current || data.length === 0 || mobile) return;
const container = containerRef.current;
const slideWidth = container.scrollWidth / slidesData.length;
const originalDataLength = data.length;
const originalLength = data.length;
// Start from the middle set of slides
scrollPositionRef.current = slideWidth * originalDataLength;
container.scrollLeft = scrollPositionRef.current;
// Start dari middle set
scrollPosRef.current = slideWidth * originalLength;
container.scrollLeft = scrollPosRef.current;
const animate = () => {
if (!containerRef.current) return;
const container = containerRef.current;
const slideWidth = container.scrollWidth / slidesData.length;
const timeSinceScroll = Date.now() - lastScrollRef.current;
const isUserScrolling = timeSinceScroll < SCROLL_THRESHOLD;
// Check if user recently scrolled manually
const timeSinceLastScroll = Date.now() - lastScrollTimeRef.current;
const isUserScrolling = timeSinceLastScroll < 100;
// Only auto-scroll if user is not actively scrolling or dragging
if (!isDraggingRef.current && !isUserScrolling) {
const currentSpeed = isHoveredRef.current ? hoverSpeed : normalSpeed;
scrollPositionRef.current += currentSpeed;
const speed = isHoveredRef.current ? SPEED_HOVER : SPEED_NORMAL;
scrollPosRef.current += speed;
// Reset position for infinite loop
if (scrollPositionRef.current >= slideWidth * (originalDataLength * 2)) {
scrollPositionRef.current -= slideWidth * originalDataLength;
// Reset untuk infinite loop
if (scrollPosRef.current >= slideWidth * (originalLength * 2)) {
scrollPosRef.current -= slideWidth * originalLength;
}
if (scrollPosRef.current <= 0) {
scrollPosRef.current += slideWidth * originalLength;
}
if (scrollPositionRef.current <= 0) {
scrollPositionRef.current += slideWidth * originalDataLength;
}
container.scrollLeft = scrollPositionRef.current;
container.scrollLeft = scrollPosRef.current;
} else {
// Sync scroll position when user is scrolling
scrollPositionRef.current = container.scrollLeft;
// Apply momentum/velocity for smooth drag release
scrollPosRef.current = container.scrollLeft;
// Momentum untuk drag release
if (!isDraggingRef.current && Math.abs(velocityRef.current) > 0.1) {
scrollPositionRef.current += velocityRef.current;
velocityRef.current *= 0.95; // Decay velocity
container.scrollLeft = scrollPositionRef.current;
scrollPosRef.current += velocityRef.current;
velocityRef.current *= VELOCITY_DECAY;
container.scrollLeft = scrollPosRef.current;
}
}
animationFrameRef.current = requestAnimationFrame(animate);
animFrameRef.current = requestAnimationFrame(animate);
};
animationFrameRef.current = requestAnimationFrame(animate);
animFrameRef.current = requestAnimationFrame(animate);
return () => {
if (animationFrameRef.current) {
cancelAnimationFrame(animationFrameRef.current);
if (animFrameRef.current) {
cancelAnimationFrame(animFrameRef.current);
}
};
}, [loading, slidesData.length, data.length, mobile]);
}, [loading, data.length, mobile]);
const handleMouseEnter = () => {
isHoveredRef.current = true;
if (!mobile) isHoveredRef.current = true;
};
const handleMouseLeave = () => {
isHoveredRef.current = false;
isDraggingRef.current = false;
if (!mobile) {
isHoveredRef.current = false;
isDraggingRef.current = false;
}
};
// Mouse drag handlers
const handleMouseDown = (e: React.MouseEvent) => {
if (!containerRef.current) return;
if (!containerRef.current || mobile) return;
isDraggingRef.current = true;
startXRef.current = e.pageX - containerRef.current.offsetLeft;
scrollLeftRef.current = containerRef.current.scrollLeft;
velocityRef.current = 0;
containerRef.current.style.cursor = 'grabbing';
};
const handleMouseMove = (e: React.MouseEvent) => {
if (!isDraggingRef.current || !containerRef.current) return;
if (!isDraggingRef.current || !containerRef.current || mobile) return;
e.preventDefault();
const x = e.pageX - containerRef.current.offsetLeft;
const walk = (x - startXRef.current) * 2;
const newScrollLeft = scrollLeftRef.current - walk;
velocityRef.current = containerRef.current.scrollLeft - newScrollLeft;
containerRef.current.scrollLeft = newScrollLeft;
scrollPositionRef.current = newScrollLeft;
lastScrollTimeRef.current = Date.now();
scrollPosRef.current = newScrollLeft;
lastScrollRef.current = Date.now();
};
const handleMouseUp = () => {
if (!containerRef.current) return;
if (!containerRef.current || mobile) return;
isDraggingRef.current = false;
containerRef.current.style.cursor = 'grab';
};
// Wheel scroll handler
const handleWheel = (e: React.WheelEvent) => {
if (!containerRef.current) return;
if (!containerRef.current || mobile) return;
e.preventDefault();
containerRef.current.scrollLeft += e.deltaY;
scrollPositionRef.current = containerRef.current.scrollLeft;
lastScrollTimeRef.current = Date.now();
scrollPosRef.current = containerRef.current.scrollLeft;
lastScrollRef.current = Date.now();
};
if (loading) {
@@ -211,37 +203,45 @@ function Slider() {
onWheel={handleWheel}
py="xl"
style={{
overflow: "hidden",
cursor: "grab",
overflowX: mobile ? "auto" : "hidden",
overflowY: "hidden",
cursor: mobile ? "default" : "grab",
userSelect: "none",
position: "relative",
WebkitOverflowScrolling: "touch",
scrollbarWidth: "none",
msOverflowStyle: "none",
}}
>
{/* Blur edges effect */}
<Box
style={{
position: "absolute",
top: 0,
left: 0,
width: "120px",
height: "100%",
background: "linear-gradient(to right, rgba(249, 250, 251, 1), rgba(249, 250, 251, 0))",
zIndex: 10,
pointerEvents: "none",
}}
/>
<Box
style={{
position: "absolute",
top: 0,
right: 0,
width: "120px",
height: "100%",
background: "linear-gradient(to left, rgba(249, 250, 251, 1), rgba(249, 250, 251, 0))",
zIndex: 10,
pointerEvents: "none",
}}
/>
{/* Blur edges - hanya untuk desktop */}
{!mobile && (
<>
<Box
style={{
position: "absolute",
top: 0,
left: 0,
width: "120px",
height: "100%",
background: "linear-gradient(to right, rgba(249, 250, 251, 1), rgba(249, 250, 251, 0))",
zIndex: 10,
pointerEvents: "none",
}}
/>
<Box
style={{
position: "absolute",
top: 0,
right: 0,
width: "120px",
height: "100%",
background: "linear-gradient(to left, rgba(249, 250, 251, 1), rgba(249, 250, 251, 0))",
zIndex: 10,
pointerEvents: "none",
}}
/>
</>
)}
<Box
style={{
@@ -255,8 +255,8 @@ function Slider() {
<Box
key={`${item.id}-${index}`}
style={{
flex: `0 0 ${mobile ? "90%" : "calc(33.333% - 1rem)"}`,
minWidth: mobile ? "90%" : "calc(33.333% - 1rem)",
flex: `0 0 ${mobile ? "85%" : "calc(33.333% - 1rem)"}`,
minWidth: mobile ? "85%" : "calc(33.333% - 1rem)",
}}
>
<Paper
@@ -272,12 +272,16 @@ function Slider() {
overflow: "hidden",
}}
onMouseEnter={(e) => {
e.currentTarget.style.transform = "translateY(-8px) scale(1.02)";
e.currentTarget.style.boxShadow = "0 12px 28px rgba(0,0,0,0.25)";
if (!mobile) {
e.currentTarget.style.transform = "translateY(-8px) scale(1.02)";
e.currentTarget.style.boxShadow = "0 12px 28px rgba(0,0,0,0.25)";
}
}}
onMouseLeave={(e) => {
e.currentTarget.style.transform = "translateY(0) scale(1)";
e.currentTarget.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)";
if (!mobile) {
e.currentTarget.style.transform = "translateY(0) scale(1)";
e.currentTarget.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)";
}
}}
>
<Box

View File

@@ -13,7 +13,7 @@ function Page() {
const state = useProxy(prestasiState.prestasiDesa);
const router = useRouter();
const [search, setSearch] = useState("");
const [debouncedSearch] = useDebouncedValue(search, 500); // 500ms delay
const [debouncedSearch] = useDebouncedValue(search, 1000); // 500ms delay
const { data, page, totalPages, loading, load } = state.findMany;