diff --git a/src/app/content/ui/icon.json b/src/app/content/ui/icon.json index 718953ab..4479ac05 100644 --- a/src/app/content/ui/icon.json +++ b/src/app/content/ui/icon.json @@ -10,7 +10,6 @@ "Subtle Variants": "import { Icon } from \"@/components/ui/icon\";\nimport { mdiInformationOutline } from \"@mdi/js\";\n\nexport default function SubtleVariantsDemo() {\n return (\n
\n \n \n \n \n \n \n \n \n \n \n \n
\n );\n}", "Filled Variants": "import { Icon } from \"@/components/ui/icon\";\nimport { mdiInformationOutline } from \"@mdi/js\";\n\nexport default function FilledVariantsDemo() {\n return (\n
\n \n \n \n \n \n \n \n \n \n \n \n
\n );\n}", - - "Sitecore Logos": "import { Icon } from \"@/components/ui/icon\";\nimport { iconContentHubOne, iconOrdercloud, iconPersonalize, iconXmCloud } from \"@/app/(registry)/graphics/icons/logo-icons\";\n\nexport default function SitecoreLogosDemo() {\n return (\n
\n \n \n \n \n
\n );\n}" + "Sitecore Logos": "import { Icon } from \"@/components/ui/icon\";\n\nexport default function SitecoreLogosDemo() {\n return (\n
\n \n \n \n \n
\n );\n}" } diff --git a/src/app/content/ui/navigation-menu.json b/src/app/content/ui/navigation-menu.json index 73594404..031484bf 100644 --- a/src/app/content/ui/navigation-menu.json +++ b/src/app/content/ui/navigation-menu.json @@ -1,4 +1,6 @@ { - "Default": "import {\n NavigationMenu,\n NavigationMenuList,\n NavigationMenuItem,\n NavigationMenuTrigger,\n NavigationMenuContent,\n NavigationMenuLink\n} from \"@/components/ui/navigation-menu\";\n\nconst components: { title: string; href: string; description: string }[] = [\n {\n title: \"Alert Dialog\",\n href: \"/docs/primitives/alert-dialog\",\n description:\n \"A modal dialog that interrupts the user with important content and expects a response.\",\n },\n {\n title: \"Hover Card\",\n href: \"/docs/primitives/hover-card\",\n description:\n \"For sighted users to preview content available behind a link.\",\n },\n {\n title: \"Progress\",\n href: \"/docs/primitives/progress\",\n description:\n \"Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.\",\n },\n {\n title: \"Scroll-area\",\n href: \"/docs/primitives/scroll-area\",\n description: \"Visually or semantically separates content.\",\n },\n {\n title: \"Tabs\",\n href: \"/docs/primitives/tabs\",\n description:\n \"A set of layered sections of content—known as tab panels—that are displayed one at a time.\",\n },\n {\n title: \"Tooltip\",\n href: \"/docs/primitives/tooltip\",\n description:\n \"A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.\",\n },\n];\n\nexport default function DefaultDemo() {\n return (\n \n \n \n Getting Started\n \n
    \n \n
    Blok CN
    \n

    \n Beautifully designed components built with Tailwind CSS.\n

    \n \n \n Blok is a Sitecore's product design system: the ui framework and style guide we use to build great apps. It's publicly available, so that anyone can easily build software in the Sitecore product design language.\n \n \n How to install dependencies and structure your app.\n \n \n Styles for headings, paragraphs, lists...etc\n \n
\n
\n
\n\n \n Components\n \n
    \n {components.map((component) => (\n \n {component.description}\n \n ))}\n
\n
\n
\n\n \n \n Documentation\n \n \n
\n
\n );\n}", - "Secondary": "import {\n NavigationMenu,\n NavigationMenuList,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuTrigger,\n NavigationMenuContent\n} from \"@/components/ui/navigation-menu\";\nimport { Icon } from \"@/lib/icon\";\nimport {\n mdiHelpCircleOutline,\n mdiCircleOutline,\n mdiCheckCircleOutline\n} from \"@mdi/js\";\n\nexport default function SecondaryDemo() {\n return (\n
\n \n \n \n \n Documentation\n \n \n\n \n List\n \n
    \n
  • \n \n \n
    Components
    \n
    \n Browse all components in the library.\n
    \n \n
    \n \n \n
    Documentation
    \n
    \n Learn how to use the library.\n
    \n \n
    \n \n \n
    Blog
    \n
    \n Read our latest blog posts.\n
    \n \n
    \n
  • \n
\n
\n
\n\n \n Simple List\n \n
    \n
  • \n \n Components\n \n \n Documentation\n \n \n Blocks\n \n
  • \n
\n
\n
\n\n \n With Icon\n \n
    \n
  • \n \n \n \n Backlog\n \n \n \n \n \n To Do\n \n \n \n \n \n Done\n \n \n
  • \n
\n
\n
\n
\n
\n
\n );\n}" -} \ No newline at end of file + "Default": "import {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n navigationMenuTriggerStyle,\n} from \"@/components/ui/navigation-menu\";\nimport type React from \"react\";\n\nfunction Link({\n href,\n children,\n className,\n ...props\n}: React.AnchorHTMLAttributes & { href: string }) {\n return (\n \n {children}\n \n );\n}\n\nconst components: { title: string; href: string; description: string }[] = [\n {\n title: \"Alert Dialog\",\n href: \"/docs/primitives/alert-dialog\",\n description:\n \"A modal dialog that interrupts the user with important content and expects a response.\",\n },\n {\n title: \"Hover Card\",\n href: \"/docs/primitives/hover-card\",\n description:\n \"For sighted users to preview content available behind a link.\",\n },\n {\n title: \"Progress\",\n href: \"/docs/primitives/progress\",\n description:\n \"Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.\",\n },\n {\n title: \"Scroll-area\",\n href: \"/docs/primitives/scroll-area\",\n description: \"Visually or semantically separates content.\",\n },\n {\n title: \"Tabs\",\n href: \"/docs/primitives/tabs\",\n description:\n \"A set of layered sections of content—known as tab panels—that are displayed one at a time.\",\n },\n {\n title: \"Tooltip\",\n href: \"/docs/primitives/tooltip\",\n description:\n \"A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.\",\n },\n];\n\nfunction ListItem({\n title,\n children,\n href,\n ...props\n}: React.ComponentPropsWithoutRef<\"li\"> & { href: string }) {\n return (\n
  • \n \n \n
    {title}
    \n
    \n {children}\n
    \n \n
    \n
  • \n );\n}\n\nexport default function DefaultDemo() {\n return (\n \n \n \n Getting Started\n \n
      \n \n
      Blok CN
      \n

      \n Beautifully designed components built with Tailwind CSS.\n

      \n \n \n Blok is a Sitecore's product design system: the ui framework and style guide we use to build great apps. It's publicly available, so that anyone can easily build software in the Sitecore product design language.\n \n \n How to install dependencies and structure your app.\n \n \n Styles for headings, paragraphs, lists...etc\n \n
    \n
    \n
    \n\n \n Components\n \n
      \n {components.map((component) => (\n \n {component.description}\n \n ))}\n
    \n
    \n
    \n\n \n \n Documentation\n \n \n
    \n
    \n );\n}", + + "Secondary": "import {\n NavigationMenu,\n NavigationMenuContent,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n NavigationMenuTrigger,\n navigationMenuTriggerStyle,\n} from \"@/components/ui/navigation-menu\";\nimport {\n mdiCheckCircleOutline,\n mdiCircleOutline,\n mdiHelpCircleOutline,\n} from \"@mdi/js\";\nimport { Icon } from \"@/lib/icon\";\nimport type React from \"react\";\n\nfunction Link({\n href,\n children,\n className,\n ...props\n}: React.AnchorHTMLAttributes & { href: string }) {\n return (\n \n {children}\n \n );\n}\n\nexport default function SecondaryDemo() {\n return (\n \n \n \n \n Documentation\n \n \n\n \n List\n \n
      \n
    • \n \n \n
      Components
      \n
      \n Browse all components in the library.\n
      \n \n
      \n \n \n
      Documentation
      \n
      \n Learn how to use the library.\n
      \n \n
      \n \n \n
      Blog
      \n
      \n Read our latest blog posts.\n
      \n \n
      \n
    • \n
    \n
    \n
    \n\n \n Simple List\n \n
      \n
    • \n \n Components\n \n \n Documentation\n \n \n Blocks\n \n
    • \n
    \n
    \n
    \n\n \n With Icon\n \n
      \n
    • \n \n \n \n Backlog\n \n \n \n \n \n To Do\n \n \n \n \n \n Done\n \n \n
    • \n
    \n
    \n
    \n
    \n
    \n );\n}" +} + diff --git a/src/app/content/ui/scroll-area.json b/src/app/content/ui/scroll-area.json index 30bb3cb0..505cbef7 100644 --- a/src/app/content/ui/scroll-area.json +++ b/src/app/content/ui/scroll-area.json @@ -1,5 +1,8 @@ { - "Default": "import { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { Separator } from \"@/components/ui/separator\";\nimport * as React from \"react\";\n\nconst tags = Array.from({ length: 50 }).map(\n (_, i, a) => `v1.2.0-beta.${a.length - i}`\n);\n\nexport default function DefaultDemo() {\n return (\n
    \n \n
    \n

    Tags

    \n {tags.map((tag) => (\n \n
    {tag}
    \n \n
    \n ))}\n
    \n
    \n
    \n );\n}", - "Vertical": "import { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { Separator } from \"@/components/ui/separator\";\nimport * as React from \"react\";\n\nconst tags = Array.from({ length: 50 }).map(\n (_, i, a) => `v1.2.0-beta.${a.length - i}`\n);\n\nexport default function VerticalDemo() {\n return (\n
    \n \n
    \n

    Tags

    \n {tags.map((tag) => (\n \n
    {tag}
    \n \n
    \n ))}\n
    \n
    \n
    \n );\n}", - "Horizontal": "import { ScrollArea, ScrollBar } from \"@/components/ui/scroll-area\";\n\nexport default function HorizontalDemo() {\n return (\n \n
    \n {works.map((artwork) => (\n
    \n
    \n \n
    \n
    \n ))}\n
    \n \n
    \n );\n}" -} \ No newline at end of file + "Default": "import * as React from \"react\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { Separator } from \"@/components/ui/separator\";\n\nconst tags = Array.from({ length: 50 }).map(\n (_, i, a) => `v1.2.0-beta.${a.length - i}`\n);\n\nexport default function DefaultDemo() {\n return (\n
    \n \n
    \n

    Tags

    \n {tags.map((tag) => (\n \n
    {tag}
    \n \n
    \n ))}\n
    \n
    \n
    \n );\n}", + + "Vertical": "import * as React from \"react\";\nimport { ScrollArea } from \"@/components/ui/scroll-area\";\nimport { Separator } from \"@/components/ui/separator\";\n\nconst tags = Array.from({ length: 50 }).map(\n (_, i, a) => `v1.2.0-beta.${a.length - i}`\n);\n\nexport default function VerticalDemo() {\n return (\n
    \n \n
    \n

    Tags

    \n {tags.map((tag) => (\n \n
    {tag}
    \n \n
    \n ))}\n
    \n
    \n
    \n );\n}", + + "Horizontal": "import * as React from \"react\";\nimport { ScrollArea, ScrollBar } from \"@/components/ui/scroll-area\";\n\nconst works = [\n {\n artist: \"Ornella Binni\",\n art: \"https://delivery-sitecore.sitecorecontenthub.cloud/api/public/content/235496330fe148edb446ee62d1d54d56?v=4a57ed46\",\n },\n {\n artist: \"Tom Byrom\",\n art: \"https://delivery-sitecore.sitecorecontenthub.cloud/api/public/content/6712f89819cc43f98ba707b516191919?v=b56e5265\",\n },\n {\n artist: \"Vladimir Malyav\",\n art: \"https://delivery-sitecore.sitecorecontenthub.cloud/api/public/content/0dff752591c943569243ed310d5237ca?v=cca386af\",\n },\n] as const;\n\nexport default function HorizontalDemo() {\n return (\n \n
    \n {works.map((artwork) => (\n
    \n
    \n \n
    \n
    \n ))}\n
    \n \n
    \n );\n}" +} + diff --git a/src/app/demo/[name]/ui/icon.tsx b/src/app/demo/[name]/ui/icon.tsx index 86ad39d4..eb6895eb 100644 --- a/src/app/demo/[name]/ui/icon.tsx +++ b/src/app/demo/[name]/ui/icon.tsx @@ -87,13 +87,13 @@ export const icon = { ), - // "Sitecore Logos": ( - //
    - // - // - // - // - //
    - // ) + "Sitecore Logos": ( +
    + + + + +
    + ) }, }; diff --git a/src/components/ui/icon.tsx b/src/components/ui/icon.tsx index 0a92b1e4..cc598449 100644 --- a/src/components/ui/icon.tsx +++ b/src/components/ui/icon.tsx @@ -1,7 +1,8 @@ +'use client' + import { cn } from "@/lib/utils"; -import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; -import { SVGProps } from "react"; +import { SVGProps, useEffect, useState } from "react"; const iconVariants = cva("inline-flex items-center justify-center", { variants: { @@ -151,6 +152,33 @@ const iconSize = { xxl: "size-11", } as const; +function isUrl(value: string) { + return ( + value.startsWith("http://") || + value.startsWith("https://") || + value.startsWith("data:") || + value.startsWith("blob:") + ); +} + +function extractInlineSvg(svgText: string) { + const parser = new DOMParser(); + const doc = parser.parseFromString(svgText, "image/svg+xml"); + + const svg = doc.querySelector("svg"); + if (!svg) return null; + + // Normalize colors so `currentColor` works + svg.querySelectorAll("[fill]").forEach((el) => { + el.setAttribute("fill", "currentColor"); + }); + + return { + inner: svg.innerHTML, + viewBox: svg.getAttribute("viewBox") ?? "0 0 24 24", + }; +} + type IconsProps = SVGProps & { path: string, title?: string, @@ -169,22 +197,66 @@ function Icon({ fill = "currentColor", ...props }: IconsProps) { + const [svgData, setSvgData] = useState<{ + inner: string; + viewBox: string; + } | null>(null); + + const url = isUrl(path); + + useEffect(() => { + if (!url) return; + + let cancelled = false; + + fetch(path) + .then(async (res) => { + const text = await res.text(); + const extracted = extractInlineSvg(text); + + if (!cancelled) { + setSvgData(extracted); + } + }) + .catch(() => { + if (!cancelled) setSvgData(null); + }); + + return () => { + cancelled = true; + }; + }, [path, url]); + return ( - - - + {!url && ( + + + + )} + + {url && svgData && ( + + )} ) } diff --git a/src/lib/right-sidebar-metadata.ts b/src/lib/right-sidebar-metadata.ts index 3e59c71a..83d18004 100644 --- a/src/lib/right-sidebar-metadata.ts +++ b/src/lib/right-sidebar-metadata.ts @@ -432,7 +432,7 @@ export const rightSidebarMetadata: Record = { { id: "color-schemes", title: "Color Schemes" }, { id: "subtle-variants", title: "Subtle Variants" }, { id: "filled-variants", title: "Filled Variants" }, - // { id: "sitecore-logos", title: "Sitecore Logos" }, + { id: "sitecore-logos", title: "Sitecore Logos" }, ], }, ],