Search

Ctrl + K

BrowserMockup

This document outlines the steps to create BrowserMockup component styled withTailwind CSS and using some npm dependency libraries.

Prerequisites

  • Node.js and npm installed on your machine.
  • Tailwind CSS installed in your project.
  • CVA(class-variance-authority) is a utility for managing CSS class names based on various conditions.
  • clsx is a tiny utility for constructing className strings conditionally.
Step 1: Create BrowserMockup component
1// browser-mockup.component.tsx
2import clsx from "clsx";
3import {
4  AlignJustifyIcon,
5  ArrowLeftIcon,
6  ArrowRightIcon,
7  CircleUserRoundIcon,
8  DownloadIcon,
9  RotateCwIcon,
10  SearchIcon,
11  XIcon,
12} from "lucide-react";
13
14export interface BrowserMockupProps {
15  variant?: "compact" | "full";
16  href: string;
17  title?: string;
18  hasButtonColor?: boolean;
19  children?: React.ReactNode;
20  className?: string;
21  contentClassName?: string;
22}
23
24const BrowserMockup: React.FC<BrowserMockupProps> = ({
25  variant = "compact",
26  href,
27  title = "Website title",
28  hasButtonColor,
29  className,
30  contentClassName,
31  children,
32}) => {
33  return (
34    <div
35      className={clsx(
36        "min-w-96 overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-500",
37        className,
38      )}
39    >
40      <div
41        className={clsx("flex items-stretch bg-neutral-200 dark:bg-neutral-800", {
42          "py-3": variant === "compact",
43          "pt-2": variant === "full",
44        })}
45      >
46        <div
47          className={clsx("flex flex-shrink-0 items-center gap-2 pl-6", {
48            "border-b border-neutral-300 dark:border-neutral-500":
49              variant === "full",
50          })}
51        >
52          <div
53            className={clsx(
54              "h-3 w-3 rounded-full",
55              hasButtonColor ? "bg-red-500" : "bg-neutral-400",
56            )}
57          />
58          <div
59            className={clsx(
60              "h-3 w-3 rounded-full",
61              hasButtonColor ? "bg-yellow-500" : "bg-neutral-400",
62            )}
63          />
64          <div
65            className={clsx(
66              "h-3 w-3 rounded-full",
67              hasButtonColor ? "bg-green-500" : "bg-neutral-400",
68            )}
69          />
70        </div>
71        {variant === "compact" ? (
72          <div className="flex flex-1 justify-center px-8">
73            <div className="flex w-full flex-nowrap items-center rounded-lg bg-neutral-50 px-2 py-1 text-neutral-700 dark:bg-neutral-700">
74              <SearchIcon className="mr-2 h-4 w-4 flex-shrink-0" />
75              <p className="flex-1 overflow-hidden text-ellipsis whitespace-nowrap text-sm text-neutral-500 dark:text-neutral-200">
76                {href}
77              </p>
78            </div>
79          </div>
80        ) : (
81          <>
82            <div className="mt-auto h-3 w-6 translate-x-[1px] bg-neutral-50 dark:bg-neutral-700">
83              <div className="h-full w-full rounded-br-lg border-b border-r border-neutral-300 bg-neutral-200 dark:border-neutral-500 dark:bg-neutral-800" />
84            </div>
85            <div className="flex h-9 w-52 items-center rounded-t-lg border-x border-t border-neutral-300 bg-neutral-50 px-4 dark:border-neutral-500 dark:bg-neutral-700">
86              <div className="relative flex-1 overflow-hidden whitespace-nowrap text-sm text-neutral-500 dark:text-neutral-200">
87                {title}
88                <div className="absolute inset-y-0 right-0 w-10 bg-[linear-gradient(to_right,rgba(255,255,255,0),rgba(255,255,255,1))] dark:bg-[linear-gradient(to_right,rgba(64,64,64,0),rgba(64,64,64,1))]" />
89              </div>
90              <div className="flex h-3 w-3 items-center justify-center rounded-full bg-neutral-400">
91                <XIcon className="h-2.5 w-2.5 text-white" />
92              </div>
93            </div>
94            <div className="mt-auto h-3 flex-1 -translate-x-[1px] bg-neutral-50 dark:bg-neutral-700">
95              <div className="h-full w-full rounded-bl-lg border-b border-l border-neutral-300 bg-neutral-200 dark:border-neutral-500 dark:bg-neutral-800" />
96            </div>
97          </>
98        )}
99      </div>
100      {variant === "full" && (
101        <div className="flex w-full flex-1 flex-shrink-0 flex-grow-0 items-center gap-4 bg-neutral-50 px-4 py-2 dark:bg-neutral-700">
102          <div className="flex flex-shrink-0 gap-2 text-neutral-500 dark:text-neutral-200">
103            <ArrowLeftIcon className="h-4 w-4" />
104            <ArrowRightIcon className="h-4 w-4" />
105            <RotateCwIcon className="h-4 w-4" />
106          </div>
107          <div className="w-full flex-1 overflow-hidden text-ellipsis whitespace-nowrap rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm text-neutral-500 dark:border-neutral-500 dark:bg-neutral-800 dark:text-neutral-200">
108            {href}
109          </div>
110          <div className="flex flex-shrink-0 gap-2 text-neutral-500 dark:text-neutral-200">
111            <DownloadIcon className="h-4 w-4" />
112            <CircleUserRoundIcon className="h-4 w-4" />
113            <AlignJustifyIcon className="h-4 w-4" />
114          </div>
115        </div>
116      )}
117      <div
118        className={clsx(
119          "min-h-32 border-t border-neutral-300 bg-neutral-100 dark:border-neutral-500 dark:bg-neutral-600",
120          contentClassName,
121        )}
122      >
123        {children}
124      </div>
125    </div>
126  );
127};
128
129export default BrowserMockup;
130