shipd 0.1.0
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/LICENSE +21 -0
- package/README.md +205 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1366 -0
- package/docs-template/README.md +255 -0
- package/docs-template/[slug]/[subslug]/page.tsx +1242 -0
- package/docs-template/[slug]/page.tsx +422 -0
- package/docs-template/api/page.tsx +47 -0
- package/docs-template/components/docs/docs-category-page.tsx +162 -0
- package/docs-template/components/docs/docs-code-card.tsx +135 -0
- package/docs-template/components/docs/docs-header.tsx +69 -0
- package/docs-template/components/docs/docs-nav.ts +95 -0
- package/docs-template/components/docs/docs-sidebar.tsx +112 -0
- package/docs-template/components/docs/docs-toc.tsx +38 -0
- package/docs-template/components/ui/badge.tsx +47 -0
- package/docs-template/components/ui/button.tsx +60 -0
- package/docs-template/components/ui/card.tsx +93 -0
- package/docs-template/components/ui/sheet.tsx +140 -0
- package/docs-template/documentation/page.tsx +80 -0
- package/docs-template/layout.tsx +27 -0
- package/docs-template/lib/utils.ts +7 -0
- package/docs-template/page.tsx +360 -0
- package/package.json +66 -0
- package/template/.env.example +45 -0
- package/template/README.md +239 -0
- package/template/app/api/auth/[...all]/route.ts +4 -0
- package/template/app/api/chat/route.ts +16 -0
- package/template/app/api/subscription/route.ts +25 -0
- package/template/app/api/upload-image/route.ts +64 -0
- package/template/app/blog/[slug]/page.tsx +314 -0
- package/template/app/blog/page.tsx +107 -0
- package/template/app/dashboard/_components/chart-interactive.tsx +289 -0
- package/template/app/dashboard/_components/chatbot.tsx +39 -0
- package/template/app/dashboard/_components/mode-toggle.tsx +46 -0
- package/template/app/dashboard/_components/navbar.tsx +84 -0
- package/template/app/dashboard/_components/section-cards.tsx +102 -0
- package/template/app/dashboard/_components/sidebar.tsx +90 -0
- package/template/app/dashboard/_components/subscribe-button.tsx +49 -0
- package/template/app/dashboard/billing/page.tsx +277 -0
- package/template/app/dashboard/chat/page.tsx +73 -0
- package/template/app/dashboard/cli/page.tsx +260 -0
- package/template/app/dashboard/layout.tsx +24 -0
- package/template/app/dashboard/page.tsx +216 -0
- package/template/app/dashboard/payment/_components/manage-subscription.tsx +22 -0
- package/template/app/dashboard/payment/page.tsx +126 -0
- package/template/app/dashboard/settings/page.tsx +613 -0
- package/template/app/dashboard/upload/page.tsx +324 -0
- package/template/app/error.tsx +78 -0
- package/template/app/favicon.ico +0 -0
- package/template/app/globals.css +126 -0
- package/template/app/layout.tsx +135 -0
- package/template/app/not-found.tsx +45 -0
- package/template/app/page.tsx +28 -0
- package/template/app/pricing/_component/pricing-table.tsx +276 -0
- package/template/app/pricing/page.tsx +23 -0
- package/template/app/privacy-policy/page.tsx +280 -0
- package/template/app/robots.txt +12 -0
- package/template/app/sign-in/page.tsx +228 -0
- package/template/app/sign-up/page.tsx +243 -0
- package/template/app/sitemap.ts +62 -0
- package/template/app/success/page.tsx +123 -0
- package/template/app/terms-of-service/page.tsx +212 -0
- package/template/auth-schema.ts +47 -0
- package/template/components/homepage/cli-workflow-section.tsx +138 -0
- package/template/components/homepage/features-section.tsx +150 -0
- package/template/components/homepage/footer.tsx +53 -0
- package/template/components/homepage/hero-section.tsx +112 -0
- package/template/components/homepage/integrations.tsx +124 -0
- package/template/components/homepage/navigation.tsx +116 -0
- package/template/components/homepage/news-section.tsx +82 -0
- package/template/components/homepage/testimonials-section.tsx +34 -0
- package/template/components/logos/BetterAuth.tsx +21 -0
- package/template/components/logos/NeonPostgres.tsx +41 -0
- package/template/components/logos/Nextjs.tsx +72 -0
- package/template/components/logos/Polar.tsx +7 -0
- package/template/components/logos/TailwindCSS.tsx +27 -0
- package/template/components/logos/index.ts +6 -0
- package/template/components/logos/shadcnui.tsx +8 -0
- package/template/components/provider.tsx +8 -0
- package/template/components/ui/avatar.tsx +53 -0
- package/template/components/ui/badge.tsx +46 -0
- package/template/components/ui/button.tsx +59 -0
- package/template/components/ui/card.tsx +92 -0
- package/template/components/ui/chart.tsx +353 -0
- package/template/components/ui/checkbox.tsx +32 -0
- package/template/components/ui/dialog.tsx +135 -0
- package/template/components/ui/dropdown-menu.tsx +257 -0
- package/template/components/ui/form.tsx +167 -0
- package/template/components/ui/input.tsx +21 -0
- package/template/components/ui/label.tsx +24 -0
- package/template/components/ui/progress.tsx +31 -0
- package/template/components/ui/resizable.tsx +56 -0
- package/template/components/ui/select.tsx +185 -0
- package/template/components/ui/separator.tsx +28 -0
- package/template/components/ui/sheet.tsx +139 -0
- package/template/components/ui/skeleton.tsx +13 -0
- package/template/components/ui/sonner.tsx +25 -0
- package/template/components/ui/switch.tsx +31 -0
- package/template/components/ui/tabs.tsx +66 -0
- package/template/components/ui/textarea.tsx +18 -0
- package/template/components/ui/toggle-group.tsx +73 -0
- package/template/components/ui/toggle.tsx +47 -0
- package/template/components/ui/tooltip.tsx +61 -0
- package/template/components/user-profile.tsx +139 -0
- package/template/components.json +21 -0
- package/template/db/drizzle.ts +14 -0
- package/template/db/migrations/0000_worried_rawhide_kid.sql +77 -0
- package/template/db/migrations/meta/0000_snapshot.json +494 -0
- package/template/db/migrations/meta/_journal.json +13 -0
- package/template/db/schema.ts +85 -0
- package/template/drizzle.config.ts +13 -0
- package/template/emails/components/layout.tsx +181 -0
- package/template/emails/password-reset.tsx +67 -0
- package/template/emails/payment-failed.tsx +167 -0
- package/template/emails/subscription-confirmation.tsx +129 -0
- package/template/emails/welcome.tsx +100 -0
- package/template/eslint.config.mjs +16 -0
- package/template/hooks/use-mobile.ts +21 -0
- package/template/lib/auth-client.ts +8 -0
- package/template/lib/auth.ts +276 -0
- package/template/lib/email.ts +118 -0
- package/template/lib/polar-products.ts +49 -0
- package/template/lib/subscription.ts +148 -0
- package/template/lib/upload-image.ts +28 -0
- package/template/lib/utils.ts +6 -0
- package/template/middleware.ts +30 -0
- package/template/next-env.d.ts +5 -0
- package/template/next.config.ts +27 -0
- package/template/package.json +99 -0
- package/template/postcss.config.mjs +5 -0
- package/template/public/add.png +0 -0
- package/template/public/favicon.svg +4 -0
- package/template/public/file.svg +1 -0
- package/template/public/globe.svg +1 -0
- package/template/public/iphone.png +0 -0
- package/template/public/logo.png +0 -0
- package/template/public/next.svg +1 -0
- package/template/public/polar-sh.svg +1 -0
- package/template/public/shadcn-ui.svg +1 -0
- package/template/public/site.webmanifest +21 -0
- package/template/public/vercel.svg +1 -0
- package/template/public/window.svg +1 -0
- package/template/tailwind.config.ts +89 -0
- package/template/template.config.json +138 -0
- package/template/tsconfig.json +27 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
|
|
5
|
+
|
|
6
|
+
import { useIsMobile } from "@/hooks/use-mobile";
|
|
7
|
+
import {
|
|
8
|
+
Card,
|
|
9
|
+
CardAction,
|
|
10
|
+
CardContent,
|
|
11
|
+
CardDescription,
|
|
12
|
+
CardHeader,
|
|
13
|
+
CardTitle,
|
|
14
|
+
} from "@/components/ui/card";
|
|
15
|
+
import {
|
|
16
|
+
ChartConfig,
|
|
17
|
+
ChartContainer,
|
|
18
|
+
ChartTooltip,
|
|
19
|
+
ChartTooltipContent,
|
|
20
|
+
} from "@/components/ui/chart";
|
|
21
|
+
import {
|
|
22
|
+
Select,
|
|
23
|
+
SelectContent,
|
|
24
|
+
SelectItem,
|
|
25
|
+
SelectTrigger,
|
|
26
|
+
SelectValue,
|
|
27
|
+
} from "@/components/ui/select";
|
|
28
|
+
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
|
|
29
|
+
|
|
30
|
+
export const description = "An interactive area chart";
|
|
31
|
+
|
|
32
|
+
const chartData = [
|
|
33
|
+
{ date: "2024-04-01", desktop: 222, mobile: 150 },
|
|
34
|
+
{ date: "2024-04-02", desktop: 97, mobile: 180 },
|
|
35
|
+
{ date: "2024-04-03", desktop: 167, mobile: 120 },
|
|
36
|
+
{ date: "2024-04-04", desktop: 242, mobile: 260 },
|
|
37
|
+
{ date: "2024-04-05", desktop: 373, mobile: 290 },
|
|
38
|
+
{ date: "2024-04-06", desktop: 301, mobile: 340 },
|
|
39
|
+
{ date: "2024-04-07", desktop: 245, mobile: 180 },
|
|
40
|
+
{ date: "2024-04-08", desktop: 409, mobile: 320 },
|
|
41
|
+
{ date: "2024-04-09", desktop: 59, mobile: 110 },
|
|
42
|
+
{ date: "2024-04-10", desktop: 261, mobile: 190 },
|
|
43
|
+
{ date: "2024-04-11", desktop: 327, mobile: 350 },
|
|
44
|
+
{ date: "2024-04-12", desktop: 292, mobile: 210 },
|
|
45
|
+
{ date: "2024-04-13", desktop: 342, mobile: 380 },
|
|
46
|
+
{ date: "2024-04-14", desktop: 137, mobile: 220 },
|
|
47
|
+
{ date: "2024-04-15", desktop: 120, mobile: 170 },
|
|
48
|
+
{ date: "2024-04-16", desktop: 138, mobile: 190 },
|
|
49
|
+
{ date: "2024-04-17", desktop: 446, mobile: 360 },
|
|
50
|
+
{ date: "2024-04-18", desktop: 364, mobile: 410 },
|
|
51
|
+
{ date: "2024-04-19", desktop: 243, mobile: 180 },
|
|
52
|
+
{ date: "2024-04-20", desktop: 89, mobile: 150 },
|
|
53
|
+
{ date: "2024-04-21", desktop: 137, mobile: 200 },
|
|
54
|
+
{ date: "2024-04-22", desktop: 224, mobile: 170 },
|
|
55
|
+
{ date: "2024-04-23", desktop: 138, mobile: 230 },
|
|
56
|
+
{ date: "2024-04-24", desktop: 387, mobile: 290 },
|
|
57
|
+
{ date: "2024-04-25", desktop: 215, mobile: 250 },
|
|
58
|
+
{ date: "2024-04-26", desktop: 75, mobile: 130 },
|
|
59
|
+
{ date: "2024-04-27", desktop: 383, mobile: 420 },
|
|
60
|
+
{ date: "2024-04-28", desktop: 122, mobile: 180 },
|
|
61
|
+
{ date: "2024-04-29", desktop: 315, mobile: 240 },
|
|
62
|
+
{ date: "2024-04-30", desktop: 454, mobile: 380 },
|
|
63
|
+
{ date: "2024-05-01", desktop: 165, mobile: 220 },
|
|
64
|
+
{ date: "2024-05-02", desktop: 293, mobile: 310 },
|
|
65
|
+
{ date: "2024-05-03", desktop: 247, mobile: 190 },
|
|
66
|
+
{ date: "2024-05-04", desktop: 385, mobile: 420 },
|
|
67
|
+
{ date: "2024-05-05", desktop: 481, mobile: 390 },
|
|
68
|
+
{ date: "2024-05-06", desktop: 498, mobile: 520 },
|
|
69
|
+
{ date: "2024-05-07", desktop: 388, mobile: 300 },
|
|
70
|
+
{ date: "2024-05-08", desktop: 149, mobile: 210 },
|
|
71
|
+
{ date: "2024-05-09", desktop: 227, mobile: 180 },
|
|
72
|
+
{ date: "2024-05-10", desktop: 293, mobile: 330 },
|
|
73
|
+
{ date: "2024-05-11", desktop: 335, mobile: 270 },
|
|
74
|
+
{ date: "2024-05-12", desktop: 197, mobile: 240 },
|
|
75
|
+
{ date: "2024-05-13", desktop: 197, mobile: 160 },
|
|
76
|
+
{ date: "2024-05-14", desktop: 448, mobile: 490 },
|
|
77
|
+
{ date: "2024-05-15", desktop: 473, mobile: 380 },
|
|
78
|
+
{ date: "2024-05-16", desktop: 338, mobile: 400 },
|
|
79
|
+
{ date: "2024-05-17", desktop: 499, mobile: 420 },
|
|
80
|
+
{ date: "2024-05-18", desktop: 315, mobile: 350 },
|
|
81
|
+
{ date: "2024-05-19", desktop: 235, mobile: 180 },
|
|
82
|
+
{ date: "2024-05-20", desktop: 177, mobile: 230 },
|
|
83
|
+
{ date: "2024-05-21", desktop: 82, mobile: 140 },
|
|
84
|
+
{ date: "2024-05-22", desktop: 81, mobile: 120 },
|
|
85
|
+
{ date: "2024-05-23", desktop: 252, mobile: 290 },
|
|
86
|
+
{ date: "2024-05-24", desktop: 294, mobile: 220 },
|
|
87
|
+
{ date: "2024-05-25", desktop: 201, mobile: 250 },
|
|
88
|
+
{ date: "2024-05-26", desktop: 213, mobile: 170 },
|
|
89
|
+
{ date: "2024-05-27", desktop: 420, mobile: 460 },
|
|
90
|
+
{ date: "2024-05-28", desktop: 233, mobile: 190 },
|
|
91
|
+
{ date: "2024-05-29", desktop: 78, mobile: 130 },
|
|
92
|
+
{ date: "2024-05-30", desktop: 340, mobile: 280 },
|
|
93
|
+
{ date: "2024-05-31", desktop: 178, mobile: 230 },
|
|
94
|
+
{ date: "2024-06-01", desktop: 178, mobile: 200 },
|
|
95
|
+
{ date: "2024-06-02", desktop: 470, mobile: 410 },
|
|
96
|
+
{ date: "2024-06-03", desktop: 103, mobile: 160 },
|
|
97
|
+
{ date: "2024-06-04", desktop: 439, mobile: 380 },
|
|
98
|
+
{ date: "2024-06-05", desktop: 88, mobile: 140 },
|
|
99
|
+
{ date: "2024-06-06", desktop: 294, mobile: 250 },
|
|
100
|
+
{ date: "2024-06-07", desktop: 323, mobile: 370 },
|
|
101
|
+
{ date: "2024-06-08", desktop: 385, mobile: 320 },
|
|
102
|
+
{ date: "2024-06-09", desktop: 438, mobile: 480 },
|
|
103
|
+
{ date: "2024-06-10", desktop: 155, mobile: 200 },
|
|
104
|
+
{ date: "2024-06-11", desktop: 92, mobile: 150 },
|
|
105
|
+
{ date: "2024-06-12", desktop: 492, mobile: 420 },
|
|
106
|
+
{ date: "2024-06-13", desktop: 81, mobile: 130 },
|
|
107
|
+
{ date: "2024-06-14", desktop: 426, mobile: 380 },
|
|
108
|
+
{ date: "2024-06-15", desktop: 307, mobile: 350 },
|
|
109
|
+
{ date: "2024-06-16", desktop: 371, mobile: 310 },
|
|
110
|
+
{ date: "2024-06-17", desktop: 475, mobile: 520 },
|
|
111
|
+
{ date: "2024-06-18", desktop: 107, mobile: 170 },
|
|
112
|
+
{ date: "2024-06-19", desktop: 341, mobile: 290 },
|
|
113
|
+
{ date: "2024-06-20", desktop: 408, mobile: 450 },
|
|
114
|
+
{ date: "2024-06-21", desktop: 169, mobile: 210 },
|
|
115
|
+
{ date: "2024-06-22", desktop: 317, mobile: 270 },
|
|
116
|
+
{ date: "2024-06-23", desktop: 480, mobile: 530 },
|
|
117
|
+
{ date: "2024-06-24", desktop: 132, mobile: 180 },
|
|
118
|
+
{ date: "2024-06-25", desktop: 141, mobile: 190 },
|
|
119
|
+
{ date: "2024-06-26", desktop: 434, mobile: 380 },
|
|
120
|
+
{ date: "2024-06-27", desktop: 448, mobile: 490 },
|
|
121
|
+
{ date: "2024-06-28", desktop: 149, mobile: 200 },
|
|
122
|
+
{ date: "2024-06-29", desktop: 103, mobile: 160 },
|
|
123
|
+
{ date: "2024-06-30", desktop: 446, mobile: 400 },
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
const chartConfig = {
|
|
127
|
+
visitors: {
|
|
128
|
+
label: "Visitors",
|
|
129
|
+
},
|
|
130
|
+
desktop: {
|
|
131
|
+
label: "Desktop",
|
|
132
|
+
color: "var(--primary)",
|
|
133
|
+
},
|
|
134
|
+
mobile: {
|
|
135
|
+
label: "Mobile",
|
|
136
|
+
color: "var(--primary)",
|
|
137
|
+
},
|
|
138
|
+
} satisfies ChartConfig;
|
|
139
|
+
|
|
140
|
+
export function ChartAreaInteractive() {
|
|
141
|
+
const isMobile = useIsMobile();
|
|
142
|
+
const [timeRange, setTimeRange] = React.useState("90d");
|
|
143
|
+
|
|
144
|
+
React.useEffect(() => {
|
|
145
|
+
if (isMobile) {
|
|
146
|
+
setTimeRange("7d");
|
|
147
|
+
}
|
|
148
|
+
}, [isMobile]);
|
|
149
|
+
|
|
150
|
+
const filteredData = chartData.filter((item) => {
|
|
151
|
+
const date = new Date(item.date);
|
|
152
|
+
const referenceDate = new Date("2024-06-30");
|
|
153
|
+
let daysToSubtract = 90;
|
|
154
|
+
if (timeRange === "30d") {
|
|
155
|
+
daysToSubtract = 30;
|
|
156
|
+
} else if (timeRange === "7d") {
|
|
157
|
+
daysToSubtract = 7;
|
|
158
|
+
}
|
|
159
|
+
const startDate = new Date(referenceDate);
|
|
160
|
+
startDate.setDate(startDate.getDate() - daysToSubtract);
|
|
161
|
+
return date >= startDate;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<Card className="@container/card">
|
|
166
|
+
<CardHeader>
|
|
167
|
+
<CardTitle>Total Visitors</CardTitle>
|
|
168
|
+
<CardDescription>
|
|
169
|
+
<span className="hidden @[540px]/card:block">
|
|
170
|
+
Total for the last 3 months
|
|
171
|
+
</span>
|
|
172
|
+
<span className="@[540px]/card:hidden">Last 3 months</span>
|
|
173
|
+
</CardDescription>
|
|
174
|
+
<CardAction>
|
|
175
|
+
<ToggleGroup
|
|
176
|
+
type="single"
|
|
177
|
+
value={timeRange}
|
|
178
|
+
onValueChange={setTimeRange}
|
|
179
|
+
variant="outline"
|
|
180
|
+
className="hidden *:data-[slot=toggle-group-item]:!px-4 @[767px]/card:flex"
|
|
181
|
+
>
|
|
182
|
+
<ToggleGroupItem value="90d">Last 3 months</ToggleGroupItem>
|
|
183
|
+
<ToggleGroupItem value="30d">Last 30 days</ToggleGroupItem>
|
|
184
|
+
<ToggleGroupItem value="7d">Last 7 days</ToggleGroupItem>
|
|
185
|
+
</ToggleGroup>
|
|
186
|
+
<Select value={timeRange} onValueChange={setTimeRange}>
|
|
187
|
+
<SelectTrigger
|
|
188
|
+
className="flex w-40 **:data-[slot=select-value]:block **:data-[slot=select-value]:truncate @[767px]/card:hidden"
|
|
189
|
+
size="sm"
|
|
190
|
+
aria-label="Select a value"
|
|
191
|
+
>
|
|
192
|
+
<SelectValue placeholder="Last 3 months" />
|
|
193
|
+
</SelectTrigger>
|
|
194
|
+
<SelectContent className="rounded-xl">
|
|
195
|
+
<SelectItem value="90d" className="rounded-lg">
|
|
196
|
+
Last 3 months
|
|
197
|
+
</SelectItem>
|
|
198
|
+
<SelectItem value="30d" className="rounded-lg">
|
|
199
|
+
Last 30 days
|
|
200
|
+
</SelectItem>
|
|
201
|
+
<SelectItem value="7d" className="rounded-lg">
|
|
202
|
+
Last 7 days
|
|
203
|
+
</SelectItem>
|
|
204
|
+
</SelectContent>
|
|
205
|
+
</Select>
|
|
206
|
+
</CardAction>
|
|
207
|
+
</CardHeader>
|
|
208
|
+
<CardContent className="px-2 pt-4 sm:px-6 sm:pt-6">
|
|
209
|
+
<ChartContainer
|
|
210
|
+
config={chartConfig}
|
|
211
|
+
className="aspect-auto h-[250px] w-full"
|
|
212
|
+
>
|
|
213
|
+
<AreaChart data={filteredData}>
|
|
214
|
+
<defs>
|
|
215
|
+
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
|
|
216
|
+
<stop
|
|
217
|
+
offset="5%"
|
|
218
|
+
stopColor="var(--color-desktop)"
|
|
219
|
+
stopOpacity={1.0}
|
|
220
|
+
/>
|
|
221
|
+
<stop
|
|
222
|
+
offset="95%"
|
|
223
|
+
stopColor="var(--color-desktop)"
|
|
224
|
+
stopOpacity={0.1}
|
|
225
|
+
/>
|
|
226
|
+
</linearGradient>
|
|
227
|
+
<linearGradient id="fillMobile" x1="0" y1="0" x2="0" y2="1">
|
|
228
|
+
<stop
|
|
229
|
+
offset="5%"
|
|
230
|
+
stopColor="var(--color-mobile)"
|
|
231
|
+
stopOpacity={0.8}
|
|
232
|
+
/>
|
|
233
|
+
<stop
|
|
234
|
+
offset="95%"
|
|
235
|
+
stopColor="var(--color-mobile)"
|
|
236
|
+
stopOpacity={0.1}
|
|
237
|
+
/>
|
|
238
|
+
</linearGradient>
|
|
239
|
+
</defs>
|
|
240
|
+
<CartesianGrid vertical={false} />
|
|
241
|
+
<XAxis
|
|
242
|
+
dataKey="date"
|
|
243
|
+
tickLine={false}
|
|
244
|
+
axisLine={false}
|
|
245
|
+
tickMargin={8}
|
|
246
|
+
minTickGap={32}
|
|
247
|
+
tickFormatter={(value) => {
|
|
248
|
+
const date = new Date(value);
|
|
249
|
+
return date.toLocaleDateString("en-US", {
|
|
250
|
+
month: "short",
|
|
251
|
+
day: "numeric",
|
|
252
|
+
});
|
|
253
|
+
}}
|
|
254
|
+
/>
|
|
255
|
+
<ChartTooltip
|
|
256
|
+
cursor={false}
|
|
257
|
+
defaultIndex={isMobile ? -1 : 10}
|
|
258
|
+
content={
|
|
259
|
+
<ChartTooltipContent
|
|
260
|
+
labelFormatter={(value) => {
|
|
261
|
+
return new Date(value).toLocaleDateString("en-US", {
|
|
262
|
+
month: "short",
|
|
263
|
+
day: "numeric",
|
|
264
|
+
});
|
|
265
|
+
}}
|
|
266
|
+
indicator="dot"
|
|
267
|
+
/>
|
|
268
|
+
}
|
|
269
|
+
/>
|
|
270
|
+
<Area
|
|
271
|
+
dataKey="mobile"
|
|
272
|
+
type="natural"
|
|
273
|
+
fill="url(#fillMobile)"
|
|
274
|
+
stroke="var(--color-mobile)"
|
|
275
|
+
stackId="a"
|
|
276
|
+
/>
|
|
277
|
+
<Area
|
|
278
|
+
dataKey="desktop"
|
|
279
|
+
type="natural"
|
|
280
|
+
fill="url(#fillDesktop)"
|
|
281
|
+
stroke="var(--color-desktop)"
|
|
282
|
+
stackId="a"
|
|
283
|
+
/>
|
|
284
|
+
</AreaChart>
|
|
285
|
+
</ChartContainer>
|
|
286
|
+
</CardContent>
|
|
287
|
+
</Card>
|
|
288
|
+
);
|
|
289
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Input } from "@/components/ui/input";
|
|
3
|
+
import { Bot, X } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
|
|
6
|
+
export default function Chatbot() {
|
|
7
|
+
const [open, setOpen] = useState(false);
|
|
8
|
+
return (
|
|
9
|
+
<div className="absolute bottom-4 right-4 z-[99]">
|
|
10
|
+
<div
|
|
11
|
+
className="rounded-full bg-black/10 cursor-pointer border p-3"
|
|
12
|
+
onClick={() => setOpen(!open)}
|
|
13
|
+
>
|
|
14
|
+
<Bot className="w-4 h-4 transition-transform hover:scale-125 hover:rotate-12 duration-300 ease-in-out" />
|
|
15
|
+
</div>
|
|
16
|
+
{open && (
|
|
17
|
+
<div className="absolute bottom-12 right-4 w-80 z-[99] dark:bg-black bg-white">
|
|
18
|
+
<div className="flex flex-col items-start justify-between gap-3 rounded-lg border h-96 shadow-lg p-4">
|
|
19
|
+
<div className="w-full">
|
|
20
|
+
<div className="flex items-center justify-between">
|
|
21
|
+
<h3 className="text-lg font-semibold">Nextjs Starter Kit</h3>
|
|
22
|
+
<X
|
|
23
|
+
className="w-4 h-4 hover:cursor-pointer"
|
|
24
|
+
onClick={() => setOpen(false)}
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
<p className="text-sm text-muted-foreground mt-1 mb-4">
|
|
28
|
+
Ask me anything about Nextjs Starter Kit
|
|
29
|
+
</p>
|
|
30
|
+
</div>
|
|
31
|
+
<div className="flex items-end justify-center gap-2 w-full">
|
|
32
|
+
<Input className="w-full" placeholder="Ask me anything" />
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
import { Moon, Sun } from "lucide-react";
|
|
5
|
+
import { useTheme } from "next-themes";
|
|
6
|
+
|
|
7
|
+
import { Button } from "@/components/ui/button";
|
|
8
|
+
|
|
9
|
+
export default function ModeToggle() {
|
|
10
|
+
const { theme, setTheme } = useTheme();
|
|
11
|
+
const [mounted, setMounted] = useState(false);
|
|
12
|
+
|
|
13
|
+
// After mounting, we have access to the theme
|
|
14
|
+
useEffect(() => setMounted(true), []);
|
|
15
|
+
|
|
16
|
+
if (!mounted) {
|
|
17
|
+
// Render nothing on the server and until the theme is mounted
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div>
|
|
23
|
+
{theme === "dark" ? (
|
|
24
|
+
<Button
|
|
25
|
+
variant="ghost"
|
|
26
|
+
className="hover:bg-[#ff5722]/10 hover:text-[#ff5722]"
|
|
27
|
+
size="icon"
|
|
28
|
+
onClick={() => setTheme("light")}
|
|
29
|
+
>
|
|
30
|
+
<Sun className="w-5 h-5" />
|
|
31
|
+
<span className="sr-only">Switch to light mode</span>
|
|
32
|
+
</Button>
|
|
33
|
+
) : (
|
|
34
|
+
<Button
|
|
35
|
+
variant="ghost"
|
|
36
|
+
size="icon"
|
|
37
|
+
className="hover:bg-[#ff5722]/10 hover:text-[#ff5722]"
|
|
38
|
+
onClick={() => setTheme("dark")}
|
|
39
|
+
>
|
|
40
|
+
<Moon className="w-5 h-5" />
|
|
41
|
+
<span className="sr-only">Switch to dark mode</span>
|
|
42
|
+
</Button>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { Dialog, DialogClose } from "@/components/ui/dialog";
|
|
5
|
+
import { Separator } from "@/components/ui/separator";
|
|
6
|
+
import {
|
|
7
|
+
SheetContent,
|
|
8
|
+
SheetHeader,
|
|
9
|
+
SheetTitle,
|
|
10
|
+
SheetTrigger,
|
|
11
|
+
} from "@/components/ui/sheet";
|
|
12
|
+
import UserProfile from "@/components/user-profile";
|
|
13
|
+
import {
|
|
14
|
+
CreditCard,
|
|
15
|
+
HomeIcon,
|
|
16
|
+
Settings,
|
|
17
|
+
Terminal,
|
|
18
|
+
} from "lucide-react";
|
|
19
|
+
import Link from "next/link";
|
|
20
|
+
import { ReactNode } from "react";
|
|
21
|
+
import ModeToggle from "./mode-toggle";
|
|
22
|
+
|
|
23
|
+
export default function DashboardTopNav({ children }: { children: ReactNode }) {
|
|
24
|
+
return (
|
|
25
|
+
<div className="flex flex-col">
|
|
26
|
+
<header className="flex h-14 lg:h-[52px] items-center gap-4 border-b px-3">
|
|
27
|
+
<Dialog>
|
|
28
|
+
<SheetTrigger className="min-[1024px]:hidden p-2 transition">
|
|
29
|
+
<Link prefetch={true} href="/dashboard">
|
|
30
|
+
<span className="sr-only">Home</span>
|
|
31
|
+
</Link>
|
|
32
|
+
</SheetTrigger>
|
|
33
|
+
<SheetContent side="left">
|
|
34
|
+
<SheetHeader>
|
|
35
|
+
<Link prefetch={true} href="/">
|
|
36
|
+
<SheetTitle>SaaS Scaffold</SheetTitle>
|
|
37
|
+
</Link>
|
|
38
|
+
</SheetHeader>
|
|
39
|
+
<div className="flex flex-col space-y-3 mt-[1rem]">
|
|
40
|
+
<DialogClose asChild>
|
|
41
|
+
<Link prefetch={true} href="/dashboard">
|
|
42
|
+
<Button variant="outline" className="w-full">
|
|
43
|
+
<HomeIcon className="mr-2 h-4 w-4" />
|
|
44
|
+
Overview
|
|
45
|
+
</Button>
|
|
46
|
+
</Link>
|
|
47
|
+
</DialogClose>
|
|
48
|
+
<DialogClose asChild>
|
|
49
|
+
<Link prefetch={true} href="/dashboard/cli">
|
|
50
|
+
<Button variant="outline" className="w-full">
|
|
51
|
+
<Terminal className="mr-2 h-4 w-4" />
|
|
52
|
+
CLI Access
|
|
53
|
+
</Button>
|
|
54
|
+
</Link>
|
|
55
|
+
</DialogClose>
|
|
56
|
+
<DialogClose asChild>
|
|
57
|
+
<Link prefetch={true} href="/dashboard/billing">
|
|
58
|
+
<Button variant="outline" className="w-full">
|
|
59
|
+
<CreditCard className="mr-2 h-4 w-4" />
|
|
60
|
+
Billing
|
|
61
|
+
</Button>
|
|
62
|
+
</Link>
|
|
63
|
+
</DialogClose>
|
|
64
|
+
<Separator className="my-3" />
|
|
65
|
+
<DialogClose asChild>
|
|
66
|
+
<Link prefetch={true} href="/dashboard/settings">
|
|
67
|
+
<Button variant="outline" className="w-full">
|
|
68
|
+
<Settings className="mr-2 h-4 w-4" />
|
|
69
|
+
Settings
|
|
70
|
+
</Button>
|
|
71
|
+
</Link>
|
|
72
|
+
</DialogClose>
|
|
73
|
+
</div>
|
|
74
|
+
</SheetContent>
|
|
75
|
+
</Dialog>
|
|
76
|
+
<div className="flex justify-center items-center gap-2 ml-auto">
|
|
77
|
+
<ModeToggle />
|
|
78
|
+
<UserProfile mini={true} />
|
|
79
|
+
</div>
|
|
80
|
+
</header>
|
|
81
|
+
{children}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { IconTrendingUp } from "@tabler/icons-react";
|
|
2
|
+
|
|
3
|
+
import { Badge } from "@/components/ui/badge";
|
|
4
|
+
import {
|
|
5
|
+
Card,
|
|
6
|
+
CardAction,
|
|
7
|
+
CardDescription,
|
|
8
|
+
CardFooter,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from "@/components/ui/card";
|
|
12
|
+
|
|
13
|
+
export function SectionCards() {
|
|
14
|
+
return (
|
|
15
|
+
<div className="*:data-[slot=card]:from-primary/5 *:data-[slot=card]:to-card dark:*:data-[slot=card]:bg-card grid grid-cols-1 gap-4 *:data-[slot=card]:bg-gradient-to-t *:data-[slot=card]:shadow-xs @xl/main:grid-cols-2 @5xl/main:grid-cols-4">
|
|
16
|
+
<Card className="@container/card">
|
|
17
|
+
<CardHeader>
|
|
18
|
+
<CardDescription>Projects Generated</CardDescription>
|
|
19
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
20
|
+
1,247
|
|
21
|
+
</CardTitle>
|
|
22
|
+
<CardAction>
|
|
23
|
+
<Badge variant="outline">
|
|
24
|
+
<IconTrendingUp />
|
|
25
|
+
+18.2%
|
|
26
|
+
</Badge>
|
|
27
|
+
</CardAction>
|
|
28
|
+
</CardHeader>
|
|
29
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
30
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
31
|
+
Growing adoption rate <IconTrendingUp className="size-4" />
|
|
32
|
+
</div>
|
|
33
|
+
<div className="text-muted-foreground">
|
|
34
|
+
Projects created this month
|
|
35
|
+
</div>
|
|
36
|
+
</CardFooter>
|
|
37
|
+
</Card>
|
|
38
|
+
<Card className="@container/card">
|
|
39
|
+
<CardHeader>
|
|
40
|
+
<CardDescription>GitHub Stars</CardDescription>
|
|
41
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
42
|
+
324
|
|
43
|
+
</CardTitle>
|
|
44
|
+
<CardAction>
|
|
45
|
+
<Badge variant="outline">
|
|
46
|
+
<IconTrendingUp />
|
|
47
|
+
+45%
|
|
48
|
+
</Badge>
|
|
49
|
+
</CardAction>
|
|
50
|
+
</CardHeader>
|
|
51
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
52
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
53
|
+
Community is growing <IconTrendingUp className="size-4" />
|
|
54
|
+
</div>
|
|
55
|
+
<div className="text-muted-foreground">
|
|
56
|
+
Star us on GitHub
|
|
57
|
+
</div>
|
|
58
|
+
</CardFooter>
|
|
59
|
+
</Card>
|
|
60
|
+
<Card className="@container/card">
|
|
61
|
+
<CardHeader>
|
|
62
|
+
<CardDescription>Active Developers</CardDescription>
|
|
63
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
64
|
+
892
|
|
65
|
+
</CardTitle>
|
|
66
|
+
<CardAction>
|
|
67
|
+
<Badge variant="outline">
|
|
68
|
+
<IconTrendingUp />
|
|
69
|
+
+24.3%
|
|
70
|
+
</Badge>
|
|
71
|
+
</CardAction>
|
|
72
|
+
</CardHeader>
|
|
73
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
74
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
75
|
+
Strong community engagement <IconTrendingUp className="size-4" />
|
|
76
|
+
</div>
|
|
77
|
+
<div className="text-muted-foreground">Weekly active users</div>
|
|
78
|
+
</CardFooter>
|
|
79
|
+
</Card>
|
|
80
|
+
<Card className="@container/card">
|
|
81
|
+
<CardHeader>
|
|
82
|
+
<CardDescription>Feature Adoption</CardDescription>
|
|
83
|
+
<CardTitle className="text-2xl font-semibold tabular-nums @[250px]/card:text-3xl">
|
|
84
|
+
78%
|
|
85
|
+
</CardTitle>
|
|
86
|
+
<CardAction>
|
|
87
|
+
<Badge variant="outline">
|
|
88
|
+
<IconTrendingUp />
|
|
89
|
+
+8.5%
|
|
90
|
+
</Badge>
|
|
91
|
+
</CardAction>
|
|
92
|
+
</CardHeader>
|
|
93
|
+
<CardFooter className="flex-col items-start gap-1.5 text-sm">
|
|
94
|
+
<div className="line-clamp-1 flex gap-2 font-medium">
|
|
95
|
+
Users love optional features <IconTrendingUp className="size-4" />
|
|
96
|
+
</div>
|
|
97
|
+
<div className="text-muted-foreground">Avg features per project</div>
|
|
98
|
+
</CardFooter>
|
|
99
|
+
</Card>
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import UserProfile from "@/components/user-profile";
|
|
4
|
+
import clsx from "clsx";
|
|
5
|
+
import {
|
|
6
|
+
CreditCard,
|
|
7
|
+
HomeIcon,
|
|
8
|
+
LucideIcon,
|
|
9
|
+
Settings,
|
|
10
|
+
} from "lucide-react";
|
|
11
|
+
import Link from "next/link";
|
|
12
|
+
import { usePathname, useRouter } from "next/navigation";
|
|
13
|
+
|
|
14
|
+
interface NavItem {
|
|
15
|
+
label: string;
|
|
16
|
+
href: string;
|
|
17
|
+
icon: LucideIcon;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const navItems: NavItem[] = [
|
|
21
|
+
{
|
|
22
|
+
label: "Overview",
|
|
23
|
+
href: "/dashboard",
|
|
24
|
+
icon: HomeIcon,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: "Billing",
|
|
28
|
+
href: "/dashboard/billing",
|
|
29
|
+
icon: CreditCard,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
export default function DashboardSideBar() {
|
|
34
|
+
const pathname = usePathname();
|
|
35
|
+
const router = useRouter();
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div className="min-[1024px]:block hidden w-64 border-r h-full bg-background">
|
|
39
|
+
<div className="flex h-full flex-col">
|
|
40
|
+
<div className="flex h-[3.45rem] items-center border-b px-4">
|
|
41
|
+
<Link
|
|
42
|
+
prefetch={true}
|
|
43
|
+
className="flex items-center font-semibold hover:cursor-pointer"
|
|
44
|
+
href="/"
|
|
45
|
+
>
|
|
46
|
+
<span>SaaS Scaffold</span>
|
|
47
|
+
</Link>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<nav className="flex flex-col h-full justify-between items-start w-full space-y-1">
|
|
51
|
+
<div className="w-full space-y-1 p-4">
|
|
52
|
+
{navItems.map((item) => (
|
|
53
|
+
<div
|
|
54
|
+
key={item.href}
|
|
55
|
+
onClick={() => router.push(item.href)}
|
|
56
|
+
className={clsx(
|
|
57
|
+
"flex items-center gap-2 w-full rounded-lg px-3 py-2 text-sm font-medium transition-colors hover:cursor-pointer",
|
|
58
|
+
pathname === item.href
|
|
59
|
+
? "bg-primary/10 text-primary hover:bg-primary/20"
|
|
60
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
<item.icon className="h-4 w-4" />
|
|
64
|
+
{item.label}
|
|
65
|
+
</div>
|
|
66
|
+
))}
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div className="flex flex-col gap-2 w-full">
|
|
70
|
+
<div className="px-4">
|
|
71
|
+
<div
|
|
72
|
+
onClick={() => router.push("/dashboard/settings")}
|
|
73
|
+
className={clsx(
|
|
74
|
+
"flex items-center w-full gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-colors hover:cursor-pointer",
|
|
75
|
+
pathname === "/dashboard/settings"
|
|
76
|
+
? "bg-primary/10 text-primary hover:bg-primary/20"
|
|
77
|
+
: "text-muted-foreground hover:bg-muted hover:text-foreground",
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
<Settings className="h-4 w-4" />
|
|
81
|
+
Settings
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
<UserProfile />
|
|
85
|
+
</div>
|
|
86
|
+
</nav>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
);
|
|
90
|
+
}
|