create-varity-app 2.0.0-beta.1
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 +85 -0
- package/dist/create.js +141 -0
- package/dist/index.js +45 -0
- package/dist/utils.js +29 -0
- package/package.json +61 -0
- package/template/.env.example +17 -0
- package/template/KNOWN_ISSUES.md +69 -0
- package/template/LICENSE +21 -0
- package/template/README.md +241 -0
- package/template/gitignore +42 -0
- package/template/next-env.d.ts +6 -0
- package/template/next.config.js +21 -0
- package/template/package.json +39 -0
- package/template/postcss.config.js +6 -0
- package/template/public/logo.svg +4 -0
- package/template/public/robots.txt +4 -0
- package/template/public/sitemap.xml +4 -0
- package/template/src/app/dashboard/layout.tsx +298 -0
- package/template/src/app/dashboard/page.tsx +209 -0
- package/template/src/app/dashboard/projects/page.tsx +638 -0
- package/template/src/app/dashboard/settings/page.tsx +749 -0
- package/template/src/app/dashboard/tasks/page.tsx +301 -0
- package/template/src/app/dashboard/team/page.tsx +295 -0
- package/template/src/app/globals.css +177 -0
- package/template/src/app/icon.svg +4 -0
- package/template/src/app/layout.tsx +33 -0
- package/template/src/app/login/page.tsx +98 -0
- package/template/src/app/not-found.tsx +20 -0
- package/template/src/app/page.tsx +23 -0
- package/template/src/components/dashboard/DashboardStats.tsx +137 -0
- package/template/src/components/dashboard/RecentActivity.tsx +63 -0
- package/template/src/components/landing/CTA.tsx +42 -0
- package/template/src/components/landing/Features.tsx +116 -0
- package/template/src/components/landing/Hero.tsx +146 -0
- package/template/src/components/landing/HowItWorks.tsx +80 -0
- package/template/src/components/landing/Pricing.tsx +124 -0
- package/template/src/components/landing/Testimonials.tsx +78 -0
- package/template/src/components/providers.tsx +11 -0
- package/template/src/components/shared/Footer.tsx +71 -0
- package/template/src/components/shared/Navbar.tsx +87 -0
- package/template/src/lib/constants.ts +35 -0
- package/template/src/lib/database.ts +7 -0
- package/template/src/lib/hooks.ts +331 -0
- package/template/src/lib/utils.ts +68 -0
- package/template/src/lib/varity.ts +1 -0
- package/template/src/services/dashboardService.ts +589 -0
- package/template/src/types/index.ts +52 -0
- package/template/tailwind.config.js +27 -0
- package/template/tsconfig.json +23 -0
- package/template/varity.config.json +14 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useRouter } from 'next/navigation';
|
|
4
|
+
import { useProjects, useTasks, useTeam, useCurrentUser } from '@/lib/hooks';
|
|
5
|
+
import { DashboardStats } from '@/components/dashboard/DashboardStats';
|
|
6
|
+
import { RecentActivity } from '@/components/dashboard/RecentActivity';
|
|
7
|
+
import { APP_NAME } from '@/lib/constants';
|
|
8
|
+
import { FolderKanban, ListTodo, Users, ArrowRight } from 'lucide-react';
|
|
9
|
+
|
|
10
|
+
function QuickActions() {
|
|
11
|
+
const router = useRouter();
|
|
12
|
+
|
|
13
|
+
const actions = [
|
|
14
|
+
{
|
|
15
|
+
label: 'New Project',
|
|
16
|
+
description: 'Organize your work',
|
|
17
|
+
icon: 'folderKanban',
|
|
18
|
+
path: '/dashboard/projects',
|
|
19
|
+
color: 'bg-blue-50 text-blue-600',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
label: 'View Tasks',
|
|
23
|
+
description: 'Track your progress',
|
|
24
|
+
icon: 'listTodo',
|
|
25
|
+
path: '/dashboard/tasks',
|
|
26
|
+
color: 'bg-amber-50 text-amber-600',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: 'Invite Team',
|
|
30
|
+
description: 'Collaborate together',
|
|
31
|
+
icon: 'users',
|
|
32
|
+
path: '/dashboard/team',
|
|
33
|
+
color: 'bg-green-50 text-green-600',
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const getIcon = (name: string) => {
|
|
38
|
+
const className = "h-5 w-5";
|
|
39
|
+
switch (name) {
|
|
40
|
+
case 'folderKanban': return <FolderKanban className={className} />;
|
|
41
|
+
case 'listTodo': return <ListTodo className={className} />;
|
|
42
|
+
case 'users': return <Users className={className} />;
|
|
43
|
+
default: return null;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
|
|
49
|
+
{actions.map((action) => (
|
|
50
|
+
<button
|
|
51
|
+
key={action.path}
|
|
52
|
+
onClick={() => router.push(action.path)}
|
|
53
|
+
className="flex items-center gap-3 rounded-xl border border-gray-200 bg-white p-4 text-left shadow-sm hover:shadow-md hover:border-gray-300 transition-all"
|
|
54
|
+
>
|
|
55
|
+
<div className={`flex h-10 w-10 shrink-0 items-center justify-center rounded-lg ${action.color}`}>
|
|
56
|
+
{getIcon(action.icon)}
|
|
57
|
+
</div>
|
|
58
|
+
<div>
|
|
59
|
+
<p className="text-sm font-medium text-gray-900">{action.label}</p>
|
|
60
|
+
<p className="text-xs text-gray-500">{action.description}</p>
|
|
61
|
+
</div>
|
|
62
|
+
</button>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function GettingStarted({
|
|
69
|
+
hasProjects,
|
|
70
|
+
hasTasks,
|
|
71
|
+
hasTeam,
|
|
72
|
+
}: {
|
|
73
|
+
hasProjects: boolean;
|
|
74
|
+
hasTasks: boolean;
|
|
75
|
+
hasTeam: boolean;
|
|
76
|
+
}) {
|
|
77
|
+
const router = useRouter();
|
|
78
|
+
const completedCount = [hasProjects, hasTasks, hasTeam].filter(Boolean).length;
|
|
79
|
+
|
|
80
|
+
if (completedCount === 3) return null;
|
|
81
|
+
|
|
82
|
+
const steps = [
|
|
83
|
+
{
|
|
84
|
+
label: 'Create your first project',
|
|
85
|
+
done: hasProjects,
|
|
86
|
+
path: '/dashboard/projects',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: 'Add a task to your project',
|
|
90
|
+
done: hasTasks,
|
|
91
|
+
path: '/dashboard/projects',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: 'Invite a team member',
|
|
95
|
+
done: hasTeam,
|
|
96
|
+
path: '/dashboard/team',
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div className="rounded-xl border border-primary-200 bg-primary-50 p-5">
|
|
102
|
+
<div className="flex items-center justify-between mb-3">
|
|
103
|
+
<h3 className="text-sm font-semibold text-primary-900">Getting Started</h3>
|
|
104
|
+
<span className="text-xs font-medium text-primary-600">{completedCount}/3 complete</span>
|
|
105
|
+
</div>
|
|
106
|
+
<div className="h-1.5 rounded-full bg-primary-100 mb-4">
|
|
107
|
+
<div
|
|
108
|
+
className="h-1.5 rounded-full bg-primary-600 transition-all"
|
|
109
|
+
style={{ width: `${(completedCount / 3) * 100}%` }}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
<div className="space-y-2">
|
|
113
|
+
{steps.map((step) => (
|
|
114
|
+
<button
|
|
115
|
+
key={step.label}
|
|
116
|
+
onClick={() => !step.done && router.push(step.path)}
|
|
117
|
+
disabled={step.done}
|
|
118
|
+
className={`flex w-full items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors ${
|
|
119
|
+
step.done
|
|
120
|
+
? 'text-primary-400'
|
|
121
|
+
: 'text-primary-800 hover:bg-primary-100'
|
|
122
|
+
}`}
|
|
123
|
+
>
|
|
124
|
+
<span className={`flex h-5 w-5 shrink-0 items-center justify-center rounded-full text-xs font-bold ${
|
|
125
|
+
step.done
|
|
126
|
+
? 'bg-primary-600 text-white'
|
|
127
|
+
: 'border-2 border-primary-300'
|
|
128
|
+
}`}>
|
|
129
|
+
{step.done ? '✓' : ''}
|
|
130
|
+
</span>
|
|
131
|
+
<span className={step.done ? 'line-through' : ''}>{step.label}</span>
|
|
132
|
+
{!step.done && <ArrowRight className="ml-auto h-4 w-4 opacity-50" />}
|
|
133
|
+
</button>
|
|
134
|
+
))}
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export default function DashboardPage() {
|
|
141
|
+
const router = useRouter();
|
|
142
|
+
const { name } = useCurrentUser();
|
|
143
|
+
const { data: projects, loading: projectsLoading, error: projectsError, refresh: refreshProjects } = useProjects();
|
|
144
|
+
const { data: tasks, loading: tasksLoading, error: tasksError, refresh: refreshTasks } = useTasks();
|
|
145
|
+
const { data: team, loading: teamLoading, error: teamError, refresh: refreshTeam } = useTeam();
|
|
146
|
+
const loading = projectsLoading || tasksLoading || teamLoading;
|
|
147
|
+
const error = projectsError || tasksError || teamError;
|
|
148
|
+
const hasProjects = projects.length > 0;
|
|
149
|
+
const hasTasks = tasks.length > 0;
|
|
150
|
+
const hasTeam = team.length > 0;
|
|
151
|
+
const hasData = hasProjects || hasTasks;
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<div className="space-y-6">
|
|
155
|
+
<div>
|
|
156
|
+
<h1 className="text-2xl font-bold text-gray-900">
|
|
157
|
+
{hasData ? 'Dashboard' : `Welcome, ${name || 'there'}`}
|
|
158
|
+
</h1>
|
|
159
|
+
<p className="mt-1 text-sm text-gray-600">
|
|
160
|
+
{hasData
|
|
161
|
+
? 'Overview of your projects and tasks.'
|
|
162
|
+
: `Get started with ${APP_NAME} by creating your first project.`}
|
|
163
|
+
</p>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
{error && (
|
|
167
|
+
<div className="flex items-center justify-between rounded-lg border border-red-200 bg-red-50 px-4 py-3">
|
|
168
|
+
<p className="text-sm text-red-700">Failed to load data. Please check your connection and try again.</p>
|
|
169
|
+
<button
|
|
170
|
+
onClick={() => { refreshProjects(); refreshTasks(); refreshTeam(); }}
|
|
171
|
+
className="text-sm font-medium text-red-700 hover:text-red-800 underline"
|
|
172
|
+
>
|
|
173
|
+
Retry
|
|
174
|
+
</button>
|
|
175
|
+
</div>
|
|
176
|
+
)}
|
|
177
|
+
|
|
178
|
+
<DashboardStats
|
|
179
|
+
projects={projects}
|
|
180
|
+
tasks={tasks}
|
|
181
|
+
team={team}
|
|
182
|
+
loading={loading}
|
|
183
|
+
/>
|
|
184
|
+
|
|
185
|
+
{!loading && !hasData ? (
|
|
186
|
+
<div className="space-y-6">
|
|
187
|
+
<GettingStarted
|
|
188
|
+
hasProjects={hasProjects}
|
|
189
|
+
hasTasks={hasTasks}
|
|
190
|
+
hasTeam={hasTeam}
|
|
191
|
+
/>
|
|
192
|
+
<QuickActions />
|
|
193
|
+
</div>
|
|
194
|
+
) : (
|
|
195
|
+
<>
|
|
196
|
+
{!loading && (!hasProjects || !hasTasks || !hasTeam) && (
|
|
197
|
+
<GettingStarted
|
|
198
|
+
hasProjects={hasProjects}
|
|
199
|
+
hasTasks={hasTasks}
|
|
200
|
+
hasTeam={hasTeam}
|
|
201
|
+
/>
|
|
202
|
+
)}
|
|
203
|
+
<QuickActions />
|
|
204
|
+
<RecentActivity tasks={tasks} loading={tasksLoading} />
|
|
205
|
+
</>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|