ui-arreya-components 0.0.16 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +342 -0
- package/dist/index.d.ts +342 -0
- package/dist/index.js +1682 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1495 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +61 -106
- package/.github/workflows/npm-publish.yml +0 -35
- package/.storybook/main.ts +0 -18
- package/.storybook/preview.ts +0 -16
- package/.storybook/vitest.setup.ts +0 -9
- package/README.md +0 -62
- package/components.json +0 -21
- package/dist/styles.css +0 -3
- package/dist/ui.cjs.js +0 -242
- package/dist/ui.es.js +0 -25142
- package/dist/ui.umd.js +0 -242
- package/eslint.config.js +0 -28
- package/postcss.config.js +0 -6
- package/scripts/build-index-ts.sh +0 -16
- package/scripts/template.sh +0 -57
- package/src/components/feature/graph-card.stories.tsx +0 -138
- package/src/components/feature/graph-card.tsx +0 -113
- package/src/components/feature/header.stories.tsx +0 -129
- package/src/components/feature/header.tsx +0 -78
- package/src/components/feature/login-form.stories.tsx +0 -35
- package/src/components/feature/login-form.tsx +0 -97
- package/src/components/feature/search-bar.stories.tsx +0 -35
- package/src/components/feature/search-bar.tsx +0 -141
- package/src/components/feature/wizard.stories.tsx +0 -199
- package/src/components/feature/wizard.tsx +0 -278
- package/src/components/ui/accordion.stories.tsx.disabled +0 -36
- package/src/components/ui/accordion.tsx +0 -55
- package/src/components/ui/alert-dialog.stories.tsx +0 -46
- package/src/components/ui/alert-dialog.tsx +0 -139
- package/src/components/ui/alert.stories.tsx +0 -45
- package/src/components/ui/alert.tsx +0 -59
- package/src/components/ui/aspect-ratio.stories.tsx +0 -24
- package/src/components/ui/aspect-ratio.tsx +0 -5
- package/src/components/ui/avatar.stories.tsx +0 -29
- package/src/components/ui/avatar.tsx +0 -48
- package/src/components/ui/badge.stories.tsx +0 -43
- package/src/components/ui/badge.tsx +0 -36
- package/src/components/ui/breadcrumb.stories.tsx +0 -146
- package/src/components/ui/breadcrumb.tsx +0 -115
- package/src/components/ui/button.stories.tsx +0 -87
- package/src/components/ui/button.tsx +0 -57
- package/src/components/ui/card.stories.tsx +0 -99
- package/src/components/ui/card.tsx +0 -76
- package/src/components/ui/carousel.stories.tsx +0 -47
- package/src/components/ui/carousel.tsx +0 -260
- package/src/components/ui/chart.stories.tsx.disabled +0 -44
- package/src/components/ui/chart.tsx +0 -363
- package/src/components/ui/checkbox.stories.tsx +0 -56
- package/src/components/ui/checkbox.tsx +0 -28
- package/src/components/ui/collapsible.stories.tsx +0 -58
- package/src/components/ui/collapsible.tsx +0 -9
- package/src/components/ui/context-menu.stories.tsx +0 -34
- package/src/components/ui/context-menu.tsx +0 -198
- package/src/components/ui/dialog.stories.tsx +0 -40
- package/src/components/ui/dialog.tsx +0 -120
- package/src/components/ui/drawer.stories.tsx +0 -48
- package/src/components/ui/drawer.tsx +0 -116
- package/src/components/ui/dropdown-menu.stories.tsx +0 -92
- package/src/components/ui/dropdown-menu.tsx +0 -199
- package/src/components/ui/form.tsx +0 -176
- package/src/components/ui/hover-card.stories.tsx +0 -31
- package/src/components/ui/hover-card.tsx +0 -27
- package/src/components/ui/input-otp.tsx +0 -69
- package/src/components/ui/input.stories.tsx +0 -63
- package/src/components/ui/input.tsx +0 -22
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/menubar.tsx +0 -254
- package/src/components/ui/navigation-menu.tsx +0 -128
- package/src/components/ui/pagination.tsx +0 -117
- package/src/components/ui/popover.tsx +0 -31
- package/src/components/ui/progress.tsx +0 -26
- package/src/components/ui/radio-group.tsx +0 -42
- package/src/components/ui/resizable.tsx +0 -43
- package/src/components/ui/scroll-area.tsx +0 -46
- package/src/components/ui/select.tsx +0 -157
- package/src/components/ui/separator.tsx +0 -29
- package/src/components/ui/sheet.tsx +0 -138
- package/src/components/ui/sidebar.tsx +0 -771
- package/src/components/ui/skeleton.tsx +0 -15
- package/src/components/ui/slider.tsx +0 -26
- package/src/components/ui/sonner.tsx +0 -29
- package/src/components/ui/switch.tsx +0 -27
- package/src/components/ui/table.tsx +0 -120
- package/src/components/ui/tabs.tsx +0 -53
- package/src/components/ui/textarea.tsx +0 -22
- package/src/components/ui/toast.tsx +0 -127
- package/src/components/ui/toaster.tsx +0 -33
- package/src/components/ui/toggle-group.tsx +0 -59
- package/src/components/ui/toggle.tsx +0 -43
- package/src/components/ui/tooltip.tsx +0 -30
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/hooks/use-toast.ts +0 -194
- package/src/index.css +0 -3633
- package/src/index.ts +0 -51
- package/src/lib/types.ts +0 -5
- package/src/lib/utils.ts +0 -6
- package/src/styles/tailwind.css +0 -100
- package/tailwind.config.js +0 -94
- package/tsconfig.app.json +0 -30
- package/tsconfig.json +0 -13
- package/tsconfig.node.json +0 -24
- package/vite.config.ts +0 -33
- package/vitest.workspace.ts +0 -32
package/eslint.config.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import js from '@eslint/js'
|
|
2
|
-
import globals from 'globals'
|
|
3
|
-
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
-
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
-
import tseslint from 'typescript-eslint'
|
|
6
|
-
|
|
7
|
-
export default tseslint.config(
|
|
8
|
-
{ ignores: ['dist'] },
|
|
9
|
-
{
|
|
10
|
-
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
-
files: ['**/*.{ts,tsx}'],
|
|
12
|
-
languageOptions: {
|
|
13
|
-
ecmaVersion: 2020,
|
|
14
|
-
globals: globals.browser,
|
|
15
|
-
},
|
|
16
|
-
plugins: {
|
|
17
|
-
'react-hooks': reactHooks,
|
|
18
|
-
'react-refresh': reactRefresh,
|
|
19
|
-
},
|
|
20
|
-
rules: {
|
|
21
|
-
...reactHooks.configs.recommended.rules,
|
|
22
|
-
'react-refresh/only-export-components': [
|
|
23
|
-
'warn',
|
|
24
|
-
{ allowConstantExport: true },
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
)
|
package/postcss.config.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Starting fresh
|
|
4
|
-
rm src/index.ts
|
|
5
|
-
|
|
6
|
-
# Add Components
|
|
7
|
-
for import in `ls src/components/ui/ | grep -v '.stories.' | cut -f1 -d\.`;
|
|
8
|
-
do
|
|
9
|
-
echo 'export * from "./components/ui/'$import'"' >> src/index.ts
|
|
10
|
-
done
|
|
11
|
-
|
|
12
|
-
# Add Features
|
|
13
|
-
for import in `ls src/components/feature/ | grep -v '.stories.' | cut -f1 -d\.`;
|
|
14
|
-
do
|
|
15
|
-
echo 'export * from "./components/feature/'${import}'"' >> src/index.ts
|
|
16
|
-
done
|
package/scripts/template.sh
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# Check if a parameter is passed
|
|
4
|
-
if [ "$#" -ne 2 ]; then
|
|
5
|
-
echo "Usage: $0 <feature|component> <name>"
|
|
6
|
-
exit 1
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
# Determine which template to output based on the parameter
|
|
10
|
-
TEMPLATE_TYPE=$1
|
|
11
|
-
COMPONENT_OR_FEATURE_NAME=$2
|
|
12
|
-
|
|
13
|
-
case $TEMPLATE_TYPE in
|
|
14
|
-
feature)
|
|
15
|
-
echo "Creating feature template..."
|
|
16
|
-
mkdir -p src/components/feature/${COMPONENT_OR_FEATURE_NAME}
|
|
17
|
-
|
|
18
|
-
cat <<EOF > src/components/feature/${COMPONENT_OR_FEATURE_NAME}/index.ts
|
|
19
|
-
export * from './${COMPONENT_OR_FEATURE_NAME}'
|
|
20
|
-
EOF
|
|
21
|
-
|
|
22
|
-
cat <<EOF >> src/components/feature/index.ts
|
|
23
|
-
export * from './${COMPONENT_OR_FEATURE_NAME}'
|
|
24
|
-
EOF
|
|
25
|
-
|
|
26
|
-
cat <<EOF >> src/components/index.ts
|
|
27
|
-
export * from './feature/${COMPONENT_OR_FEATURE_NAME}'
|
|
28
|
-
EOF
|
|
29
|
-
|
|
30
|
-
touch src/components/feature/${COMPONENT_OR_FEATURE_NAME}/{${COMPONENT_OR_FEATURE_NAME}.stories.tsx,${COMPONENT_OR_FEATURE_NAME}.tsx}
|
|
31
|
-
;;
|
|
32
|
-
component)
|
|
33
|
-
echo "Creating component template"
|
|
34
|
-
mkdir -p src/components/ui/${COMPONENT_OR_FEATURE_NAME}
|
|
35
|
-
|
|
36
|
-
cat <<EOF > src/components/ui/${COMPONENT_OR_FEATURE_NAME}/index.ts
|
|
37
|
-
export * from './${COMPONENT_OR_FEATURE_NAME}'
|
|
38
|
-
EOF
|
|
39
|
-
|
|
40
|
-
cat <<EOF >> src/components/ui/index.ts
|
|
41
|
-
export * from './${COMPONENT_OR_FEATURE_NAME}'
|
|
42
|
-
EOF
|
|
43
|
-
|
|
44
|
-
cat <<EOF >> src/components/index.ts
|
|
45
|
-
export * from './ui/${COMPONENT_OR_FEATURE_NAME}'
|
|
46
|
-
EOF
|
|
47
|
-
|
|
48
|
-
touch src/components/ui/${COMPONENT_OR_FEATURE_NAME}/{${COMPONENT_OR_FEATURE_NAME}.stories.tsx,${COMPONENT_OR_FEATURE_NAME}.tsx}
|
|
49
|
-
;;
|
|
50
|
-
*)
|
|
51
|
-
echo "Invalid option. Usage: $0 <feature|component> <name>"
|
|
52
|
-
exit 1
|
|
53
|
-
|
|
54
|
-
;;
|
|
55
|
-
esac
|
|
56
|
-
|
|
57
|
-
echo "Template created successfully!"
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
-
import { GraphCard } from "./graph-card"
|
|
3
|
-
import { Area, AreaChart, ResponsiveContainer } from "recharts"
|
|
4
|
-
|
|
5
|
-
const meta: Meta<typeof GraphCard> = {
|
|
6
|
-
title: "Feature/GraphCard",
|
|
7
|
-
component: GraphCard,
|
|
8
|
-
parameters: {
|
|
9
|
-
layout: "centered",
|
|
10
|
-
},
|
|
11
|
-
tags: ["autodocs"],
|
|
12
|
-
argTypes: {
|
|
13
|
-
title: {
|
|
14
|
-
control: "text",
|
|
15
|
-
description: "The title of the graph card",
|
|
16
|
-
},
|
|
17
|
-
description: {
|
|
18
|
-
control: "text",
|
|
19
|
-
description: "Optional description text below the title",
|
|
20
|
-
},
|
|
21
|
-
value: {
|
|
22
|
-
control: "text",
|
|
23
|
-
description: "The primary value to display (e.g., total, average)",
|
|
24
|
-
},
|
|
25
|
-
change: {
|
|
26
|
-
control: "number",
|
|
27
|
-
description: "Percentage change to display",
|
|
28
|
-
},
|
|
29
|
-
changeType: {
|
|
30
|
-
control: { type: "select" },
|
|
31
|
-
options: ["increase", "decrease", "neutral"],
|
|
32
|
-
description: "Type of change (affects color and icon)",
|
|
33
|
-
},
|
|
34
|
-
changeLabel: {
|
|
35
|
-
control: "text",
|
|
36
|
-
description: "Label to display after the change value",
|
|
37
|
-
},
|
|
38
|
-
isLoading: {
|
|
39
|
-
control: "boolean",
|
|
40
|
-
description: "Whether to show a loading state",
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default meta
|
|
46
|
-
type Story = StoryObj<typeof GraphCard>
|
|
47
|
-
|
|
48
|
-
// Simple example with minimal data
|
|
49
|
-
export const Simple: Story = {
|
|
50
|
-
args: {
|
|
51
|
-
title: "Monthly Sales",
|
|
52
|
-
description: "Total sales for the current month",
|
|
53
|
-
value: "$12,345",
|
|
54
|
-
chart: (
|
|
55
|
-
<ResponsiveContainer width="100%" height="100%">
|
|
56
|
-
<AreaChart
|
|
57
|
-
data={[
|
|
58
|
-
{ month: "Jan", value: 1000 },
|
|
59
|
-
{ month: "Feb", value: 2000 },
|
|
60
|
-
{ month: "Mar", value: 1500 },
|
|
61
|
-
{ month: "Apr", value: 3000 },
|
|
62
|
-
{ month: "May", value: 2500 },
|
|
63
|
-
{ month: "Jun", value: 4000 },
|
|
64
|
-
]}
|
|
65
|
-
>
|
|
66
|
-
<Area type="monotone" dataKey="value" stroke="hsl(var(--primary))" fill="hsl(var(--primary) / 0.2)" />
|
|
67
|
-
</AreaChart>
|
|
68
|
-
</ResponsiveContainer>
|
|
69
|
-
),
|
|
70
|
-
},
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Example with positive change
|
|
74
|
-
export const PositiveChange: Story = {
|
|
75
|
-
args: {
|
|
76
|
-
title: "Website Traffic",
|
|
77
|
-
description: "Unique visitors per day",
|
|
78
|
-
value: "12,456",
|
|
79
|
-
change: 23.5,
|
|
80
|
-
changeType: "increase",
|
|
81
|
-
changeLabel: "vs last week",
|
|
82
|
-
chart: (
|
|
83
|
-
<ResponsiveContainer width="100%" height="100%">
|
|
84
|
-
<AreaChart
|
|
85
|
-
data={[
|
|
86
|
-
{ day: "Mon", value: 1000 },
|
|
87
|
-
{ day: "Tue", value: 2000 },
|
|
88
|
-
{ day: "Wed", value: 3000 },
|
|
89
|
-
{ day: "Thu", value: 2500 },
|
|
90
|
-
{ day: "Fri", value: 4000 },
|
|
91
|
-
{ day: "Sat", value: 3500 },
|
|
92
|
-
{ day: "Sun", value: 4500 },
|
|
93
|
-
]}
|
|
94
|
-
>
|
|
95
|
-
<Area type="monotone" dataKey="value" stroke="hsl(var(--primary))" fill="hsl(var(--primary) / 0.2)" />
|
|
96
|
-
</AreaChart>
|
|
97
|
-
</ResponsiveContainer>
|
|
98
|
-
),
|
|
99
|
-
},
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Example with negative change
|
|
103
|
-
export const NegativeChange: Story = {
|
|
104
|
-
args: {
|
|
105
|
-
title: "Conversion Rate",
|
|
106
|
-
description: "Percentage of visitors who make a purchase",
|
|
107
|
-
value: "3.2%",
|
|
108
|
-
change: 5.7,
|
|
109
|
-
changeType: "decrease",
|
|
110
|
-
changeLabel: "vs last month",
|
|
111
|
-
chart: (
|
|
112
|
-
<ResponsiveContainer width="100%" height="100%">
|
|
113
|
-
<AreaChart
|
|
114
|
-
data={[
|
|
115
|
-
{ week: "W1", value: 4.5 },
|
|
116
|
-
{ week: "W2", value: 4.2 },
|
|
117
|
-
{ week: "W3", value: 3.8 },
|
|
118
|
-
{ week: "W4", value: 3.5 },
|
|
119
|
-
{ week: "W5", value: 3.2 },
|
|
120
|
-
]}
|
|
121
|
-
>
|
|
122
|
-
<Area type="monotone" dataKey="value" stroke="hsl(var(--destructive))" fill="hsl(var(--destructive) / 0.2)" />
|
|
123
|
-
</AreaChart>
|
|
124
|
-
</ResponsiveContainer>
|
|
125
|
-
),
|
|
126
|
-
},
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Loading state
|
|
130
|
-
export const Loading: Story = {
|
|
131
|
-
args: {
|
|
132
|
-
title: "Revenue",
|
|
133
|
-
description: "Total revenue this quarter",
|
|
134
|
-
value: "$143,245",
|
|
135
|
-
isLoading: true,
|
|
136
|
-
chart: <div />, // This won't be shown in loading state
|
|
137
|
-
},
|
|
138
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import type React from "react"
|
|
2
|
-
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
|
3
|
-
import { ChartContainer } from "@/components/ui/chart"
|
|
4
|
-
import { cn } from "@/lib/utils"
|
|
5
|
-
import { ArrowDownIcon, ArrowUpIcon, MoreHorizontal } from "lucide-react"
|
|
6
|
-
import { Button } from "@/components/ui/button"
|
|
7
|
-
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
|
8
|
-
|
|
9
|
-
export interface GraphCardProps {
|
|
10
|
-
title: string
|
|
11
|
-
description?: string
|
|
12
|
-
chart?: React.ReactNode | any
|
|
13
|
-
value?: string | number
|
|
14
|
-
previousValue?: string | number
|
|
15
|
-
change?: number
|
|
16
|
-
changeType?: "increase" | "decrease" | "neutral"
|
|
17
|
-
changeLabel?: string
|
|
18
|
-
className?: string
|
|
19
|
-
footerContent?: React.ReactNode
|
|
20
|
-
menuItems?: Array<{ label: string; onClick: () => void }>
|
|
21
|
-
chartConfig?: Record<string, any>
|
|
22
|
-
isLoading?: boolean
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function GraphCard({
|
|
26
|
-
title,
|
|
27
|
-
description,
|
|
28
|
-
chart,
|
|
29
|
-
value,
|
|
30
|
-
previousValue,
|
|
31
|
-
change,
|
|
32
|
-
changeType,
|
|
33
|
-
changeLabel,
|
|
34
|
-
className,
|
|
35
|
-
footerContent,
|
|
36
|
-
menuItems,
|
|
37
|
-
chartConfig,
|
|
38
|
-
isLoading = false,
|
|
39
|
-
}: GraphCardProps) {
|
|
40
|
-
const renderChangeIndicator = () => {
|
|
41
|
-
if (changeType === "increase") {
|
|
42
|
-
return <ArrowUpIcon className="h-4 w-4 text-emerald-500" />
|
|
43
|
-
} else if (changeType === "decrease") {
|
|
44
|
-
return <ArrowDownIcon className="h-4 w-4 text-red-500" />
|
|
45
|
-
}
|
|
46
|
-
return null
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const getChangeTextColor = () => {
|
|
50
|
-
if (changeType === "increase") return "text-emerald-500"
|
|
51
|
-
if (changeType === "decrease") return "text-red-500"
|
|
52
|
-
return "text-muted-foreground"
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return (
|
|
56
|
-
<Card className={cn("overflow-hidden", className)}>
|
|
57
|
-
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
58
|
-
<div>
|
|
59
|
-
<CardTitle className="text-base font-medium">{title}</CardTitle>
|
|
60
|
-
{description && <CardDescription>{description}</CardDescription>}
|
|
61
|
-
</div>
|
|
62
|
-
{menuItems && menuItems.length > 0 && (
|
|
63
|
-
<DropdownMenu>
|
|
64
|
-
<DropdownMenuTrigger asChild>
|
|
65
|
-
<Button variant="ghost" className="h-8 w-8 p-0">
|
|
66
|
-
<span className="sr-only">Open menu</span>
|
|
67
|
-
<MoreHorizontal className="h-4 w-4" />
|
|
68
|
-
</Button>
|
|
69
|
-
</DropdownMenuTrigger>
|
|
70
|
-
<DropdownMenuContent align="end">
|
|
71
|
-
{menuItems.map((item, index) => (
|
|
72
|
-
<DropdownMenuItem key={index} onClick={item.onClick}>
|
|
73
|
-
{item.label}
|
|
74
|
-
</DropdownMenuItem>
|
|
75
|
-
))}
|
|
76
|
-
</DropdownMenuContent>
|
|
77
|
-
</DropdownMenu>
|
|
78
|
-
)}
|
|
79
|
-
</CardHeader>
|
|
80
|
-
<CardContent className="pb-2">
|
|
81
|
-
{value && (
|
|
82
|
-
<div className="flex items-center justify-between">
|
|
83
|
-
<div className="space-y-1">
|
|
84
|
-
<p className="text-2xl font-bold">{value}</p>
|
|
85
|
-
{(change !== undefined || previousValue) && (
|
|
86
|
-
<div className="flex items-center text-xs">
|
|
87
|
-
{renderChangeIndicator()}
|
|
88
|
-
<span className={cn("ml-1", getChangeTextColor())}>
|
|
89
|
-
{change !== undefined && `${Math.abs(change)}%`}
|
|
90
|
-
{previousValue && !change && `from ${previousValue}`}
|
|
91
|
-
</span>
|
|
92
|
-
{changeLabel && <span className="ml-1 text-muted-foreground">{changeLabel}</span>}
|
|
93
|
-
</div>
|
|
94
|
-
)}
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
)}
|
|
98
|
-
<div className={cn("mt-4", value ? "h-[180px]" : "h-[240px]")}>
|
|
99
|
-
{isLoading ? (
|
|
100
|
-
<div className="flex h-full items-center justify-center">
|
|
101
|
-
<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent"></div>
|
|
102
|
-
</div>
|
|
103
|
-
) : (chartConfig && chart) ? (
|
|
104
|
-
<ChartContainer config={chartConfig}>{ chart }</ChartContainer>
|
|
105
|
-
) : (
|
|
106
|
-
chart
|
|
107
|
-
)}
|
|
108
|
-
</div>
|
|
109
|
-
</CardContent>
|
|
110
|
-
{footerContent && <CardFooter>{footerContent}</CardFooter>}
|
|
111
|
-
</Card>
|
|
112
|
-
)
|
|
113
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react"
|
|
2
|
-
import { Header } from "./header"
|
|
3
|
-
|
|
4
|
-
const meta: Meta<typeof Header> = {
|
|
5
|
-
title: "Feature/Header",
|
|
6
|
-
component: Header,
|
|
7
|
-
parameters: {
|
|
8
|
-
layout: "fullscreen",
|
|
9
|
-
},
|
|
10
|
-
tags: ["autodocs"],
|
|
11
|
-
argTypes: {
|
|
12
|
-
title: {
|
|
13
|
-
control: "text",
|
|
14
|
-
description: "The main title displayed in the header",
|
|
15
|
-
},
|
|
16
|
-
breadcrumbItems: {
|
|
17
|
-
control: "object",
|
|
18
|
-
description: "Array of breadcrumb items to display in the navigation",
|
|
19
|
-
},
|
|
20
|
-
showHomeLink: {
|
|
21
|
-
control: "boolean",
|
|
22
|
-
description: "Whether to show the home link at the start of the breadcrumb",
|
|
23
|
-
},
|
|
24
|
-
className: {
|
|
25
|
-
control: "text",
|
|
26
|
-
description: "Additional CSS classes to apply to the header",
|
|
27
|
-
},
|
|
28
|
-
children: {
|
|
29
|
-
control: { type: undefined },
|
|
30
|
-
description: "Additional content to render within the header",
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export default meta
|
|
36
|
-
type Story = StoryObj<typeof Header>
|
|
37
|
-
|
|
38
|
-
// Basic header with just a title
|
|
39
|
-
export const Basic: Story = {
|
|
40
|
-
args: {
|
|
41
|
-
title: "Dashboard",
|
|
42
|
-
showHomeLink: true,
|
|
43
|
-
breadcrumbItems: [],
|
|
44
|
-
},
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Header with a single breadcrumb (current page)
|
|
48
|
-
export const SingleBreadcrumb: Story = {
|
|
49
|
-
args: {
|
|
50
|
-
title: "Products",
|
|
51
|
-
showHomeLink: true,
|
|
52
|
-
breadcrumbItems: [
|
|
53
|
-
{ label: "Products", isCurrentPage: true },
|
|
54
|
-
],
|
|
55
|
-
},
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Header with multiple breadcrumb levels
|
|
59
|
-
export const MultipleBreadcrumbs: Story = {
|
|
60
|
-
args: {
|
|
61
|
-
title: "Edit Product",
|
|
62
|
-
showHomeLink: true,
|
|
63
|
-
breadcrumbItems: [
|
|
64
|
-
{ label: "Products", href: "/products" },
|
|
65
|
-
{ label: "Electronics", href: "/products/electronics" },
|
|
66
|
-
{ label: "Edit Product", isCurrentPage: true },
|
|
67
|
-
],
|
|
68
|
-
},
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Header without home link
|
|
72
|
-
export const NoHomeLink: Story = {
|
|
73
|
-
args: {
|
|
74
|
-
title: "Settings",
|
|
75
|
-
showHomeLink: false,
|
|
76
|
-
breadcrumbItems: [
|
|
77
|
-
{ label: "Account", href: "/account" },
|
|
78
|
-
{ label: "Settings", isCurrentPage: true },
|
|
79
|
-
],
|
|
80
|
-
},
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Header with custom content
|
|
84
|
-
export const WithCustomContent: Story = {
|
|
85
|
-
args: {
|
|
86
|
-
title: "Dashboard",
|
|
87
|
-
showHomeLink: true,
|
|
88
|
-
breadcrumbItems: [
|
|
89
|
-
{ label: "Dashboard", isCurrentPage: true },
|
|
90
|
-
],
|
|
91
|
-
},
|
|
92
|
-
render: (args) => (
|
|
93
|
-
<Header {...args}>
|
|
94
|
-
<div className="flex justify-between items-center mt-4">
|
|
95
|
-
<p className="text-muted-foreground">Last updated: Yesterday</p>
|
|
96
|
-
<button className="bg-primary text-primary-foreground px-4 py-2 rounded-md text-sm">
|
|
97
|
-
Refresh Data
|
|
98
|
-
</button>
|
|
99
|
-
</div>
|
|
100
|
-
</Header>
|
|
101
|
-
),
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Header with a very long breadcrumb path
|
|
105
|
-
export const LongBreadcrumbPath: Story = {
|
|
106
|
-
args: {
|
|
107
|
-
title: "Edit User Profile",
|
|
108
|
-
showHomeLink: true,
|
|
109
|
-
breadcrumbItems: [
|
|
110
|
-
{ label: "Administration", href: "/admin" },
|
|
111
|
-
{ label: "User Management", href: "/admin/users" },
|
|
112
|
-
{ label: "Enterprise Accounts", href: "/admin/users/enterprise" },
|
|
113
|
-
{ label: "ACME Corporation", href: "/admin/users/enterprise/acme" },
|
|
114
|
-
{ label: "Department Leads", href: "/admin/users/enterprise/acme/leads" },
|
|
115
|
-
{ label: "John Doe", isCurrentPage: true },
|
|
116
|
-
],
|
|
117
|
-
},
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Header with minimal styling
|
|
121
|
-
export const Minimalist: Story = {
|
|
122
|
-
args: {
|
|
123
|
-
title: "Analytics",
|
|
124
|
-
showHomeLink: false,
|
|
125
|
-
breadcrumbItems: [],
|
|
126
|
-
className: "border-0 pb-0",
|
|
127
|
-
},
|
|
128
|
-
}
|
|
129
|
-
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import React from "react"
|
|
2
|
-
import {
|
|
3
|
-
Breadcrumb,
|
|
4
|
-
BreadcrumbItem as BreadcrumbItemComponent,
|
|
5
|
-
BreadcrumbLink,
|
|
6
|
-
BreadcrumbList,
|
|
7
|
-
BreadcrumbPage,
|
|
8
|
-
BreadcrumbSeparator,
|
|
9
|
-
} from "@/components/ui/breadcrumb"
|
|
10
|
-
import { ChevronRight, Home } from "lucide-react"
|
|
11
|
-
|
|
12
|
-
type BreadcrumbItem = {
|
|
13
|
-
label: string
|
|
14
|
-
href?: string
|
|
15
|
-
isCurrentPage?: boolean
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface HeaderProps {
|
|
19
|
-
title?: string
|
|
20
|
-
breadcrumbItems?: BreadcrumbItem[]
|
|
21
|
-
showHomeLink?: boolean
|
|
22
|
-
className?: string
|
|
23
|
-
children?: React.ReactNode
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function Header({ title, breadcrumbItems = [], showHomeLink = true, className = "", children }: HeaderProps) {
|
|
27
|
-
return (
|
|
28
|
-
<header className={`border-b pb-4 ${className}`}>
|
|
29
|
-
<div className="container mx-auto p-4">
|
|
30
|
-
{(breadcrumbItems.length > 0 || showHomeLink) && (
|
|
31
|
-
<Breadcrumb className="mb-2">
|
|
32
|
-
<BreadcrumbList>
|
|
33
|
-
{showHomeLink && (
|
|
34
|
-
<>
|
|
35
|
-
<BreadcrumbItemComponent>
|
|
36
|
-
<BreadcrumbLink href="/" className="flex items-center">
|
|
37
|
-
<Home className="h-3.5 w-3.5 mr-1" />
|
|
38
|
-
Home
|
|
39
|
-
</BreadcrumbLink>
|
|
40
|
-
</BreadcrumbItemComponent>
|
|
41
|
-
{breadcrumbItems.length > 0 && (
|
|
42
|
-
<BreadcrumbSeparator>
|
|
43
|
-
<ChevronRight className="h-3.5 w-3.5" />
|
|
44
|
-
</BreadcrumbSeparator>
|
|
45
|
-
)}
|
|
46
|
-
</>
|
|
47
|
-
)}
|
|
48
|
-
|
|
49
|
-
{breadcrumbItems.map((item, index) => (
|
|
50
|
-
<React.Fragment key={index}>
|
|
51
|
-
<BreadcrumbItemComponent>
|
|
52
|
-
{item.isCurrentPage ? (
|
|
53
|
-
<BreadcrumbPage>{item.label}</BreadcrumbPage>
|
|
54
|
-
) : (
|
|
55
|
-
<BreadcrumbLink href={item.href || "#"}>{item.label}</BreadcrumbLink>
|
|
56
|
-
)}
|
|
57
|
-
</BreadcrumbItemComponent>
|
|
58
|
-
{index < breadcrumbItems.length - 1 && (
|
|
59
|
-
<BreadcrumbSeparator>
|
|
60
|
-
<ChevronRight className="h-3.5 w-3.5" />
|
|
61
|
-
</BreadcrumbSeparator>
|
|
62
|
-
)}
|
|
63
|
-
</React.Fragment>
|
|
64
|
-
))}
|
|
65
|
-
</BreadcrumbList>
|
|
66
|
-
</Breadcrumb>
|
|
67
|
-
)}
|
|
68
|
-
|
|
69
|
-
<div className="flex items-center justify-between">
|
|
70
|
-
{title && <h1 className="text-2xl font-bold tracking-tight">{title}</h1>}
|
|
71
|
-
{children && <div className="flex items-center">{children}</div>}
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
</header>
|
|
75
|
-
)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { Meta, StoryObj } from "@storybook/react"
|
|
2
|
-
|
|
3
|
-
import { GalleryVerticalEnd } from 'lucide-react'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
LoginForm
|
|
7
|
-
} from "./login-form"
|
|
8
|
-
|
|
9
|
-
const meta = {
|
|
10
|
-
title: "Feature/LoginForm",
|
|
11
|
-
component: LoginForm,
|
|
12
|
-
parameters: {
|
|
13
|
-
layout: "centered",
|
|
14
|
-
},
|
|
15
|
-
tags: ["autodocs"],
|
|
16
|
-
} satisfies Meta<typeof LoginForm>
|
|
17
|
-
|
|
18
|
-
export default meta
|
|
19
|
-
type Story = StoryObj<typeof meta>
|
|
20
|
-
|
|
21
|
-
export const Default: Story = {
|
|
22
|
-
render: () => (
|
|
23
|
-
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
|
|
24
|
-
<div className="flex w-full max-w-sm flex-col gap-6">
|
|
25
|
-
<a href="#" className="flex items-center gap-2 self-center font-medium">
|
|
26
|
-
<div className="flex h-6 w-6 items-center justify-center rounded-md bg-primary text-primary-foreground">
|
|
27
|
-
<GalleryVerticalEnd className="size-4" />
|
|
28
|
-
</div>
|
|
29
|
-
Acme Inc.
|
|
30
|
-
</a>
|
|
31
|
-
<LoginForm />
|
|
32
|
-
</div>
|
|
33
|
-
</div>)
|
|
34
|
-
}
|
|
35
|
-
|