From ec52bdf3feb1f584eaca2bb95248534fc4e94013 Mon Sep 17 00:00:00 2001 From: Piyush Gupta <56182734+gupta-piyush19@users.noreply.github.com> Date: Wed, 20 Aug 2025 20:27:43 +0530 Subject: [PATCH] feat: adds stories for logo component (#6448) --- .../modules/auth/components/form-wrapper.tsx | 8 +- apps/web/modules/setup/layout.tsx | 4 +- .../connect-integration/index.test.tsx | 4 +- .../components/connect-integration/index.tsx | 4 +- .../ui/components/formbricks-logo/index.tsx | 197 ----------------- .../modules/ui/components/logo/index.test.tsx | 68 ++++-- apps/web/modules/ui/components/logo/index.tsx | 206 +++++++++++++++++- .../modules/ui/components/logo/stories.tsx | 74 +++++++ 8 files changed, 338 insertions(+), 227 deletions(-) delete mode 100644 apps/web/modules/ui/components/formbricks-logo/index.tsx create mode 100644 apps/web/modules/ui/components/logo/stories.tsx diff --git a/apps/web/modules/auth/components/form-wrapper.tsx b/apps/web/modules/auth/components/form-wrapper.tsx index 0439d8f96d..8b02d84b58 100644 --- a/apps/web/modules/auth/components/form-wrapper.tsx +++ b/apps/web/modules/auth/components/form-wrapper.tsx @@ -10,8 +10,12 @@ export const FormWrapper = ({ children }: FormWrapperProps) => {
- - + +
{children} diff --git a/apps/web/modules/setup/layout.tsx b/apps/web/modules/setup/layout.tsx index 2e4722ec5f..616c37a8d8 100644 --- a/apps/web/modules/setup/layout.tsx +++ b/apps/web/modules/setup/layout.tsx @@ -1,4 +1,4 @@ -import { FormbricksLogo } from "@/modules/ui/components/formbricks-logo"; +import { Logo } from "@/modules/ui/components/logo"; import { Toaster } from "react-hot-toast"; export const SetupLayout = ({ children }: { children: React.ReactNode }) => { @@ -10,7 +10,7 @@ export const SetupLayout = ({ children }: { children: React.ReactNode }) => { style={{ scrollbarGutter: "stable both-edges" }} className="flex max-h-[90vh] w-[40rem] flex-col items-center space-y-4 overflow-auto rounded-lg border bg-white p-12 text-center shadow-md">
- +
{children}
diff --git a/apps/web/modules/ui/components/connect-integration/index.test.tsx b/apps/web/modules/ui/components/connect-integration/index.test.tsx index e5a3edbbad..c063340115 100644 --- a/apps/web/modules/ui/components/connect-integration/index.test.tsx +++ b/apps/web/modules/ui/components/connect-integration/index.test.tsx @@ -41,8 +41,8 @@ vi.mock("next/link", () => ({ ), })); -vi.mock("@/modules/ui/components/formbricks-logo", () => ({ - FormbricksLogo: () =>
FormbricksLogo
, +vi.mock("@/modules/ui/components/logo", () => ({ + Logo: () =>
Logo
, })); vi.mock("@/modules/ui/components/button", () => ({ diff --git a/apps/web/modules/ui/components/connect-integration/index.tsx b/apps/web/modules/ui/components/connect-integration/index.tsx index 984aba3221..67540bcd6d 100644 --- a/apps/web/modules/ui/components/connect-integration/index.tsx +++ b/apps/web/modules/ui/components/connect-integration/index.tsx @@ -1,7 +1,7 @@ "use client"; import { Button } from "@/modules/ui/components/button"; -import { FormbricksLogo } from "@/modules/ui/components/formbricks-logo"; +import { Logo } from "@/modules/ui/components/logo"; import { useTranslate } from "@tolgee/react"; import Image, { StaticImageData } from "next/image"; import Link from "next/link"; @@ -51,7 +51,7 @@ export const ConnectIntegration = ({
- +
logo diff --git a/apps/web/modules/ui/components/formbricks-logo/index.tsx b/apps/web/modules/ui/components/formbricks-logo/index.tsx deleted file mode 100644 index 7b2d66e54c..0000000000 --- a/apps/web/modules/ui/components/formbricks-logo/index.tsx +++ /dev/null @@ -1,197 +0,0 @@ -interface FormbricksLogoProps { - className?: string; -} - -export const FormbricksLogo = ({ className }: FormbricksLogoProps) => { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; diff --git a/apps/web/modules/ui/components/logo/index.test.tsx b/apps/web/modules/ui/components/logo/index.test.tsx index cae4bb4dc2..4adea7f2e8 100644 --- a/apps/web/modules/ui/components/logo/index.test.tsx +++ b/apps/web/modules/ui/components/logo/index.test.tsx @@ -8,33 +8,59 @@ describe("Logo", () => { cleanup(); }); - test("renders correctly", () => { - const { container } = render(); - const svg = container.querySelector("svg"); + describe("default variant", () => { + test("renders default logo correctly", () => { + const { container } = render(); + const svg = container.querySelector("svg"); - expect(svg).toBeInTheDocument(); - expect(svg).toHaveAttribute("viewBox", "0 0 697 150"); - expect(svg).toHaveAttribute("fill", "none"); - expect(svg).toHaveAttribute("xmlns", "http://www.w3.org/2000/svg"); + expect(svg).toBeInTheDocument(); + }); }); - test("accepts and passes through props", () => { - const testClassName = "test-class"; - const { container } = render(); - const svg = container.querySelector("svg"); + describe("image variant", () => { + test("renders image logo correctly", () => { + const { container } = render(); + const svg = container.querySelector("svg"); - expect(svg).toBeInTheDocument(); - expect(svg).toHaveAttribute("class", testClassName); + expect(svg).toBeInTheDocument(); + }); + + test("renders image logo with className correctly", () => { + const testClassName = "test-class"; + const { container } = render(); + const svg = container.querySelector("svg"); + + expect(svg).toBeInTheDocument(); + expect(svg).toHaveAttribute("class", testClassName); + }); }); - test("contains expected svg elements", () => { - const { container } = render(); - const svg = container.querySelector("svg"); + describe("wordmark variant", () => { + test("renders wordmark logo correctly", () => { + const { container } = render(); + const svg = container.querySelector("svg"); - expect(svg?.querySelectorAll("path").length).toBeGreaterThan(0); - expect(svg?.querySelector("line")).toBeInTheDocument(); - expect(svg?.querySelectorAll("mask").length).toBe(2); - expect(svg?.querySelectorAll("filter").length).toBe(3); - expect(svg?.querySelectorAll("linearGradient").length).toBe(6); + expect(svg).toBeInTheDocument(); + }); + + test("renders wordmark logo with className correctly", () => { + const testClassName = "test-class"; + const { container } = render(); + const svg = container.querySelector("svg"); + + expect(svg).toBeInTheDocument(); + expect(svg).toHaveAttribute("class", testClassName); + }); + + test("contains expected svg elements", () => { + const { container } = render(); + const svg = container.querySelector("svg"); + + expect(svg?.querySelectorAll("path").length).toBeGreaterThan(0); + expect(svg?.querySelector("line")).toBeInTheDocument(); + expect(svg?.querySelectorAll("mask").length).toBe(2); + expect(svg?.querySelectorAll("filter").length).toBe(3); + expect(svg?.querySelectorAll("linearGradient").length).toBe(6); + }); }); }); diff --git a/apps/web/modules/ui/components/logo/index.tsx b/apps/web/modules/ui/components/logo/index.tsx index 1993736f91..03d2767b78 100644 --- a/apps/web/modules/ui/components/logo/index.tsx +++ b/apps/web/modules/ui/components/logo/index.tsx @@ -1,4 +1,208 @@ -export const Logo = (props: any) => { +interface LogoProps extends React.SVGProps { + variant?: "image" | "wordmark"; +} + +export const Logo = ({ variant = "wordmark", ...props }: LogoProps) => { + if (variant === "image") return ; + + return ; +}; + +const ImageLogo = (props: React.SVGProps) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const WordmarkLogo = (props: React.SVGProps) => { return ( ; + +const meta: Meta = { + title: "UI/Logo", + component: Logo, + tags: ["autodocs"], + parameters: { + layout: "centered", + controls: { sort: "alpha", exclude: [] }, + docs: { + description: { + component: + "** Logo ** renders the Formbricks brand as scalable SVG.It supports two variants('image' and 'wordmark') and is suitable for headers, navigation, and other branding areas.", + }, + }, + }, + argTypes: { + variant: { + control: "select", + options: ["image", "wordmark"], + description: "The variant of the logo to display", + table: { + category: "Appearance", + type: { summary: "string" }, + defaultValue: { summary: "wordmark" }, + }, + order: 1, + }, + className: { + control: "text", + description: "Additional CSS classes for styling", + table: { + category: "Appearance", + type: { summary: "string" }, + }, + order: 1, + }, + }, +}; + +export default meta; +type Story = StoryObj; + +const renderLogoWithOptions = (args: StoryProps) => { + const { ...logoProps } = args; + + return ; +}; + +export const Default: Story = { + render: renderLogoWithOptions, + args: { + className: "h-20", + }, +}; + +export const Image: Story = { + render: renderLogoWithOptions, + args: { + className: "h-20", + variant: "image", + }, +}; + +export const Wordmark: Story = { + render: renderLogoWithOptions, + args: { + className: "h-20", + variant: "wordmark", + }, +};