From 16b3366fab458ddd78ccee69269246f7ae7c9c0c Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Wed, 15 Jan 2025 18:41:15 +0000 Subject: [PATCH 1/2] chore: add link component --- site/src/components/Link/Link.stories.tsx | 21 ++++++++++++ site/src/components/Link/Link.tsx | 40 +++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 site/src/components/Link/Link.stories.tsx create mode 100644 site/src/components/Link/Link.tsx diff --git a/site/src/components/Link/Link.stories.tsx b/site/src/components/Link/Link.stories.tsx new file mode 100644 index 0000000000000..7f309950e5753 --- /dev/null +++ b/site/src/components/Link/Link.stories.tsx @@ -0,0 +1,21 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { Link } from "./Link"; + +const meta: Meta = { + title: "components/Link", + component: Link, + args: { + text: "Learn more", + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; + +export const Small: Story = { + args: { + size: "sm", + }, +}; diff --git a/site/src/components/Link/Link.tsx b/site/src/components/Link/Link.tsx new file mode 100644 index 0000000000000..c7346e64dbc61 --- /dev/null +++ b/site/src/components/Link/Link.tsx @@ -0,0 +1,40 @@ +import { type VariantProps, cva } from "class-variance-authority"; +import { SquareArrowOutUpRight } from "lucide-react"; +import { forwardRef } from "react"; +import { cn } from "utils/cn"; + +export const linkVariants = cva( + `relative inline-flex items-center no-underline font-medium text-content-link + after:hover:content-[''] after:hover:absolute after:hover:w-full after:hover:h-[1px] after:hover:bg-current after:hover:bottom-px + focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link + focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary focus-visible:rounded-sm + visited:text-content-link`, + { + variants: { + size: { + lg: "text-sm mb-px", + sm: "text-xs [&_svg]:size-icon-xs [&_svg]:p-px", + }, + }, + defaultVariants: { + size: "lg", + }, + }, +); + +export interface LinkProps + extends React.AnchorHTMLAttributes, + VariantProps { + text: string; +} + +export const Link = forwardRef( + ({ className, text, size, ...props }, ref) => { + return ( + + {text}  + + ); + }, +); From ca9f33743e60b8188e11e074a99e5e4102d0f918 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Wed, 15 Jan 2025 19:29:18 +0000 Subject: [PATCH 2/2] Apply minor style improvements --- site/src/components/Link/Link.stories.tsx | 16 ++++++++++-- site/src/components/Link/Link.tsx | 30 ++++++++++++++--------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/site/src/components/Link/Link.stories.tsx b/site/src/components/Link/Link.stories.tsx index 7f309950e5753..30cd346878877 100644 --- a/site/src/components/Link/Link.stories.tsx +++ b/site/src/components/Link/Link.stories.tsx @@ -5,17 +5,29 @@ const meta: Meta = { title: "components/Link", component: Link, args: { - text: "Learn more", + children: "Learn more", }, }; export default meta; type Story = StoryObj; -export const Default: Story = {}; +export const Large: Story = {}; export const Small: Story = { args: { size: "sm", }, }; + +export const InlineUsage: Story = { + render: () => { + return ( +

+ A workspace is your personal, customized development + environment. It's based on a template that configures your + workspace using Terraform. +

+ ); + }, +}; diff --git a/site/src/components/Link/Link.tsx b/site/src/components/Link/Link.tsx index c7346e64dbc61..e70475899f825 100644 --- a/site/src/components/Link/Link.tsx +++ b/site/src/components/Link/Link.tsx @@ -1,19 +1,20 @@ +import { Slot } from "@radix-ui/react-slot"; import { type VariantProps, cva } from "class-variance-authority"; -import { SquareArrowOutUpRight } from "lucide-react"; +import { SquareArrowOutUpRightIcon } from "lucide-react"; import { forwardRef } from "react"; import { cn } from "utils/cn"; export const linkVariants = cva( - `relative inline-flex items-center no-underline font-medium text-content-link - after:hover:content-[''] after:hover:absolute after:hover:w-full after:hover:h-[1px] after:hover:bg-current after:hover:bottom-px + `relative inline-flex items-center no-underline font-medium text-content-link hover:cursor-pointer + after:hover:content-[''] after:hover:absolute after:hover:left-0 after:hover:w-full after:hover:h-[1px] after:hover:bg-current after:hover:bottom-px focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link focus-visible:ring-offset-2 focus-visible:ring-offset-surface-primary focus-visible:rounded-sm - visited:text-content-link`, + visited:text-content-link pl-[2px]`, //pl-[2px] adjusts the underline spacing to align with the icon on the right. { variants: { size: { - lg: "text-sm mb-px", - sm: "text-xs [&_svg]:size-icon-xs [&_svg]:p-px", + lg: "text-sm gap-[2px] [&_svg]:size-icon-sm [&_svg]:p-[2px] leading-6", + sm: "text-xs gap-1 [&_svg]:size-icon-xs [&_svg]:p-[1px] leading-[18px]", }, }, defaultVariants: { @@ -25,16 +26,21 @@ export const linkVariants = cva( export interface LinkProps extends React.AnchorHTMLAttributes, VariantProps { - text: string; + asChild?: boolean; } export const Link = forwardRef( - ({ className, text, size, ...props }, ref) => { + ({ className, children, size, asChild, ...props }, ref) => { + const Comp = asChild ? Slot : "a"; return ( - - {text}  - + + {children} + ); }, );