From 3f87bda1b5a43099c8cc3b31619fba71ca68d888 Mon Sep 17 00:00:00 2001 From: Raphael Cunha Date: Mon, 18 Nov 2024 18:27:54 -0300 Subject: [PATCH 1/2] feat: add link button to share component --- app/selects/page.tsx | 156 ++++++++++++++++++++-------------------- demo/card-component.tsx | 59 +++++++++++++++ demo/copy-button.tsx | 141 +++++++++++++++++------------------- demo/demo-component.tsx | 37 +++++----- demo/link-button.tsx | 87 ++++++++++++++++++++++ demo/name-component.tsx | 21 ++++++ 6 files changed, 332 insertions(+), 169 deletions(-) create mode 100644 demo/card-component.tsx create mode 100644 demo/link-button.tsx create mode 100644 demo/name-component.tsx diff --git a/app/selects/page.tsx b/app/selects/page.tsx index 00c59fa..09d3f7e 100644 --- a/app/selects/page.tsx +++ b/app/selects/page.tsx @@ -4,91 +4,91 @@ import PageHeader from "@/demo/page-header"; import type { Metadata } from "next"; export const metadata: Metadata = { - title: "Select Components - Origin UI", - description: - "A collection of beautiful and accessible select components built with Tailwind CSS and Next.js.", + title: "Select Components - Origin UI", + description: + "A collection of beautiful and accessible select components built with Tailwind CSS and Next.js.", }; const directory = "selects"; const files = [ - "select-01", - "select-02", - "select-03", - "select-04", - "select-05", - "select-06", - "select-07", - "select-08", - "select-09", - "select-10", - "select-11", - "select-12", - "select-13", - "select-14", - "select-15", - "select-16", - "select-17", - "select-18", - "select-19", - "select-20", - "select-21", - "select-22", - "select-23", - "select-24", - "select-25", - "select-26", - "select-27", - "select-28", - "select-29", - "select-30", - "select-31", - "select-32", - "select-33", - "select-34", - "select-35", - "select-36", - "select-37", - "select-38", - "select-39", - "select-40", - "select-41", - "select-42", - "select-43", - "select-44", - "select-45", - "select-46", - "select-47", - "select-48", - "select-49", - "select-50", - "select-51", + "select-01", + "select-02", + "select-03", + "select-04", + "select-05", + "select-06", + "select-07", + "select-08", + "select-09", + "select-10", + "select-11", + "select-12", + "select-13", + "select-14", + "select-15", + "select-16", + "select-17", + "select-18", + "select-19", + "select-20", + "select-21", + "select-22", + "select-23", + "select-24", + "select-25", + "select-26", + "select-27", + "select-28", + "select-29", + "select-30", + "select-31", + "select-32", + "select-33", + "select-34", + "select-35", + "select-36", + "select-37", + "select-38", + "select-39", + "select-40", + "select-41", + "select-42", + "select-43", + "select-44", + "select-45", + "select-46", + "select-47", + "select-48", + "select-49", + "select-50", + "select-51", ]; export default function Page() { - return ( -
-
-
- - A growing collection of {files.length} select components built with Next.js and - TailwindCSS. - + return ( +
+
+
+ + A growing collection of {files.length} select components built with + Next.js and TailwindCSS. + -
- {files.map((componentName) => { - return ( - - ); - })} -
+
+ {files.map((componentName) => { + return ( + + ); + })} +
- -
-
-
- ); + +
+
+
+ ); } diff --git a/demo/card-component.tsx b/demo/card-component.tsx new file mode 100644 index 0000000..b3d1b4e --- /dev/null +++ b/demo/card-component.tsx @@ -0,0 +1,59 @@ +"use client"; +import { cn } from "@/lib/utils"; +import LinkButton from "./link-button"; +import CopyButton from "./copy-button"; +import { useEffect, useRef } from "react"; +import { useState } from "react"; +import NameComponent from "./name-component"; + +const CardComponent = ({ + componentName, + directory, + className, + children, + source, +}: { + componentName: string; + directory: string; + className?: string; + children: React.ReactNode; + source: string; +}) => { + const ref = useRef(null); + const [selected, setSelected] = useState(false); + + useEffect(() => { + const isSelected = + typeof window !== "undefined" && + window.location.hash === `#${componentName}`; + + if (isSelected) { + setTimeout(() => { + window.scrollTo({ + top: (ref.current?.offsetTop || 0) - window.innerHeight / 2 + 160, + behavior: "smooth", + }); + setSelected(isSelected); + }, 300); + } + }, [componentName]); + + return ( +
+ {children} + + + +
+ ); +}; + +export default CardComponent; diff --git a/demo/copy-button.tsx b/demo/copy-button.tsx index 92b0160..f9640d3 100644 --- a/demo/copy-button.tsx +++ b/demo/copy-button.tsx @@ -1,87 +1,78 @@ "use client"; import { Button } from "@/components/ui/button"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; +import { Check, Code, Copy } from "lucide-react"; import { useState } from "react"; const CopyButton = ({ componentSource }: { componentSource: string }) => { - const [copied, setCopied] = useState(false); + const [copied, setCopied] = useState(false); - const handleCopy = async () => { - try { - await navigator.clipboard.writeText(componentSource); - setCopied(true); - setTimeout(() => setCopied(false), 1500); - } catch (err) { - console.error("Failed to copy text: ", err); - } - }; + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(componentSource); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + } catch (err) { + console.error("Failed to copy text: ", err); + } + }; - return ( -
- - - - - - - Copy - - - -
- ); + return ( +
+ + + + + + + Copy Code + + + +
+ ); }; export default CopyButton; diff --git a/demo/demo-component.tsx b/demo/demo-component.tsx index 85ec640..bc764af 100644 --- a/demo/demo-component.tsx +++ b/demo/demo-component.tsx @@ -1,23 +1,28 @@ -import { cn } from "@/lib/utils"; -import CopyButton from "./copy-button"; import { readComponentSource } from "./read-component-source"; +import CardComponent from "./card-component"; export default async function DemoComponent({ - directory, - componentName, - className, + directory, + componentName, + className, }: { - directory: string; - componentName: string; - className?: string; + directory: string; + componentName: string; + className?: string; }) { - const Component = (await import(`@/components/${directory}/${componentName}`)).default; - const source = await readComponentSource(directory, componentName); + // get anchor from url + const Component = (await import(`@/components/${directory}/${componentName}`)) + .default; + const source = await readComponentSource(directory, componentName); - return ( -
- - -
- ); + return ( + + + + ); } diff --git a/demo/link-button.tsx b/demo/link-button.tsx new file mode 100644 index 0000000..1f562c7 --- /dev/null +++ b/demo/link-button.tsx @@ -0,0 +1,87 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { cn } from "@/lib/utils"; +import { useState } from "react"; +import { Check, Link2 } from "lucide-react"; + +interface ShareButtonProps { + componentName: string; + directory: string; +} + +const ShareButton = ({ componentName, directory }: ShareButtonProps) => { + console.log("directory", directory); + const [copied, setCopied] = useState(false); + const url = + typeof window !== "undefined" && + `${window.location.origin}/${directory}#${componentName}`; + + const handleCopy = async () => { + try { + await navigator.clipboard.writeText(url || ""); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + } catch (err) { + console.error("Failed to copy link: ", err); + } + }; + + return ( +
+ + + + + + + Copy Link + + + +
+ ); +}; + +export default ShareButton; diff --git a/demo/name-component.tsx b/demo/name-component.tsx new file mode 100644 index 0000000..44b7b03 --- /dev/null +++ b/demo/name-component.tsx @@ -0,0 +1,21 @@ +import { cn } from "@/lib/utils"; + +interface NameComponentProps { + componentName: string; + isSelected: boolean; +} + +const NameComponent = ({ componentName, isSelected }: NameComponentProps) => { + return ( +
+ {componentName} +
+ ); +}; + +export default NameComponent; From 58dd089d8b29e94ce3f2179bd9f10dc030f58b1a Mon Sep 17 00:00:00 2001 From: Raphael Cunha Date: Mon, 18 Nov 2024 19:55:50 -0300 Subject: [PATCH 2/2] feat: add link button to share component --- demo/card-component.tsx | 2 +- demo/link-button.tsx | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/demo/card-component.tsx b/demo/card-component.tsx index b3d1b4e..fbbcead 100644 --- a/demo/card-component.tsx +++ b/demo/card-component.tsx @@ -44,7 +44,7 @@ const CardComponent = ({ data-selected={selected} className={cn( "group/item relative hover", - selected && "bg-zinc-50", + selected && "bg-zinc-50 border-x-2 border-zinc-200", className, )} > diff --git a/demo/link-button.tsx b/demo/link-button.tsx index 1f562c7..c57fb49 100644 --- a/demo/link-button.tsx +++ b/demo/link-button.tsx @@ -17,14 +17,13 @@ interface ShareButtonProps { } const ShareButton = ({ componentName, directory }: ShareButtonProps) => { - console.log("directory", directory); const [copied, setCopied] = useState(false); - const url = - typeof window !== "undefined" && - `${window.location.origin}/${directory}#${componentName}`; const handleCopy = async () => { try { + const url = + typeof window !== "undefined" && + `${window.location.origin}/${directory}#${componentName}`; await navigator.clipboard.writeText(url || ""); setCopied(true); setTimeout(() => setCopied(false), 1500);