create-aron-app 0.1.7 → 0.1.10
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/.cursor/worktrees.json +3 -0
- package/README.md +24 -31
- package/dist/index.js +38 -49
- package/package.json +3 -7
- package/templates/.cursor/rules/backend.mdc +112 -0
- package/templates/.cursor/rules/coding_standards.mdc +85 -4
- package/templates/.cursor/rules/frontend_architecture.mdc +334 -0
- package/templates/.env.example +6 -0
- package/templates/apps/{react-router → web}/.react-router/types/+routes.ts +11 -6
- package/templates/apps/{react-router/.react-router/types/src/routes/(dashboard)/todos → web/.react-router/types/src/routes/(dashboard)/(todos)}/+types/[id].ts +5 -2
- package/templates/apps/{react-router/.react-router/types/src/routes/(dashboard)/todos → web/.react-router/types/src/routes/(dashboard)/(todos)}/+types/index.ts +5 -2
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/layout.ts +65 -0
- package/templates/apps/{react-router → web}/project.json +11 -4
- package/templates/apps/{react-router → web}/react-router.config.ts +1 -1
- package/templates/apps/web/src/libs/convex_query_client.ts +11 -0
- package/templates/apps/web/src/libs/react_query_client.ts +17 -0
- package/templates/apps/web/src/libs/server/auth.ts +32 -0
- package/templates/apps/web/src/libs/server/protected.ts +17 -0
- package/templates/apps/web/src/providers/api_auth_provider.tsx +26 -0
- package/templates/apps/web/src/providers/global_provider.tsx +28 -0
- package/templates/apps/web/src/providers/navigation_loading_bar_provider.tsx +72 -0
- package/templates/apps/web/src/root.tsx +68 -0
- package/templates/apps/web/src/routes/(dashboard)/(todos)/[id].tsx +33 -0
- package/templates/apps/web/src/routes/(dashboard)/(todos)/index.tsx +26 -0
- package/templates/apps/web/src/routes/(dashboard)/(todos)/layout.tsx +9 -0
- package/templates/apps/{react-router → web}/src/routes/(dashboard)/index.tsx +3 -2
- package/templates/apps/web/src/routes/(dashboard)/layout.tsx +20 -0
- package/templates/apps/{react-router → web}/src/routes.ts +4 -2
- package/templates/apps/{react-router → web}/src/surfaces/sidebar/install.tsx +1 -5
- package/templates/apps/{react-router → web}/src/surfaces/sidebar/layout.tsx +24 -15
- package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/all_todos.tsx +1 -1
- package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/all_todos_controller.ts +1 -1
- package/templates/apps/web/src/surfaces/todos/all_todos/bootstrap.ts +21 -0
- package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/bootstrap.ts +4 -5
- package/templates/apps/{nextjs → web}/src/surfaces/todos/single_todo/header/create.tsx +4 -6
- package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/single_todo_controller.ts +1 -1
- package/templates/components.json +20 -0
- package/templates/gitignore +60 -0
- package/templates/nx.json +0 -11
- package/templates/package.json +2 -3
- package/templates/shared/assets/src/styles/global.css +14 -8
- package/templates/shared/ui/src/base/collapsible.tsx +31 -0
- package/templates/shared/ui/src/base/hover-card.tsx +42 -0
- package/templates/shared/ui/src/base/input-group.tsx +168 -0
- package/templates/shared/ui/src/base/panel.tsx +93 -0
- package/templates/shared/ui/src/hooks/use_mobile.tsx +1 -1
- package/templates/shared/ui/src/hooks/use_query_params.tsx +6 -7
- package/templates/shared/utils/src/convex.ts +2 -1
- package/templates/tsconfig.base.json +2 -4
- package/templates/.cursor/commands/builder.md +0 -0
- package/templates/.cursor/rules/api_architecture.mdc +0 -262
- package/templates/.cursor/rules/convex_rules.mdc +0 -331
- package/templates/.cursor/rules/frontend_architecture_core.mdc +0 -495
- package/templates/.cursor/rules/frontend_architecture_nextjs.mdc +0 -458
- package/templates/.cursor/rules/frontend_architecture_reactrouter.mdc +0 -473
- package/templates/.github/workflows/ci.yml +0 -29
- package/templates/apps/api/tsconfig.json +0 -23
- package/templates/apps/nextjs/.env.example +0 -10
- package/templates/apps/nextjs/index.d.ts +0 -6
- package/templates/apps/nextjs/next-env.d.ts +0 -5
- package/templates/apps/nextjs/next.config.js +0 -22
- package/templates/apps/nextjs/postcss.config.js +0 -17
- package/templates/apps/nextjs/project.json +0 -22
- package/templates/apps/nextjs/src/app/(auth)/layout.tsx +0 -21
- package/templates/apps/nextjs/src/app/(auth)/not-allowed/page.tsx +0 -23
- package/templates/apps/nextjs/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +0 -15
- package/templates/apps/nextjs/src/app/(dashboard)/layout.tsx +0 -22
- package/templates/apps/nextjs/src/app/(dashboard)/page.tsx +0 -12
- package/templates/apps/nextjs/src/app/(dashboard)/todos/[id]/page.tsx +0 -26
- package/templates/apps/nextjs/src/app/(dashboard)/todos/page.tsx +0 -19
- package/templates/apps/nextjs/src/app/app.css +0 -3
- package/templates/apps/nextjs/src/app/layout.tsx +0 -26
- package/templates/apps/nextjs/src/middleware.ts +0 -18
- package/templates/apps/nextjs/src/providers/convex_provider.tsx +0 -44
- package/templates/apps/nextjs/src/surfaces/home/home.tsx +0 -27
- package/templates/apps/nextjs/src/surfaces/home/layout.tsx +0 -44
- package/templates/apps/nextjs/src/surfaces/home/main/create.tsx +0 -34
- package/templates/apps/nextjs/src/surfaces/sidebar/install.tsx +0 -23
- package/templates/apps/nextjs/src/surfaces/sidebar/layout.tsx +0 -118
- package/templates/apps/nextjs/src/surfaces/sidebar/nav_main/create.tsx +0 -19
- package/templates/apps/nextjs/src/surfaces/sidebar/nav_main/nav_config.ts +0 -22
- package/templates/apps/nextjs/src/surfaces/sidebar/nav_main/nav_main.tsx +0 -25
- package/templates/apps/nextjs/src/surfaces/sidebar/nav_secondary/create.tsx +0 -21
- package/templates/apps/nextjs/src/surfaces/sidebar/nav_secondary/nav_secondary.tsx +0 -33
- package/templates/apps/nextjs/src/surfaces/sidebar/sidebar.tsx +0 -23
- package/templates/apps/nextjs/src/surfaces/sidebar/ui/sidebar_nav_link.tsx +0 -39
- package/templates/apps/nextjs/src/surfaces/sidebar/user_menu/create.tsx +0 -28
- package/templates/apps/nextjs/src/surfaces/sidebar/user_menu/user_menu.tsx +0 -42
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/all_todos.tsx +0 -29
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/all_todos_controller.ts +0 -61
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/bootstrap.ts +0 -21
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/header/create.tsx +0 -23
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/install.tsx +0 -23
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/layout.tsx +0 -44
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/create.tsx +0 -49
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/main.tsx +0 -70
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/new_todo_sheet/create.tsx +0 -56
- package/templates/apps/nextjs/src/surfaces/todos/all_todos/main/new_todo_sheet/new_todo_sheet.tsx +0 -99
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/bootstrap.ts +0 -32
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/header/header.tsx +0 -22
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/install.tsx +0 -27
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/layout.tsx +0 -55
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/main/create.tsx +0 -38
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/main/main.tsx +0 -49
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/single_todo.tsx +0 -29
- package/templates/apps/nextjs/src/surfaces/todos/single_todo/single_todo_controller.ts +0 -13
- package/templates/apps/nextjs/src/utils/auth.ts +0 -18
- package/templates/apps/nextjs/src/utils/convex.ts +0 -11
- package/templates/apps/nextjs/src/utils/font.ts +0 -9
- package/templates/apps/nextjs/tsconfig.json +0 -42
- package/templates/apps/react-router/src/providers/api_auth_provider.tsx +0 -40
- package/templates/apps/react-router/src/root.tsx +0 -37
- package/templates/apps/react-router/src/routes/(dashboard)/layout.tsx +0 -37
- package/templates/apps/react-router/src/routes/(dashboard)/todos/[id].tsx +0 -19
- package/templates/apps/react-router/src/routes/(dashboard)/todos/index.tsx +0 -19
- package/templates/apps/react-router/src/surfaces/home/bootstrap.ts +0 -9
- package/templates/apps/react-router/src/surfaces/home/install.tsx +0 -17
- package/templates/apps/react-router/src/surfaces/sidebar/nav_secondary/create.tsx +0 -21
- package/templates/apps/react-router/src/surfaces/sidebar/nav_secondary/nav_secondary.tsx +0 -31
- package/templates/apps/react-router/src/surfaces/todos/all_todos/bootstrap.ts +0 -18
- package/templates/apps/react-router/src/surfaces/todos/all_todos/main/new_todo_sheet/schema.ts +0 -11
- package/templates/apps/react-router/src/surfaces/todos/single_todo/header/create.tsx +0 -32
- package/templates/apps/react-router/tsconfig.json +0 -20
- package/templates/biome.json +0 -121
- package/templates/bun.lock +0 -3187
- package/templates/emails/tsconfig.json +0 -5
- package/templates/shared/assets/tsconfig.json +0 -5
- package/templates/shared/ui/tsconfig.json +0 -8
- package/templates/shared/utils/tsconfig.json +0 -5
- /package/templates/apps/{react-router → web}/.env.example +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/+future.ts +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/+server-build.d.ts +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/src/+types/root.ts +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/src/routes/(auth)/+types/layout.ts +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/src/routes/(auth)/sign-in/+types/index.ts +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/src/routes/(dashboard)/+types/index.ts +0 -0
- /package/templates/apps/{react-router → web}/.react-router/types/src/routes/(dashboard)/+types/layout.ts +0 -0
- /package/templates/apps/{react-router → web}/postcss.config.js +0 -0
- /package/templates/apps/{react-router → web}/public/favicon.ico +0 -0
- /package/templates/apps/{react-router → web}/src/app.css +0 -0
- /package/templates/apps/{react-router → web}/src/components/error_boundary.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/routes/(auth)/layout.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/routes/(auth)/sign-in/index.tsx +0 -0
- /package/templates/apps/{nextjs → web}/src/surfaces/home/bootstrap.ts +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/home/home.tsx +0 -0
- /package/templates/apps/{nextjs → web}/src/surfaces/home/install.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/home/layout.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/home/main/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/sidebar/nav_main/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/sidebar/nav_main/nav_main.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/sidebar/sidebar.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/sidebar/user_menu/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/sidebar/user_menu/user_menu.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/header/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/install.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/layout.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/main/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/main/main.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/main/new_todo_sheet/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/all_todos/main/new_todo_sheet/new_todo_sheet.tsx +0 -0
- /package/templates/apps/{nextjs → web}/src/surfaces/todos/all_todos/main/new_todo_sheet/schema.ts +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/header/header.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/install.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/layout.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/main/create.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/main/main.tsx +0 -0
- /package/templates/apps/{react-router → web}/src/surfaces/todos/single_todo/single_todo.tsx +0 -0
- /package/templates/apps/{react-router → web}/vite.config.ts +0 -0
- /package/templates/emails/{welcome_email.tsx → src/welcome_email.tsx} +0 -0
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { SidebarInset, SidebarProvider } from "@/ui/base/side_bar";
|
|
6
|
-
import { Sidebar } from "@/web/surfaces/sidebar/sidebar";
|
|
7
|
-
|
|
8
|
-
type DashboardLayoutProps = {
|
|
9
|
-
children: React.ReactNode;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export default function DashboardLayout({ children }: DashboardLayoutProps) {
|
|
13
|
-
return (
|
|
14
|
-
<SidebarProvider
|
|
15
|
-
style={{ "--sidebar-width": "265px" } as React.CSSProperties}
|
|
16
|
-
defaultOpen={true}
|
|
17
|
-
>
|
|
18
|
-
<Sidebar />
|
|
19
|
-
<SidebarInset>{children}</SidebarInset>
|
|
20
|
-
</SidebarProvider>
|
|
21
|
-
);
|
|
22
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { bootstrapHome } from "@/web/surfaces/home/bootstrap";
|
|
6
|
-
import { Home } from "@/web/surfaces/home/home";
|
|
7
|
-
|
|
8
|
-
export default async function HomePage() {
|
|
9
|
-
const bootstrap = await bootstrapHome();
|
|
10
|
-
|
|
11
|
-
return <Home bootstrap={bootstrap} />;
|
|
12
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Metadata } from "next";
|
|
6
|
-
|
|
7
|
-
import type { TodoId } from "@/api/todos/types";
|
|
8
|
-
import { bootstrapSingleTodo } from "@/web/surfaces/todos/single_todo/bootstrap";
|
|
9
|
-
import { SingleTodo } from "@/web/surfaces/todos/single_todo/single_todo";
|
|
10
|
-
|
|
11
|
-
type SingleTodoPageProps = {
|
|
12
|
-
params: Promise<{ id: TodoId }>;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const metadata: Metadata = {
|
|
16
|
-
title: "Todo",
|
|
17
|
-
description: "Todo",
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export default async function SingleTodoPage({ params }: SingleTodoPageProps) {
|
|
21
|
-
const { id } = await params;
|
|
22
|
-
|
|
23
|
-
const bootstrap = await bootstrapSingleTodo({ todoId: id });
|
|
24
|
-
|
|
25
|
-
return <SingleTodo bootstrap={bootstrap} />;
|
|
26
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { Metadata } from "next";
|
|
6
|
-
|
|
7
|
-
import { AllTodos } from "@/web/surfaces/todos/all_todos/all_todos";
|
|
8
|
-
import { bootstrapAllTodos } from "@/web/surfaces/todos/all_todos/bootstrap";
|
|
9
|
-
|
|
10
|
-
export const metadata: Metadata = {
|
|
11
|
-
title: "Todos",
|
|
12
|
-
description: "Todos",
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default async function AllTodosPage() {
|
|
16
|
-
const bootstrap = await bootstrapAllTodos();
|
|
17
|
-
|
|
18
|
-
return <AllTodos bootstrap={bootstrap} />;
|
|
19
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { ClerkProvider } from "@clerk/nextjs";
|
|
2
|
-
import "./app.css";
|
|
3
|
-
|
|
4
|
-
import { Toaster } from "sonner";
|
|
5
|
-
|
|
6
|
-
import { ConvexClientProvider } from "@/web/providers/convex_provider";
|
|
7
|
-
import { fontCn } from "@/web/utils/font";
|
|
8
|
-
|
|
9
|
-
type RootLayoutProps = {
|
|
10
|
-
children: React.ReactNode;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export default function RootLayout({ children }: RootLayoutProps) {
|
|
14
|
-
return (
|
|
15
|
-
<ClerkProvider dynamic>
|
|
16
|
-
<ConvexClientProvider>
|
|
17
|
-
<html lang="en" className={fontCn}>
|
|
18
|
-
<body>
|
|
19
|
-
{children}
|
|
20
|
-
<Toaster />
|
|
21
|
-
</body>
|
|
22
|
-
</html>
|
|
23
|
-
</ConvexClientProvider>
|
|
24
|
-
</ClerkProvider>
|
|
25
|
-
);
|
|
26
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
|
|
2
|
-
|
|
3
|
-
const isPublicRoute = createRouteMatcher(["/sign-in(.*)"]);
|
|
4
|
-
|
|
5
|
-
export default clerkMiddleware(async (auth, req) => {
|
|
6
|
-
if (!isPublicRoute(req)) {
|
|
7
|
-
await auth.protect();
|
|
8
|
-
}
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
export const config = {
|
|
12
|
-
matcher: [
|
|
13
|
-
// Skip Next.js internals and all static files, unless found in search params
|
|
14
|
-
"/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
|
|
15
|
-
// Always run for API routes
|
|
16
|
-
"/(api|trpc)(.*)",
|
|
17
|
-
],
|
|
18
|
-
};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { useAuth } from "@clerk/nextjs";
|
|
8
|
-
import { ConvexQueryClient } from "@convex-dev/react-query";
|
|
9
|
-
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
10
|
-
import { ConvexReactClient } from "convex/react";
|
|
11
|
-
import { ConvexProviderWithClerk } from "convex/react-clerk";
|
|
12
|
-
import { type ReactNode, useState } from "react";
|
|
13
|
-
|
|
14
|
-
if (!process.env.NEXT_PUBLIC_CONVEX_URL) {
|
|
15
|
-
throw new Error("Missing NEXT_PUBLIC_CONVEX_URL in your .env file");
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function ConvexClientProvider({ children }: { children: ReactNode }) {
|
|
19
|
-
const [{ convex, queryClient }] = useState(() => {
|
|
20
|
-
const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL as string);
|
|
21
|
-
const convexQueryClient = new ConvexQueryClient(convex);
|
|
22
|
-
const queryClient = new QueryClient({
|
|
23
|
-
defaultOptions: {
|
|
24
|
-
queries: {
|
|
25
|
-
queryKeyHashFn: convexQueryClient.hashFn(),
|
|
26
|
-
queryFn: convexQueryClient.queryFn(),
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
convexQueryClient.connect(queryClient);
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
convex,
|
|
35
|
-
queryClient,
|
|
36
|
-
};
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<ConvexProviderWithClerk client={convex} useAuth={useAuth}>
|
|
41
|
-
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
42
|
-
</ConvexProviderWithClerk>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { useMemo, useRef } from "react";
|
|
8
|
-
|
|
9
|
-
import type { HomeBootstrap } from "@/web/surfaces/home/bootstrap";
|
|
10
|
-
import { installHome } from "@/web/surfaces/home/install";
|
|
11
|
-
import { createLayout } from "@/web/surfaces/home/layout";
|
|
12
|
-
|
|
13
|
-
export type HomeProps = {
|
|
14
|
-
bootstrap: HomeBootstrap;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const Home = ({ bootstrap }: HomeProps) => {
|
|
18
|
-
const { layout, Layout } = useMemo(() => createLayout(), []);
|
|
19
|
-
const installed = useRef(false);
|
|
20
|
-
|
|
21
|
-
if (!installed.current) {
|
|
22
|
-
installed.current = true;
|
|
23
|
-
installHome({ layout, bootstrap });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return <Layout />;
|
|
27
|
-
};
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { makeObservable, observable, action, runInAction } from "mobx";
|
|
8
|
-
import { observer } from "mobx-react-lite";
|
|
9
|
-
import type { ComponentType } from "react";
|
|
10
|
-
|
|
11
|
-
import { Skeleton } from "@/ui/base/skeleton";
|
|
12
|
-
|
|
13
|
-
export class HomeLayoutController {
|
|
14
|
-
Main: ComponentType | undefined = undefined;
|
|
15
|
-
|
|
16
|
-
constructor() {
|
|
17
|
-
makeObservable(this, {
|
|
18
|
-
Main: observable.ref,
|
|
19
|
-
setMain: action,
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
setMain(Main: ComponentType) {
|
|
24
|
-
runInAction(() => {
|
|
25
|
-
this.Main = Main;
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const createLayout = () => {
|
|
31
|
-
const layout = new HomeLayoutController();
|
|
32
|
-
return {
|
|
33
|
-
layout,
|
|
34
|
-
Layout: observer(() => {
|
|
35
|
-
const Main = layout.Main;
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<div className="flex w-full flex-1 flex-col">
|
|
39
|
-
{Main ? <Main /> : <Skeleton className="h-64 w-full rounded-md" />}
|
|
40
|
-
</div>
|
|
41
|
-
);
|
|
42
|
-
}),
|
|
43
|
-
};
|
|
44
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { useUser } from "@clerk/nextjs";
|
|
8
|
-
import { observer } from "mobx-react-lite";
|
|
9
|
-
import Link from "next/link";
|
|
10
|
-
|
|
11
|
-
import { Button } from "@/ui/base/button";
|
|
12
|
-
import type { HomeBootstrap } from "@/web/surfaces/home/bootstrap";
|
|
13
|
-
|
|
14
|
-
export type CreateHomeMainOpts = {
|
|
15
|
-
bootstrap: HomeBootstrap;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const createMain = ({ bootstrap: _bootstrap }: CreateHomeMainOpts) => {
|
|
19
|
-
return observer(() => {
|
|
20
|
-
const { user } = useUser();
|
|
21
|
-
|
|
22
|
-
return (
|
|
23
|
-
<main className="flex flex-1 flex-col items-center justify-center gap-4 p-8">
|
|
24
|
-
<h1 className="text-3xl font-bold">
|
|
25
|
-
Welcome{user?.firstName ? `, ${user.firstName}` : ""}
|
|
26
|
-
</h1>
|
|
27
|
-
<p className="text-muted-foreground">Get started by managing your todos.</p>
|
|
28
|
-
<Button asChild>
|
|
29
|
-
<Link href="/todos">View Todos</Link>
|
|
30
|
-
</Button>
|
|
31
|
-
</main>
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import type { SidebarLayoutController } from "@/web/surfaces/sidebar/layout";
|
|
6
|
-
|
|
7
|
-
type InstallSidebarOpts = {
|
|
8
|
-
layout: SidebarLayoutController;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const installSidebar = ({ layout }: InstallSidebarOpts) => {
|
|
12
|
-
import("@/web/surfaces/sidebar/nav_main/create").then(({ createNavMain }) => {
|
|
13
|
-
layout.setNavMain(createNavMain());
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
import("@/web/surfaces/sidebar/nav_secondary/create").then(({ createNavSecondary }) => {
|
|
17
|
-
layout.setNavSecondary(createNavSecondary());
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
import("@/web/surfaces/sidebar/user_menu/create").then(({ createUserMenu }) => {
|
|
21
|
-
layout.setUserMenu(createUserMenu());
|
|
22
|
-
});
|
|
23
|
-
};
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { action, makeObservable, observable, runInAction } from "mobx";
|
|
8
|
-
import { observer } from "mobx-react-lite";
|
|
9
|
-
import Link from "next/link";
|
|
10
|
-
import type { ComponentType } from "react";
|
|
11
|
-
|
|
12
|
-
import {
|
|
13
|
-
Sidebar as BaseSidebar,
|
|
14
|
-
SidebarContent,
|
|
15
|
-
SidebarFooter,
|
|
16
|
-
SidebarHeader,
|
|
17
|
-
SidebarMenu,
|
|
18
|
-
SidebarMenuButton,
|
|
19
|
-
SidebarMenuItem,
|
|
20
|
-
} from "@/ui/base/side_bar";
|
|
21
|
-
import { Skeleton } from "@/ui/base/skeleton";
|
|
22
|
-
|
|
23
|
-
export class SidebarLayoutController {
|
|
24
|
-
NavMain: ComponentType | undefined = undefined;
|
|
25
|
-
NavSecondary: ComponentType | undefined = undefined;
|
|
26
|
-
UserMenu: ComponentType | undefined = undefined;
|
|
27
|
-
|
|
28
|
-
constructor() {
|
|
29
|
-
makeObservable(this, {
|
|
30
|
-
NavMain: observable.ref,
|
|
31
|
-
NavSecondary: observable.ref,
|
|
32
|
-
UserMenu: observable.ref,
|
|
33
|
-
setNavMain: action,
|
|
34
|
-
setNavSecondary: action,
|
|
35
|
-
setUserMenu: action,
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
setNavMain(NavMain: ComponentType) {
|
|
40
|
-
runInAction(() => {
|
|
41
|
-
this.NavMain = NavMain;
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
setNavSecondary(NavSecondary: ComponentType) {
|
|
46
|
-
runInAction(() => {
|
|
47
|
-
this.NavSecondary = NavSecondary;
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
setUserMenu(UserMenu: ComponentType) {
|
|
52
|
-
runInAction(() => {
|
|
53
|
-
this.UserMenu = UserMenu;
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const BrandLink = () => {
|
|
59
|
-
return (
|
|
60
|
-
<SidebarMenu>
|
|
61
|
-
<SidebarMenuItem>
|
|
62
|
-
<SidebarMenuButton
|
|
63
|
-
size="lg"
|
|
64
|
-
className="h-auto flex-col items-start gap-0.5 p-0"
|
|
65
|
-
asChild
|
|
66
|
-
>
|
|
67
|
-
<Link
|
|
68
|
-
href="/"
|
|
69
|
-
className="flex flex-row w-full items-center gap-3 px-2 py-2 transition-opacity hover:opacity-80 active:opacity-70 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0 group-data-[collapsible=icon]:[&>div:last-child]:hidden"
|
|
70
|
-
>
|
|
71
|
-
<div className="flex size-10 shrink-0 items-center justify-center rounded-md bg-sidebar-brand text-sm text-white font-semibold group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:text-xs">
|
|
72
|
-
A
|
|
73
|
-
</div>
|
|
74
|
-
<div className="flex min-w-0 flex-col">
|
|
75
|
-
<span className="truncate text-base font-bold text-sidebar-foreground">
|
|
76
|
-
App
|
|
77
|
-
</span>
|
|
78
|
-
<span className="truncate text-xs text-sidebar-muted-foreground">
|
|
79
|
-
Template
|
|
80
|
-
</span>
|
|
81
|
-
</div>
|
|
82
|
-
</Link>
|
|
83
|
-
</SidebarMenuButton>
|
|
84
|
-
</SidebarMenuItem>
|
|
85
|
-
</SidebarMenu>
|
|
86
|
-
);
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
export const createSidebarLayout = () => {
|
|
90
|
-
const layout = new SidebarLayoutController();
|
|
91
|
-
return {
|
|
92
|
-
layout,
|
|
93
|
-
Layout: observer(() => {
|
|
94
|
-
const NavMain = layout.NavMain;
|
|
95
|
-
const NavSecondary = layout.NavSecondary;
|
|
96
|
-
const UserMenu = layout.UserMenu;
|
|
97
|
-
|
|
98
|
-
return (
|
|
99
|
-
<BaseSidebar
|
|
100
|
-
data-slot="app-sidebar"
|
|
101
|
-
className="shadow-sm"
|
|
102
|
-
collapsible="icon"
|
|
103
|
-
>
|
|
104
|
-
<SidebarHeader>
|
|
105
|
-
<BrandLink />
|
|
106
|
-
</SidebarHeader>
|
|
107
|
-
<SidebarContent className="flex flex-1 flex-col gap-4 overflow-hidden px-2">
|
|
108
|
-
{NavMain ? <NavMain /> : <Skeleton className="h-24 bg-sidebar-accent" />}
|
|
109
|
-
</SidebarContent>
|
|
110
|
-
<SidebarFooter className="gap-2">
|
|
111
|
-
{NavSecondary ? <NavSecondary /> : <Skeleton className="h-10 bg-sidebar-accent" />}
|
|
112
|
-
{UserMenu ? <UserMenu /> : <Skeleton className="h-12 bg-sidebar-accent" />}
|
|
113
|
-
</SidebarFooter>
|
|
114
|
-
</BaseSidebar>
|
|
115
|
-
);
|
|
116
|
-
}),
|
|
117
|
-
};
|
|
118
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { observer } from "mobx-react-lite";
|
|
8
|
-
|
|
9
|
-
import { useSidebar } from "@/ui/base/side_bar";
|
|
10
|
-
import { navMainItems } from "@/web/surfaces/sidebar/nav_main/nav_config";
|
|
11
|
-
import { NavMain } from "@/web/surfaces/sidebar/nav_main/nav_main";
|
|
12
|
-
|
|
13
|
-
export const createNavMain = () => {
|
|
14
|
-
return observer(() => {
|
|
15
|
-
const { setOpenMobile } = useSidebar();
|
|
16
|
-
|
|
17
|
-
return <NavMain items={navMainItems} onNavigate={() => setOpenMobile(false)} />;
|
|
18
|
-
});
|
|
19
|
-
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { CheckSquareIcon, HomeIcon } from "lucide-react";
|
|
6
|
-
|
|
7
|
-
import type { SidebarNavItem } from "@/web/surfaces/sidebar/ui/sidebar_nav_link";
|
|
8
|
-
|
|
9
|
-
export const navMainItems: SidebarNavItem[] = [
|
|
10
|
-
{
|
|
11
|
-
id: "dashboard",
|
|
12
|
-
title: "Dashboard",
|
|
13
|
-
url: "/",
|
|
14
|
-
icon: HomeIcon,
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
id: "todos",
|
|
18
|
-
title: "Todos",
|
|
19
|
-
url: "/todos",
|
|
20
|
-
icon: CheckSquareIcon,
|
|
21
|
-
},
|
|
22
|
-
];
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { SidebarMenu } from "@/ui/base/side_bar";
|
|
8
|
-
|
|
9
|
-
import type { SidebarNavItem } from "@/web/surfaces/sidebar/ui/sidebar_nav_link";
|
|
10
|
-
import { SidebarNavLink } from "@/web/surfaces/sidebar/ui/sidebar_nav_link";
|
|
11
|
-
|
|
12
|
-
type NavMainProps = {
|
|
13
|
-
items: SidebarNavItem[];
|
|
14
|
-
onNavigate: () => void;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const NavMain = ({ items, onNavigate }: NavMainProps) => {
|
|
18
|
-
return (
|
|
19
|
-
<SidebarMenu>
|
|
20
|
-
{items.map((item) => (
|
|
21
|
-
<SidebarNavLink key={item.id} item={item} onNavigate={onNavigate} />
|
|
22
|
-
))}
|
|
23
|
-
</SidebarMenu>
|
|
24
|
-
);
|
|
25
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { observer } from "mobx-react-lite";
|
|
8
|
-
import { usePathname } from "next/navigation";
|
|
9
|
-
|
|
10
|
-
import { useSidebar } from "@/ui/base/side_bar";
|
|
11
|
-
|
|
12
|
-
import { NavSecondary } from "@/web/surfaces/sidebar/nav_secondary/nav_secondary";
|
|
13
|
-
|
|
14
|
-
export const createNavSecondary = () => {
|
|
15
|
-
return observer(() => {
|
|
16
|
-
const pathname = usePathname();
|
|
17
|
-
const { setOpenMobile } = useSidebar();
|
|
18
|
-
|
|
19
|
-
return <NavSecondary pathname={pathname} onNavigate={() => setOpenMobile(false)} />;
|
|
20
|
-
});
|
|
21
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { SettingsIcon } from "lucide-react";
|
|
8
|
-
import Link from "next/link";
|
|
9
|
-
|
|
10
|
-
import { SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "@/ui/base/side_bar";
|
|
11
|
-
|
|
12
|
-
type NavSecondaryProps = {
|
|
13
|
-
pathname: string;
|
|
14
|
-
onNavigate: () => void;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const NavSecondary = ({ pathname, onNavigate }: NavSecondaryProps) => {
|
|
18
|
-
const settingsPath = "/settings";
|
|
19
|
-
const isActive = pathname === settingsPath || pathname.startsWith(`${settingsPath}/`);
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<SidebarMenu>
|
|
23
|
-
<SidebarMenuItem>
|
|
24
|
-
<SidebarMenuButton isActive={isActive} asChild onClick={onNavigate}>
|
|
25
|
-
<Link href={settingsPath}>
|
|
26
|
-
<SettingsIcon className="size-4" />
|
|
27
|
-
<span>Settings</span>
|
|
28
|
-
</Link>
|
|
29
|
-
</SidebarMenuButton>
|
|
30
|
-
</SidebarMenuItem>
|
|
31
|
-
</SidebarMenu>
|
|
32
|
-
);
|
|
33
|
-
};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { useMemo, useRef } from "react";
|
|
8
|
-
|
|
9
|
-
import { installSidebar } from "@/web/surfaces/sidebar/install";
|
|
10
|
-
import { createSidebarLayout } from "@/web/surfaces/sidebar/layout";
|
|
11
|
-
|
|
12
|
-
export const Sidebar = () => {
|
|
13
|
-
const { layout, Layout } = useMemo(createSidebarLayout, []);
|
|
14
|
-
|
|
15
|
-
const installed = useRef(false);
|
|
16
|
-
|
|
17
|
-
if (!installed.current) {
|
|
18
|
-
installed.current = true;
|
|
19
|
-
installSidebar({ layout });
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return <Layout />;
|
|
23
|
-
};
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import type { LucideIcon } from "lucide-react";
|
|
8
|
-
import Link from "next/link";
|
|
9
|
-
import { usePathname } from "next/navigation";
|
|
10
|
-
|
|
11
|
-
import { SidebarMenuButton, SidebarMenuItem } from "@/ui/base/side_bar";
|
|
12
|
-
|
|
13
|
-
export type SidebarNavItem = {
|
|
14
|
-
id: string;
|
|
15
|
-
title: string;
|
|
16
|
-
url: string;
|
|
17
|
-
icon: LucideIcon;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
type SidebarNavLinkProps = {
|
|
21
|
-
item: SidebarNavItem;
|
|
22
|
-
onNavigate: () => void;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const SidebarNavLink = ({ item, onNavigate }: SidebarNavLinkProps) => {
|
|
26
|
-
const pathname = usePathname();
|
|
27
|
-
const isActive = pathname === item.url;
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<SidebarMenuItem>
|
|
31
|
-
<SidebarMenuButton asChild isActive={isActive} tooltip={item.title} onClick={onNavigate}>
|
|
32
|
-
<Link href={item.url}>
|
|
33
|
-
<item.icon className="size-4" />
|
|
34
|
-
<span>{item.title}</span>
|
|
35
|
-
</Link>
|
|
36
|
-
</SidebarMenuButton>
|
|
37
|
-
</SidebarMenuItem>
|
|
38
|
-
);
|
|
39
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) Aron Weston 2026.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
"use client";
|
|
6
|
-
|
|
7
|
-
import { useUser } from "@clerk/nextjs";
|
|
8
|
-
import { observer } from "mobx-react-lite";
|
|
9
|
-
|
|
10
|
-
import { UserMenu } from "@/web/surfaces/sidebar/user_menu/user_menu";
|
|
11
|
-
|
|
12
|
-
export const createUserMenu = () => {
|
|
13
|
-
return observer(() => {
|
|
14
|
-
const { user, isLoaded } = useUser();
|
|
15
|
-
|
|
16
|
-
if (isLoaded && !user) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<UserMenu
|
|
22
|
-
isLoaded={isLoaded}
|
|
23
|
-
fullName={user?.fullName}
|
|
24
|
-
email={user?.emailAddresses[0]?.emailAddress}
|
|
25
|
-
/>
|
|
26
|
-
);
|
|
27
|
-
});
|
|
28
|
-
};
|