Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC: Enhance Filter UI #33

Merged
merged 1 commit into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 112 additions & 66 deletions frontend/app/components/ui/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { createContext, useContext, useState, ReactNode } from "react";
import { cn } from "@/lib/utils";
import { X, Menu } from "lucide-react";
import { cn } from "@/lib/utils";
import { Menu, X } from "lucide-react";
import React, { createContext, useContext, useState, ReactNode, useRef, useEffect } from "react";

interface SidebarContextType {
isOpen: boolean;
Expand Down Expand Up @@ -28,75 +28,121 @@ export const useSidebar = () => {
return context;
};

export const Sidebar = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => {
const { isOpen } = useSidebar();
return (
<div
ref={ref}
className={cn(
"fixed inset-y-0 left-0 z-50 w-64 bg-white shadow-lg transition-transform duration-300",
isOpen ? "translate-x-0" : "-translate-x-full",
className
)}
{...props}
/>
);
}
);
export const Sidebar = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => {
const { isOpen, toggleSidebar } = useSidebar();
const sidebarRef = useRef<HTMLDivElement>(null);

// Close sidebar when clicking outside
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (sidebarRef.current && !sidebarRef.current.contains(event.target as Node)) {
// Close sidebar if the click is outside
if (isOpen) {
toggleSidebar();
}
}
};

document.addEventListener("mousedown", handleClickOutside);

return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [isOpen, toggleSidebar]);

return (
<div
ref={(node) => {
sidebarRef.current = node;
if (ref) {
if (typeof ref === "function") ref(node);
else ref.current = node;
}
}}
className={cn(
"fixed inset-y-0 left-0 z-50 w-64 bg-white shadow-lg transition-transform duration-300",
isOpen ? "translate-x-0" : "-translate-x-full",
className
)}
{...props}
/>
);
});
Sidebar.displayName = "Sidebar";

export const SidebarHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("px-4 py-2 border-b flex justify-between items-center", className)} {...props}>
{props.children}
<SidebarClose />
</div>
)
);
export const SidebarHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"px-4 py-2 border-b flex justify-between items-center",
className
)}
{...props}
>
{props.children}
<SidebarClose />
</div>
));
SidebarHeader.displayName = "SidebarHeader";

export const SidebarContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex-1 overflow-y-auto p-4", className)} {...props} />
)
);
export const SidebarContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex-1 overflow-y-auto", className)}
{...props}
/>
));
SidebarContent.displayName = "SidebarContent";

export const SidebarTrigger = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn("p-2", className)}
{...props}
>
<Menu size={30} className="text-black"/>
<span className="sr-only">Toggle Sidebar</span>
</button>
);
}
);
export const SidebarTrigger = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn(
"flex items-center gap-2 mt-2 p-1 border border-transparent hover:border-[#ccc] transition-all duration-200",
className
)}
{...props}
>
<Menu size={30} className="text-black" />
<span className="text-sm">All</span>
</button>
);
});
SidebarTrigger.displayName = "SidebarTrigger";

export const SidebarClose = React.forwardRef<HTMLButtonElement, React.ButtonHTMLAttributes<HTMLButtonElement>>(
({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn("absolute right-4 top-4 opacity-70 hover:opacity-100", className)}
{...props}
>
<X className="h-4 w-4" />
<span className="sr-only">Close Sidebar</span>
</button>
);
}
);
export const SidebarClose = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
onClick={toggleSidebar}
className={cn(
"absolute right-4 top-4 opacity-70 hover:opacity-100",
className
)}
{...props}
>
<X className="h-4 w-4" />
<span className="sr-only">Close Sidebar</span>
</button>
);
});
SidebarClose.displayName = "SidebarClose";

// export { SidebarProvider, Sidebar, SidebarHeader, SidebarContent, SidebarTrigger, SidebarClose };
60 changes: 37 additions & 23 deletions frontend/app/components/ui/slider.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
"use client"

import * as React from "react"
import * as SliderPrimitive from "@radix-ui/react-slider"

import { cn } from "@/lib/utils"
import * as SliderPrimitive from "@radix-ui/react-slider";
import * as React from "react";
import { cn } from "@/lib/utils";

const Slider = React.forwardRef<
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
>(({ className, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
className
)}
{...props}
>
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>
<SliderPrimitive.Thumb className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50" />
</SliderPrimitive.Root>
))
Slider.displayName = SliderPrimitive.Root.displayName
React.ElementRef<typeof SliderPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & { value: [number, number]; onValueChange: (value: [number, number]) => void; }
>(({ className, value, onValueChange, ...props }, ref) => (
<SliderPrimitive.Root
ref={ref}
className={cn("relative flex w-full touch-none select-none items-center", className)}
value={value}
onValueChange={onValueChange}
max={1500}
min={0}
step={10}
{...props}
>
{/* Range */}
<SliderPrimitive.Track className="relative h-2 w-full grow overflow-hidden rounded-full bg-secondary">
<SliderPrimitive.Range className="absolute h-full bg-primary" />
</SliderPrimitive.Track>

{/* Min Value */}
<SliderPrimitive.Thumb
className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
style={{ left: `${(value[0] / 1500) * 100}%` }}
/>

{/* Max Value */}
<SliderPrimitive.Thumb
className="block h-5 w-5 rounded-full border-2 border-primary bg-background ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
style={{ left: `${(value[1] / 1500) * 100}%` }}
/>
</SliderPrimitive.Root>
));

Slider.displayName = "Slider";

export { Slider }
export { Slider }
Loading
Loading