From f92b4aa646e8d06823a7316570de7f8bd45d43bf Mon Sep 17 00:00:00 2001 From: Victor Trinh Date: Wed, 18 Dec 2024 13:35:00 -0500 Subject: [PATCH] Allow filtering of icons and components --- .../docs/app/ui/icons/iconTable/IconTable.tsx | 19 +++-- apps/docs/app/ui/icons/switcher/Switcher.tsx | 21 ++++-- apps/docs/app/ui/icons/switcher/switcher.css | 7 +- apps/docs/app/ui/layout/sidebar/Sidebar.tsx | 75 ++++++++++++------- apps/docs/app/ui/layout/sidebar/sidebar.css | 1 - 5 files changed, 83 insertions(+), 40 deletions(-) diff --git a/apps/docs/app/ui/icons/iconTable/IconTable.tsx b/apps/docs/app/ui/icons/iconTable/IconTable.tsx index c7e43ad91..97596a6d3 100644 --- a/apps/docs/app/ui/icons/iconTable/IconTable.tsx +++ b/apps/docs/app/ui/icons/iconTable/IconTable.tsx @@ -1,20 +1,24 @@ "use client"; -import IconItem from "./IconItem"; -import * as IconLibrary from "@hopper-ui/icons"; import { HopperProvider } from "@hopper-ui/components"; +import * as IconLibrary from "@hopper-ui/icons"; +import IconItem from "./IconItem"; +import { ThemeContext } from "@/context/theme/ThemeProvider"; +import { useContext } from "react"; import "./iconTable.css"; interface IconTableProps { size: "sm" | "md" | "lg" | "xl"; type: "svg" | "react"; items: typeof IconLibrary.iconNames | typeof IconLibrary.richIconNames; + filter?: string; } function toKebabCase(str: string) { return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); } + function getIconNumericSize(iconSize : "sm" | "md" | "lg" | "xl") { switch (iconSize) { case "sm": @@ -28,8 +32,13 @@ function getIconNumericSize(iconSize : "sm" | "md" | "lg" | "xl") { } } -export const IconTable = ({ size, type, items }: IconTableProps) => { - const listItems = items.map(name => { +export const IconTable = ({ size, type, items, filter }: IconTableProps) => { + const { colorMode } = useContext(ThemeContext); + const listItems = items.filter(name => { + const formattedName = name.replace("RichIcon", "").replace("Icon", ""); + + return !filter || formattedName.toLowerCase().includes(filter.trim().toLowerCase()); + }).map(name => { const formattedName = name.replace("RichIcon", "").replace("Icon", ""); const copyString = type === "react" ? `${name}` @@ -45,7 +54,7 @@ export const IconTable = ({ size, type, items }: IconTableProps) => { }); return ( - +
{listItems}
diff --git a/apps/docs/app/ui/icons/switcher/Switcher.tsx b/apps/docs/app/ui/icons/switcher/Switcher.tsx index dcc5bc090..83e9cafaf 100644 --- a/apps/docs/app/ui/icons/switcher/Switcher.tsx +++ b/apps/docs/app/ui/icons/switcher/Switcher.tsx @@ -1,10 +1,12 @@ "use client"; -import { memo, useState, type ReactNode } from "react"; -import { RadioGroup, Radio, type RadioProps } from "react-aria-components"; import { IconTable } from "@/app/ui/icons/iconTable/IconTable.tsx"; import { SparklesIcon, SparklesRichIcon, iconNames, richIconNames } from "@hopper-ui/icons"; +import { memo, useContext, useState, type ReactNode } from "react"; +import { Radio, RadioGroup, type RadioProps } from "react-aria-components"; +import { ThemeContext } from "@/context/theme/ThemeProvider"; +import { HopperProvider, TextField } from "@hopper-ui/components"; import "./switcher.css"; interface SwitcherProps { @@ -15,21 +17,30 @@ interface SwitcherProps { type AvailableSizes = "sm"| "md" | "lg" | "xl"; const Switcher = memo(({ type, iconType = "icon" }: SwitcherProps) => { + const { colorMode } = useContext(ThemeContext); + const [filter, setFilter] = useState(""); const [selectedSize, setSelectedSize] = useState(iconType === "icon" ? "md" : "lg"); const Icon = iconType === "icon" ? SparklesIcon : SparklesRichIcon; const iconList = iconType === "icon" ? iconNames : richIconNames; + const onTextFieldChange = (value: string) => { + setFilter(value); + }; + return ( - <> +
setSelectedSize(value as AvailableSizes)}> {iconType === "icon" && } />} } /> } /> {iconType === "richIcon" && } />} - - + + + + +
); }); diff --git a/apps/docs/app/ui/icons/switcher/switcher.css b/apps/docs/app/ui/icons/switcher/switcher.css index 2152e9fb6..dd3a7be22 100644 --- a/apps/docs/app/ui/icons/switcher/switcher.css +++ b/apps/docs/app/ui/icons/switcher/switcher.css @@ -1,5 +1,4 @@ .hd-switcher-picker { - margin-bottom: var(--hd-space-3); display: flex; gap: var(--hd-space-2); } @@ -57,3 +56,9 @@ .hd-switcher-choice:has(input:focus-visible) { outline: -webkit-focus-ring-color auto var(--hd-border-size); } + +.hd-switcher__wrapper { + display: flex; + gap: var(--hd-space-3); + flex-direction: column; +} diff --git a/apps/docs/app/ui/layout/sidebar/Sidebar.tsx b/apps/docs/app/ui/layout/sidebar/Sidebar.tsx index 9887a6192..b955fceea 100644 --- a/apps/docs/app/ui/layout/sidebar/Sidebar.tsx +++ b/apps/docs/app/ui/layout/sidebar/Sidebar.tsx @@ -4,7 +4,7 @@ import { FeatureFlagContext } from "@/context/feature/FeatureFlagProvider.tsx"; import clsx from "clsx"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { useContext, useEffect, useRef } from "react"; +import { useContext, useEffect, useRef, useState } from "react"; import { useSidebar } from "@/context/sidebar/SidebarProvider"; @@ -12,6 +12,8 @@ import Overlay from "@/components/overlay/Overlay"; import type { Section } from "@/app/lib/getPageLinks"; +import { ThemeContext } from "@/context/theme/ThemeProvider"; +import { HopperProvider, TextField } from "@hopper-ui/components"; import "./sidebar.css"; export interface SidebarProps { @@ -19,6 +21,8 @@ export interface SidebarProps { } const Sidebar = ({ links }: SidebarProps) => { + const { colorMode } = useContext(ThemeContext); + const [filter, setFilter] = useState(""); const sidebarRef = useRef(null); const pathName = usePathname(); const sidebarContext = useSidebar()!; @@ -68,33 +72,45 @@ const Sidebar = ({ links }: SidebarProps) => { } }; - const linkItems = links.map(link => { - return ( -
    -
  • - {link.title} -
      - {link.linkItems - .filter(item => item.status === "ready" || item.status === undefined || (item.status === "alpha" && featureFlags.alpha)).map(item => { - const linkPath = `/${item.path}`; - const isActive = pathName === linkPath; - - return ( -
    • - {item.title} -
    • - ); - })} -
    -
  • -
- ); - }); + const onTextFieldChange = (value: string) => { + setFilter(value); + }; + + const linkItems = links + .filter(link => { + const trimmedFilter = filter.trim().toLowerCase(); + + const hasMatch = (value: string) => value.toLowerCase().includes(trimmedFilter); + + return hasMatch(link.title) || link.linkItems.find(item => hasMatch(item.title)); + }) + .map(link => { + return ( +
    +
  • + {link.title} +
      + {link.linkItems + .filter(item => item.status === "ready" || item.status === undefined || (item.status === "alpha" && featureFlags.alpha)).map(item => { + const linkPath = `/${item.path}`; + const isActive = pathName === linkPath; + + return ( +
    • + {item.title} +
    • + ); + })} +
    +
  • +
+ ); + }); return ( <> @@ -105,6 +121,9 @@ const Sidebar = ({ links }: SidebarProps) => { >
+ + + {linkItems}
diff --git a/apps/docs/app/ui/layout/sidebar/sidebar.css b/apps/docs/app/ui/layout/sidebar/sidebar.css index 886b110a0..feb0c42fe 100644 --- a/apps/docs/app/ui/layout/sidebar/sidebar.css +++ b/apps/docs/app/ui/layout/sidebar/sidebar.css @@ -19,7 +19,6 @@ opacity: 0; } - @media screen and (width >= 48rem) { .hd-sidebar { position: sticky;