Skip to content

Commit

Permalink
Got to create dropdown now
Browse files Browse the repository at this point in the history
  • Loading branch information
ChurroC committed Mar 12, 2024
1 parent cb526f0 commit 05f9d39
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 92 deletions.
34 changes: 14 additions & 20 deletions src/components/dropdown/dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"use client";

import { DropdownProvider, getDropdownContext } from "@/util/contexts/dropdown";
import { DropdownPortal } from "./dropdownInPortal";
import { InPortal } from "@/util/helpers/inPortal";
import { DropdownElement } from "./dropdownElement";

// This fits all my needs
// Cannot be nested
export function DropdownContext({
children
}: {
Expand All @@ -25,35 +26,28 @@ export function DropdownTrigger({
<button
className={className}
onClick={() => setIsOpen(!isOpen)}
ref={referenceElement as React.RefObject<HTMLButtonElement>}
ref={referenceElement}
>
{children}
</button>
);
}

// Make having a refernce elment optional to position aorudn it or just use manual css
// I can use this instead to give my own customizations to do what basically Dropdown does in one
// Use portal but have to have actual dropdown in a separate component to not run on server since inside Inportal there is NoSSRWrapper which causes children to run on client
// children but not the parent or where it is defined
export function DropdownContent({
children,
className,
referenceElement: customReferenceElement
className
}: {
children: React.ReactNode;
className?: string;
referenceElement?: React.RefObject<HTMLElement>;
}) {
const [isOpen, , referenceElement] = getDropdownContext();

if (isOpen) {
return (
<DropdownPortal
className={className}
referenceElement={customReferenceElement ?? referenceElement}
>
{children}
</DropdownPortal>
);
}
const [isOpen] = getDropdownContext();

return null;
return isOpen ? (
<InPortal>
<DropdownElement className={className}>{children}</DropdownElement>
</InPortal>
) : null;
}
32 changes: 32 additions & 0 deletions src/components/dropdown/dropdownElement.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { twMerge } from "tailwind-merge";
import { getDropdownContext } from "@/util/contexts/dropdown";

// This is the actual dropdown
export function DropdownElement({
children,
className
}: {
children: React.ReactNode;
className?: string;
}) {
const [, , referenceElement] = getDropdownContext();

const { top, right, left } =
referenceElement?.current?.getBoundingClientRect() ?? {
top: 0,
bottom: 0,
right: 0,
left: 0
};

const centerX = left + (right - left) / 2;

return (
<div
className={twMerge(`fixed`, className)}
style={{ left: centerX, top: top + 30 }}
>
{children}
</div>
);
}
54 changes: 0 additions & 54 deletions src/components/dropdown/dropdownInPortal.tsx

This file was deleted.

10 changes: 1 addition & 9 deletions src/components/header/icons/darkModeIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,21 @@
"use client";

import { HeaderIcon } from "./headerIcon";
import { SunIcon } from "@heroicons/react/24/outline";
import {
Dropdown,
DropdownContent,
DropdownTrigger
} from "@/components/dropdown";
import { useRef } from "react";

// Client component since local storage
export function DarkModeIcon() {
const referenceElement = useRef(null);

return (
<Dropdown>
<DropdownTrigger>
<HeaderIcon className="w-8">
<SunIcon className="h-5" />
</HeaderIcon>
<div className="fixed top-30" ref={referenceElement}>
igik
</div>
</DropdownTrigger>
<DropdownContent referenceElement={referenceElement}>
<DropdownContent className="flex">
<div className="bg-slate-600">wow</div>
</DropdownContent>
</Dropdown>
Expand Down
18 changes: 15 additions & 3 deletions src/components/header/icons/languagePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
import {
Dropdown,
DropdownContent,
DropdownTrigger
} from "@/components/dropdown";
import { HeaderIcon } from "@/components/header/icons/headerIcon";
import { LanguageIcon } from "@heroicons/react/24/outline";

// Client component since local storage
export function LanguagePicker() {
return (
<HeaderIcon className="w-8">
<LanguageIcon className="h-5" />
</HeaderIcon>
<Dropdown>
<DropdownTrigger>
<HeaderIcon className="w-8">
<LanguageIcon className="h-5" />
</HeaderIcon>
</DropdownTrigger>
<DropdownContent className="flex">
<div className="bg-slate-600">wow</div>
</DropdownContent>
</Dropdown>
);
}
15 changes: 9 additions & 6 deletions src/util/contexts/dropdown/dropdown.context.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
"use client";

import { createContext, use, useRef, useState } from "react";
import { useToggle } from "@/util/hooks/useToggle";
import { createContext, use, useRef } from "react";

const DropdownContext = createContext<
[
boolean,
React.Dispatch<React.SetStateAction<boolean>>,
React.RefObject<HTMLElement>
React.RefObject<HTMLButtonElement>
]
>([false, () => {}, { current: null }]);

export function DropdownProvider({ children }: { children: React.ReactNode }) {
const [isOpen, setIsOpen] = useState(false);
const referenceElement = useRef<HTMLElement>(null);
const [isOpen, toggleIsOpen] = useToggle();
const referenceElement = useRef<HTMLButtonElement>(null);

return (
<DropdownContext.Provider value={[isOpen, setIsOpen, referenceElement]}>
<DropdownContext.Provider
value={[isOpen, toggleIsOpen, referenceElement]}
>
{children}
</DropdownContext.Provider>
);
Expand All @@ -24,7 +27,7 @@ export function DropdownProvider({ children }: { children: React.ReactNode }) {
export function getDropdownContext(): [
boolean,
React.Dispatch<React.SetStateAction<boolean>>,
React.RefObject<HTMLElement>
React.RefObject<HTMLButtonElement>
] {
return use(DropdownContext);
}
13 changes: 13 additions & 0 deletions src/util/hooks/useToggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useCallback, useState } from "react";

export function useToggle(
initialValue = false
): [boolean, React.Dispatch<React.SetStateAction<boolean>>] {
const [value, setValue] = useState(initialValue);

const toggle = useCallback(() => {
setValue(val => !val);
}, []);

return [value, toggle];
}

1 comment on commit 05f9d39

@vercel
Copy link

@vercel vercel bot commented on 05f9d39 Mar 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

robotics – ./

robotics-git-main-churroc.vercel.app
robotics-pied.vercel.app
robotics-churroc.vercel.app

Please sign in to comment.