Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 20 additions & 18 deletions components/layout/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,24 +147,26 @@ export function Navbar() {
)}

{/* Mobile nav */}
<nav className="flex items-center gap-1 border-t border-border px-4 py-2 md:hidden">
{NAV_LINKS.map((link) => {
const active = link.href === '/app' ? pathname === '/app' : pathname.startsWith(link.href)
return (
<Link
key={link.href}
href={link.href}
className={cn(
'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',
active
? 'bg-secondary text-foreground'
: 'text-muted-foreground hover:text-foreground',
)}
>
{link.label}
</Link>
)
})}
<nav className="overflow-x-auto border-t border-border px-4 py-2 md:hidden">
<div className="flex items-center gap-1">
{NAV_LINKS.map((link) => {
const active = link.href === '/app' ? pathname === '/app' : pathname.startsWith(link.href)
return (
<Link
key={link.href}
href={link.href}
className={cn(
'rounded-md px-3 py-1.5 text-sm font-medium transition-colors whitespace-nowrap',
active
? 'bg-secondary text-foreground'
: 'text-muted-foreground hover:text-foreground',
)}
>
{link.label}
</Link>
)
})}
</div>
</nav>
</header>
)
Expand Down
2 changes: 1 addition & 1 deletion components/layout/notification-bell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export function NotificationBell() {
role="menu"
aria-label="Notifications"
tabIndex={-1}
className="absolute right-0 top-full z-50 mt-2 w-80 rounded-xl border border-border bg-card shadow-lg focus:outline-none"
className="absolute right-0 top-full z-50 mt-2 w-80 max-w-[calc(100vw-2rem)] rounded-xl border border-border bg-card shadow-lg focus:outline-none"
>
<div className="flex items-center justify-between border-b border-border px-4 py-3">
<h3 className="text-sm font-medium">Notifications</h3>
Expand Down
244 changes: 244 additions & 0 deletions components/ui/progress-bar.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
import type { Meta, StoryObj } from '@storybook/react'
import { ProgressBar } from './progress-bar'

const meta = {
title: 'UI/ProgressBar',
component: ProgressBar,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof ProgressBar>

export default meta
type Story = StoryObj<typeof meta>

/**
* Default progress bar at 50% completion
*/
export const Default: Story = {
args: {
value: 0.5,
},
}

/**
* Progress bar showing 0% completion (empty state)
*/
export const Empty: Story = {
args: {
value: 0,
},
}

/**
* Progress bar showing 25% completion
*/
export const QuarterComplete: Story = {
args: {
value: 0.25,
},
}

/**
* Progress bar showing 50% completion (half-way)
*/
export const HalfComplete: Story = {
args: {
value: 0.5,
},
}

/**
* Progress bar showing 75% completion
*/
export const ThreeQuartersComplete: Story = {
args: {
value: 0.75,
},
}

/**
* Progress bar showing 100% completion (full state)
*/
export const Complete: Story = {
args: {
value: 1,
},
}

/**
* Progress bar with indeterminate shimmer effect
* Useful for operations with unknown duration
*/
export const IndeterminateShimmer: Story = {
args: {
value: 0.5,
indeterminateShimmer: true,
},
}

/**
* Small size variant
*/
export const SmallSize: Story = {
args: {
value: 0.5,
size: 'sm',
},
}

/**
* Default size variant (default)
*/
export const DefaultSize: Story = {
args: {
value: 0.5,
size: 'default',
},
}

/**
* Large size variant
*/
export const LargeSize: Story = {
args: {
value: 0.5,
size: 'lg',
},
}

/**
* Progress bar with a secondary marker (e.g., withdrawn portion)
* Marker shows at 30% while progress is at 50%
*/
export const WithMarker: Story = {
args: {
value: 0.5,
marker: 0.3,
},
}

/**
* Edge case: negative value (should be clamped to 0)
* The component should restrict negative values and display as empty
*/
export const NegativeValue: Story = {
args: {
value: -0.5,
},
}

/**
* Edge case: value exceeding 100% (should be clamped to 1)
* The component should restrict values over 1 and display as full
*/
export const ExceedingValue: Story = {
args: {
value: 1.5,
},
}

/**
* Edge case: marker with negative value (should be clamped to 0)
*/
export const NegativeMarker: Story = {
args: {
value: 0.5,
marker: -0.3,
},
}

/**
* Edge case: marker exceeding 100% (should be clamped to 1)
*/
export const ExceedingMarker: Story = {
args: {
value: 0.5,
marker: 1.5,
},
}

/**
* Small size with indeterminate shimmer
*/
export const SmallWithShimmer: Story = {
args: {
value: 0.5,
size: 'sm',
indeterminateShimmer: true,
},
}

/**
* Large size with indeterminate shimmer
*/
export const LargeWithShimmer: Story = {
args: {
value: 0.5,
size: 'lg',
indeterminateShimmer: true,
},
}

/**
* Custom CSS class example
*/
export const WithCustomClass: Story = {
args: {
value: 0.5,
className: 'w-full max-w-md',
},
}

/**
* Multiple progress bars showing progression
*/
export const ProgressionSequence: Story = {
render: () => (
<div className="space-y-6 w-full max-w-md">
<div>
<p className="text-sm font-medium mb-2">0% - No progress</p>
<ProgressBar value={0} />
</div>
<div>
<p className="text-sm font-medium mb-2">25% - Starting</p>
<ProgressBar value={0.25} />
</div>
<div>
<p className="text-sm font-medium mb-2">50% - Halfway</p>
<ProgressBar value={0.5} />
</div>
<div>
<p className="text-sm font-medium mb-2">75% - Nearly done</p>
<ProgressBar value={0.75} />
</div>
<div>
<p className="text-sm font-medium mb-2">100% - Complete</p>
<ProgressBar value={1} />
</div>
</div>
),
}

/**
* All size variants together
*/
export const AllSizeVariants: Story = {
render: () => (
<div className="space-y-6 w-full max-w-md">
<div>
<p className="text-sm font-medium mb-2">Small</p>
<ProgressBar value={0.6} size="sm" />
</div>
<div>
<p className="text-sm font-medium mb-2">Default</p>
<ProgressBar value={0.6} size="default" />
</div>
<div>
<p className="text-sm font-medium mb-2">Large</p>
<ProgressBar value={0.6} size="lg" />
</div>
</div>
),
}
8 changes: 4 additions & 4 deletions components/webhooks/webhook-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,16 @@ export function WebhookSettings() {
<h2 className="font-medium">Recent deliveries</h2>
<div className="rounded-lg border border-border divide-y divide-border">
{history.slice(0, 20).map((d, i) => (
<div key={i} className="flex items-center justify-between px-4 py-2.5 text-sm">
<div className="flex items-center gap-2">
<div key={i} className="flex flex-wrap items-center justify-between gap-2 px-4 py-2.5 text-sm">
<div className="flex min-w-0 items-center gap-2">
{d.success ? (
<CheckCircle2 className="size-4 text-green-500 shrink-0" />
) : (
<XCircle className="size-4 text-destructive shrink-0" />
)}
<span className="text-muted-foreground">{d.eventType}</span>
<span className="truncate text-muted-foreground">{d.eventType}</span>
</div>
<div className="flex items-center gap-3 text-muted-foreground text-xs">
<div className="flex shrink-0 items-center gap-3 text-muted-foreground text-xs">
{d.statusCode && <span>{d.statusCode}</span>}
<span>{formatTimeAgo(d.deliveredAt)}</span>
</div>
Expand Down