dashboard storybook improvements (#4369)

## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR adds mobile viewport options to Storybook stories and updates UI components for mobile viewports.

### Detailed summary
- Added mobile viewport options to Storybook stories
- Updated UI components for mobile viewports in various settings pages and embedded wallets
- Adjusted button sizes and styles for different viewport sizes

> The following files were skipped due to too many changes: `pnpm-lock.yaml`, `apps/dashboard/src/app/team/[team_slug]/(team)/~/settings/general/Sidebar.stories.tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
This commit is contained in:
MananTank
2024-09-03 15:27:39 +00:00
parent ec4d635e1b
commit b6aae7f29f
13 changed files with 201 additions and 125 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ function StoryLayout(props: {
return (
<div>
<div className="flex justify-end p-4 border-b mb-5 gap-2">
<div className="flex justify-end p-4 border-b gap-2">
<Button
onClick={() => setTheme("dark")}
size="sm"
+1
View File
@@ -123,6 +123,7 @@
"@storybook/addon-interactions": "^8.2.9",
"@storybook/addon-links": "^8.2.9",
"@storybook/addon-onboarding": "^8.2.9",
"@storybook/addon-viewport": "^8.2.9",
"@storybook/blocks": "^8.2.9",
"@storybook/nextjs": "^8.2.9",
"@storybook/react": "^8.2.9",
@@ -3,42 +3,36 @@ import { ThirdwebProvider } from "thirdweb/react";
import type { Project } from "../../../../@/api/projects";
import type { Team } from "../../../../@/api/team";
import { Button } from "../../../../@/components/ui/button";
import { Separator } from "../../../../@/components/ui/separator";
import { BadgeContainer } from "../../../../stories/utils";
import { BadgeContainer, mobileViewport } from "../../../../stories/utils";
import { TeamHeaderDesktopUI, TeamHeaderMobileUI } from "./TeamHeaderUI";
const meta = {
title: "Team/Team selector",
component: Story,
component: Variants,
parameters: {
nextjs: {
appDirectory: true,
},
},
} satisfies Meta<typeof Story>;
} satisfies Meta<typeof Variants>;
export default meta;
type Story = StoryObj<typeof meta>;
export const AllVariants: Story = {
args: {},
export const Desktop: Story = {
args: {
type: "desktop",
},
};
function Story() {
return (
<div className="dark:bg-zinc-900 bg-zinc-300 p-6">
<h2 className="text-3xl mb-6 font-semibold tracking-tight">Desktop</h2>
<Variants type="desktop" />
<Separator className="my-10" />
<h2 className="mt-10 mb-6 text-3xl font-semibold tracking-tight">
Mobile
</h2>
<div className="w-[400px]">
<Variants type="mobile" />
</div>
</div>
);
}
export const Mobile: Story = {
args: {
type: "mobile",
},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
function Variants(props: {
type: "mobile" | "desktop";
@@ -48,7 +42,9 @@ function Variants(props: {
return (
<ThirdwebProvider>
<div className={"flex flex-col gap-6"}>
<div
className={"flex flex-col gap-6 bg-gray-700 px-4 py-10 min-h-screen"}
>
<BadgeContainer label="Team, Free">
<Comp
teamsAndProjects={teamsAndProjects}
@@ -1,5 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react";
import { BadgeContainer } from "../../../../../../../stories/utils";
import {
BadgeContainer,
mobileViewport,
} from "../../../../../../../stories/utils";
import { DangerSettingCard } from "./DangerSettingCard";
const meta = {
@@ -15,13 +18,20 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const AllVariants: Story = {
export const Desktop: Story = {
args: {},
};
export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
function Story() {
return (
<div className="min-h-screen bg-background text-foreground">
<div className="min-h-screen bg-background text-foreground py-4">
<div className="lg:p-10 container max-w-[1000px] flex flex-col gap-8">
<BadgeContainer label="Base">
<DangerSettingCard
@@ -1,6 +1,7 @@
import type { Team } from "@/api/team";
import { Toaster } from "@/components/ui/sonner";
import type { Meta, StoryObj } from "@storybook/react";
import { mobileViewport } from "../../../../../../../stories/utils";
import SettingsLayout from "../layout";
import {
DeleteTeamCard,
@@ -21,10 +22,17 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const AllVariants: Story = {
export const Desktop: Story = {
args: {},
};
export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
const testTeam: Team = {
id: "team-id-foo-bar",
name: "Team XYZ",
@@ -1,5 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react";
import { BadgeContainer } from "../../../../../../../stories/utils";
import {
BadgeContainer,
mobileViewport,
} from "../../../../../../../stories/utils";
import { SettingsCard } from "./SettingsCard";
const meta = {
@@ -15,13 +18,20 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const AllVariants: Story = {
export const Desktop: Story = {
args: {},
};
export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
function Story() {
return (
<div className="min-h-screen bg-background text-foreground">
<div className="min-h-screen bg-background text-foreground py-6">
<div className="lg:p-10 container max-w-[1100px] flex flex-col gap-10">
<BadgeContainer label="No Header">
<SettingsCard
@@ -1,6 +1,8 @@
import type { Meta, StoryObj } from "@storybook/react";
import { Badge } from "../../../../../../../@/components/ui/badge";
import { cn } from "../../../../../../../@/lib/utils";
import {
BadgeContainer,
mobileViewport,
} from "../../../../../../../stories/utils";
import { TeamSettingsSidebar } from "../_components/sidebar/TeamSettingsSidebar";
import { TeamSettingsMobileNav } from "../_components/sidebar/TeamsMobileNav";
@@ -17,83 +19,57 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const AllVariants: Story = {
export const Desktop: Story = {
args: {
theme: "dark",
type: "desktop",
},
};
function Story() {
return (
<div className={"min-h-screen bg-zinc-800 text-foreground"}>
<div className="lg:p-10 container max-w-[1100px]">
<div className="grid gap-8 grid-cols-2">
<HighlightContainer title="Desktop">
<TeamSettingsSidebar teamSlug="foo" />
</HighlightContainer>
export const Mobile: Story = {
args: {
type: "mobile",
},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
<div>
<HighlightContainer
className="max-w-[400px]"
title="Mobile - full nav"
>
<TeamSettingsMobileNav
activeLink={{
href: "/team/foo/settings",
name: "Foo",
}}
teamSlug="foo"
setShowFull={() => {}}
showFull={true}
/>
</HighlightContainer>
<HighlightContainer
className="max-w-[400px]"
title="Mobile - mini - General Page"
>
<TeamSettingsMobileNav
activeLink={{
href: "/team/foo/settings",
name: "General",
}}
teamSlug="foo"
setShowFull={() => {}}
showFull={false}
/>
</HighlightContainer>
<HighlightContainer title="Mobile - mini - Billing page">
<TeamSettingsMobileNav
activeLink={{
href: "/team/foo/billing",
name: "Billing",
}}
teamSlug="foo"
setShowFull={() => {}}
showFull={false}
/>
</HighlightContainer>
</div>
</div>
</div>
</div>
);
}
function HighlightContainer(props: {
children: React.ReactNode;
className?: string;
title: string;
function Story(props: {
type: "mobile" | "desktop";
}) {
return (
<div>
<Badge className="mb-2 bg-background"> {props.title} </Badge>
<div
className={cn("p-2 mb-10 rounded-lg bg-background", props.className)}
>
{props.children}
</div>
<div
className={"min-h-screen text-foreground lg:max-w-[1100px] py-6 mx-auto"}
>
{props.type === "desktop" && <TeamSettingsSidebar teamSlug="foo" />}
{props.type === "mobile" && (
<div className="flex flex-col gap-4">
<BadgeContainer label="Mobile - Expanded">
<TeamSettingsMobileNav
activeLink={{
href: "/team/foo/settings",
name: "Foo",
}}
teamSlug="foo"
setShowFull={() => {}}
showFull={true}
/>
</BadgeContainer>
<BadgeContainer label="Mobile - Mini">
<TeamSettingsMobileNav
activeLink={{
href: "/team/foo/billing",
name: "Billing",
}}
teamSlug="foo"
setShowFull={() => {}}
showFull={false}
/>
</BadgeContainer>
</div>
)}
</div>
);
}
@@ -2,7 +2,10 @@ import type { Team } from "@/api/team";
import type { TeamAccountRole, TeamMember } from "@/api/team-members";
import { Toaster } from "@/components/ui/sonner";
import type { Meta, StoryObj } from "@storybook/react";
import { BadgeContainer } from "../../../../../../../stories/utils";
import {
BadgeContainer,
mobileViewport,
} from "../../../../../../../stories/utils";
import SettingsLayout from "../layout";
import { InviteSection } from "./InviteSection";
import { ManageMembersSection } from "./ManageMembersSection";
@@ -21,10 +24,17 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const AllVariants: Story = {
export const Desktop: Story = {
args: {},
};
export const Mobile: Story = {
args: {},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
const freeTeam: Team = {
id: "team-id-foo-bar",
name: "Team XYZ",
@@ -1,5 +1,6 @@
import type { ApiKey, ApiKeyService } from "@3rdweb-sdk/react/hooks/useApi";
import type { Meta, StoryObj } from "@storybook/react";
import { mobileViewport } from "../../../stories/utils";
import { InAppWalletSettingsUI } from "./index";
const meta = {
@@ -27,6 +28,24 @@ export const FreePlan: Story = {
},
};
export const GrowthPlanMobile: Story = {
args: {
canEditAdvancedFeatures: true,
},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
export const FreePlanMobile: Story = {
args: {
canEditAdvancedFeatures: false,
},
parameters: {
viewport: mobileViewport("iphone14"),
},
};
const embeddedWalletService: ApiKeyService = {
id: "embeddedWallets",
name: "embeddedWallets", // important
@@ -56,7 +75,7 @@ function Variants(props: {
canEditAdvancedFeatures: boolean;
}) {
return (
<div className="min-h-screen bg-background p-6 text-foreground max-w-[1140px] mx-auto">
<div className="min-h-screen bg-background px-4 py-6 text-foreground max-w-[1140px] mx-auto">
<div className="flex gap-10 flex-col">
<InAppWalletSettingsUI
canEditAdvancedFeatures={props.canEditAdvancedFeatures}
@@ -23,7 +23,7 @@ export const AllVariants: Story = {
function Variants() {
return (
<div className="bg-background p-7 min-h-screen text-foreground">
<div className="flex flex-col gap-8">
<div className="flex flex-col gap-8 max-w-[500px] mx-auto">
<BadgeContainer label="upgradeRequired">
<GatedSwitch upgradeRequired />
</BadgeContainer>
+46 -13
View File
@@ -1,5 +1,7 @@
import { Button } from "@/components/ui/button";
import type { Meta, StoryObj } from "@storybook/react";
import { StarIcon } from "lucide-react";
import { BadgeContainer } from "./utils";
const meta = {
title: "Shadcn/Buttons",
@@ -12,23 +14,54 @@ const meta = {
export default meta;
type Story = StoryObj<typeof meta>;
export const Variants: Story = {
args: {
theme: "light",
},
export const AllVariants: Story = {
args: {},
};
function Component() {
return (
<div className="min-h-screen bg-background p-6 text-foreground">
<div className="flex gap-6">
<Button> Default </Button>
<Button variant="primary"> Primary </Button>
<Button variant="secondary"> Secondary </Button>
<Button variant="ghost"> Ghost </Button>
<Button variant="outline"> Outline </Button>
<Button variant="destructive"> Destructive </Button>
</div>
<div className="min-h-screen bg-background p-6 text-foregroun flex flex-col gap-6">
<Variants size="default" />
<Variants size="sm" />
<Variants size="icon" />
<Variants size="lg" />
</div>
);
}
function Variants(props: {
size: "default" | "icon" | "sm" | "lg";
}) {
return (
<BadgeContainer label={`Size: ${props.size}`}>
<div className="flex gap-6">
<Button size={props.size}>
{props.size === "icon" ? <StarIcon className="size-4" /> : "Default"}
</Button>
<Button variant="primary" size={props.size}>
{props.size === "icon" ? <StarIcon className="size-4" /> : "Primary"}
</Button>
<Button variant="secondary" size={props.size}>
{props.size === "icon" ? (
<StarIcon className="size-4" />
) : (
"Secondary"
)}
</Button>
<Button variant="ghost" size={props.size}>
{props.size === "icon" ? <StarIcon className="size-4" /> : "Ghost"}
</Button>
<Button variant="outline" size={props.size}>
{props.size === "icon" ? <StarIcon className="size-4" /> : "Outline"}
</Button>
<Button variant="destructive" size={props.size}>
{props.size === "icon" ? (
<StarIcon className="size-4" />
) : (
"Desctructive"
)}
</Button>
</div>
</BadgeContainer>
);
}
+10
View File
@@ -1,3 +1,4 @@
import { INITIAL_VIEWPORTS } from "@storybook/addon-viewport";
import { Badge } from "../@/components/ui/badge";
export function StoryBadge(props: {
@@ -24,3 +25,12 @@ export function BadgeContainer(props: {
</div>
);
}
export function mobileViewport(
key: "iphone14" | "iphone14promax" | "ipad11p" | "ipad12p",
) {
return {
viewports: INITIAL_VIEWPORTS,
defaultViewport: key,
};
}
+9 -6
View File
@@ -136,7 +136,7 @@ importers:
version: 5.5.4
vitest:
specifier: 1.6.0
version: 1.6.0(@types/[email protected])(@vitest/[email protected]([email protected]))([email protected])([email protected])
version: 1.6.0(@types/[email protected])(@vitest/[email protected])([email protected])([email protected])
yalc:
specifier: 1.0.0-pre.53
version: 1.0.0-pre.53
@@ -438,6 +438,9 @@ importers:
'@storybook/addon-onboarding':
specifier: ^8.2.9
version: 8.2.9([email protected])([email protected](@babel/[email protected](@babel/[email protected]))([email protected])([email protected]))
'@storybook/addon-viewport':
specifier: ^8.2.9
version: 8.2.9([email protected](@babel/[email protected](@babel/[email protected]))([email protected])([email protected]))
'@storybook/blocks':
specifier: ^8.2.9
version: 8.2.9([email protected]([email protected]))([email protected])([email protected](@babel/[email protected](@babel/[email protected]))([email protected])([email protected]))
@@ -25451,7 +25454,7 @@ snapshots:
dependencies:
'@codspeed/core': 3.1.0
vite: 5.4.2(@types/[email protected])([email protected])
vitest: 1.6.0(@types/[email protected])(@vitest/[email protected]([email protected]))([email protected])([email protected])
vitest: 1.6.0(@types/[email protected])(@vitest/[email protected])([email protected])([email protected])
transitivePeerDependencies:
- debug
@@ -31877,7 +31880,7 @@ snapshots:
redent: 3.0.0
optionalDependencies:
'@types/bun': 1.0.12
vitest: 1.6.0(@types/[email protected])(@vitest/[email protected]([email protected]))([email protected])([email protected])
vitest: 1.6.0(@types/[email protected])(@vitest/[email protected])([email protected])([email protected])
'@testing-library/[email protected](@types/[email protected])([email protected](@types/[email protected])(@vitest/[email protected])([email protected])([email protected]))':
dependencies:
@@ -32679,7 +32682,7 @@ snapshots:
std-env: 3.7.0
strip-literal: 2.1.0
test-exclude: 6.0.0
vitest: 1.6.0(@types/[email protected])(@vitest/[email protected]([email protected]))([email protected])([email protected])
vitest: 1.6.0(@types/[email protected])(@vitest/[email protected])([email protected])([email protected])
transitivePeerDependencies:
- supports-color
@@ -32714,7 +32717,7 @@ snapshots:
pathe: 1.1.2
picocolors: 1.0.1
sirv: 2.0.4
vitest: 1.6.0(@types/node@22.0.2)(@vitest/[email protected])([email protected])([email protected])
vitest: 1.6.0(@types/node@20.14.9)(@vitest/[email protected])([email protected])([email protected])
'@vitest/[email protected]':
dependencies:
@@ -45969,7 +45972,7 @@ snapshots:
fsevents: 2.3.3
terser: 5.31.0
[email protected](@types/[email protected])(@vitest/[email protected]([email protected]))([email protected])([email protected]):
[email protected](@types/[email protected])(@vitest/[email protected])([email protected])([email protected]):
dependencies:
'@vitest/expect': 1.6.0
'@vitest/runner': 1.6.0