create-aron-app 0.1.6 → 0.1.8
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/README.md +24 -31
- package/dist/index.js +39 -115
- package/package.json +7 -4
- package/templates/.cursor/rules/backend.mdc +112 -0
- package/templates/.cursor/rules/coding_standards.mdc +145 -0
- package/templates/.cursor/rules/frontend_architecture.mdc +334 -0
- package/templates/.github/workflows/ci.yml +40 -0
- package/templates/apps/api/_generated/api.d.ts +57 -0
- package/templates/apps/api/_generated/api.js +23 -0
- package/templates/apps/api/_generated/dataModel.d.ts +60 -0
- package/templates/apps/api/_generated/server.d.ts +143 -0
- package/templates/apps/api/_generated/server.js +93 -0
- package/templates/apps/api/http.ts +16 -0
- package/templates/apps/web/.env.example +10 -0
- package/templates/apps/web/.react-router/types/+future.ts +9 -0
- package/templates/apps/web/.react-router/types/+routes.ts +76 -0
- package/templates/apps/web/.react-router/types/+server-build.d.ts +18 -0
- package/templates/apps/web/.react-router/types/src/+types/root.ts +59 -0
- package/templates/apps/web/.react-router/types/src/routes/(auth)/+types/layout.ts +62 -0
- package/templates/apps/web/.react-router/types/src/routes/(auth)/sign-in/+types/index.ts +65 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/[id].ts +68 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/index.ts +68 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/layout.ts +65 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/+types/index.ts +65 -0
- package/templates/apps/web/.react-router/types/src/routes/(dashboard)/+types/layout.ts +62 -0
- package/templates/{react-router → apps/web}/project.json +9 -2
- package/templates/{react-router → apps/web}/react-router.config.ts +1 -1
- package/templates/apps/web/src/app.css +3 -0
- package/templates/{react-router → apps/web}/src/components/error_boundary.tsx +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/{react-router/src/routes/auth → apps/web/src/routes/(auth)}/layout.tsx +1 -1
- 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/web/src/routes/(dashboard)/index.tsx +20 -0
- package/templates/apps/web/src/routes/(dashboard)/layout.tsx +20 -0
- package/templates/apps/web/src/routes.ts +14 -0
- package/templates/apps/web/src/surfaces/home/bootstrap.ts +9 -0
- package/templates/apps/web/src/surfaces/home/home.tsx +25 -0
- package/templates/apps/web/src/surfaces/home/install.tsx +17 -0
- package/templates/apps/web/src/surfaces/home/layout.tsx +35 -0
- package/templates/apps/web/src/surfaces/home/main/create.tsx +32 -0
- package/templates/apps/web/src/surfaces/sidebar/install.tsx +19 -0
- package/templates/apps/web/src/surfaces/sidebar/layout.tsx +119 -0
- package/templates/apps/web/src/surfaces/sidebar/nav_main/create.tsx +31 -0
- package/templates/apps/web/src/surfaces/sidebar/nav_main/nav_main.tsx +42 -0
- package/templates/apps/web/src/surfaces/sidebar/sidebar.tsx +18 -0
- package/templates/apps/web/src/surfaces/sidebar/user_menu/create.tsx +26 -0
- package/templates/{react-router/src/layouts/sidebar/sidebar_aside → apps/web/src/surfaces/sidebar/user_menu}/user_menu.tsx +13 -9
- package/templates/apps/web/src/surfaces/todos/all_todos/all_todos.tsx +25 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/all_todos_controller.ts +47 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/bootstrap.ts +21 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/header/create.tsx +21 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/install.tsx +20 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/layout.tsx +35 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/create.tsx +47 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/main.tsx +68 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/new_todo_sheet/create.tsx +54 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/new_todo_sheet/new_todo_sheet.tsx +97 -0
- package/templates/apps/web/src/surfaces/todos/all_todos/main/new_todo_sheet/schema.ts +11 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/bootstrap.ts +35 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/header/create.tsx +24 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/header/header.tsx +25 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/install.tsx +27 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/layout.tsx +45 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/main/create.tsx +35 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/main/main.tsx +47 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/single_todo.tsx +27 -0
- package/templates/apps/web/src/surfaces/todos/single_todo/single_todo_controller.ts +16 -0
- package/templates/{react-router → apps/web}/vite.config.ts +27 -3
- package/templates/{_base/biome.json → biome.json} +12 -0
- package/templates/bun.lock +1917 -0
- package/templates/{_base/emails → emails}/project.json +1 -1
- package/templates/package.json +91 -0
- package/templates/{_base/shared → 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/{_base/shared → shared}/ui/src/hooks/use_mobile.tsx +1 -1
- package/templates/{_base/shared → shared}/ui/src/hooks/use_query_params.tsx +6 -7
- package/templates/{_base/shared → shared}/ui/tsconfig.json +1 -1
- package/templates/shared/utils/src/convex.ts +4 -0
- package/templates/{_base/tsconfig.base.json → tsconfig.base.json} +2 -1
- package/templates/_base/.cursor/commands/builder.md +0 -0
- package/templates/_base/.cursor/rules/api_architecture.mdc +0 -268
- package/templates/_base/.cursor/rules/coding_standards.mdc +0 -64
- package/templates/_base/.cursor/rules/convex_rules.mdc +0 -675
- package/templates/_base/.cursor/rules/frontend_rules.mdc +0 -268
- package/templates/_base/.env.convex.example +0 -3
- package/templates/_base/.github/workflows/ci.yml +0 -29
- package/templates/_base/_gitignore +0 -58
- package/templates/_base/package.json +0 -73
- package/templates/_base/shared/utils/src/convex.ts +0 -3
- package/templates/nextjs/.env.example +0 -8
- package/templates/nextjs/index.d.ts +0 -6
- package/templates/nextjs/next-env.d.ts +0 -5
- package/templates/nextjs/next.config.js +0 -22
- package/templates/nextjs/postcss.config.js +0 -17
- package/templates/nextjs/project.json +0 -22
- package/templates/nextjs/src/app/(auth)/layout.tsx +0 -21
- package/templates/nextjs/src/app/(auth)/not-allowed/page.tsx +0 -22
- package/templates/nextjs/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +0 -15
- package/templates/nextjs/src/app/(dashboard)/layout.tsx +0 -27
- package/templates/nextjs/src/app/(dashboard)/page.tsx +0 -5
- package/templates/nextjs/src/app/(dashboard)/todos/[id]/page.tsx +0 -23
- package/templates/nextjs/src/app/(dashboard)/todos/page.tsx +0 -16
- package/templates/nextjs/src/app/app.css +0 -3
- package/templates/nextjs/src/app/layout.tsx +0 -26
- package/templates/nextjs/src/convex.ts +0 -11
- package/templates/nextjs/src/middleware.ts +0 -18
- package/templates/nextjs/src/providers/convex_provider.tsx +0 -44
- package/templates/nextjs/src/surfaces/home_surface.tsx +0 -22
- package/templates/nextjs/src/surfaces/todos/all_todos_surface.tsx +0 -97
- package/templates/nextjs/src/surfaces/todos/create_todo_sheet.tsx +0 -107
- package/templates/nextjs/src/surfaces/todos/single_todo_surface.tsx +0 -90
- package/templates/nextjs/src/ui/sidebar/nav_link.tsx +0 -36
- package/templates/nextjs/src/ui/sidebar/sidebar.tsx +0 -125
- package/templates/nextjs/src/utils/font.ts +0 -9
- package/templates/nextjs/tsconfig.json +0 -42
- package/templates/react-router/.env.example +0 -8
- package/templates/react-router/src/app.css +0 -3
- package/templates/react-router/src/layouts/sidebar/sidebar_aside/sidebar_aside.tsx +0 -76
- package/templates/react-router/src/layouts/sidebar/sidebar_layout.tsx +0 -22
- package/templates/react-router/src/providers/api_auth_provider.tsx +0 -38
- package/templates/react-router/src/root.tsx +0 -37
- package/templates/react-router/src/routes/index.tsx +0 -9
- package/templates/react-router/src/routes/layout.tsx +0 -26
- package/templates/react-router/src/routes/todos/[id].tsx +0 -22
- package/templates/react-router/src/routes/todos/index.tsx +0 -13
- package/templates/react-router/src/routes.ts +0 -12
- package/templates/react-router/src/surfaces/home_surface.tsx +0 -20
- package/templates/react-router/src/surfaces/todos/all_todos_surface.tsx +0 -87
- package/templates/react-router/src/surfaces/todos/create_todo_sheet.tsx +0 -102
- package/templates/react-router/src/surfaces/todos/single_todo_surface.tsx +0 -81
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/api-specs-context.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/execute-request.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-endpoint-detail.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-tag-endpoints.sh +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-backend-api/scripts/extract-tags.js +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-in.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-2/custom-sign-up.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-in.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/custom-sign-up.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-custom-ui/core-3/show-component.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/api-routes.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/caching-auth.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/middleware-strategies.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/server-actions.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-nextjs-patterns/references/server-vs-client.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/clerk/clerk-webhooks/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/SKILL.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/agents/openai.yml +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/assets/shadcn-small.png +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/assets/shadcn.png +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/cli.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/customization.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/evals/evals.json +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/mcp.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/base-vs-radix.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/composition.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/forms.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/icons.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/agents/skills/shadcn/rules/styling.md +0 -0
- /package/templates/{_base/.cursor → .cursor}/commands/pr.md +0 -0
- /package/templates/{_base/.nvmrc → .nvmrc} +0 -0
- /package/templates/{_base/.vscode → .vscode}/settings.json +0 -0
- /package/templates/{_base/apps → apps}/api/auth.config.ts +0 -0
- /package/templates/{_base/apps → apps}/api/functions.ts +0 -0
- /package/templates/{_base/apps → apps}/api/project.json +0 -0
- /package/templates/{_base/apps → apps}/api/schema.ts +0 -0
- /package/templates/{_base/apps → apps}/api/todos/crud.ts +0 -0
- /package/templates/{_base/apps → apps}/api/todos/schema.ts +0 -0
- /package/templates/{_base/apps → apps}/api/todos/types.ts +0 -0
- /package/templates/{_base/apps → apps}/api/tsconfig.json +0 -0
- /package/templates/{_base/apps → apps}/api/types.ts +0 -0
- /package/templates/{react-router → apps/web}/postcss.config.js +0 -0
- /package/templates/{react-router → apps/web}/public/favicon.ico +0 -0
- /package/templates/{react-router/src/routes/auth/sign-in.tsx → apps/web/src/routes/(auth)/sign-in/index.tsx} +0 -0
- /package/templates/{react-router → apps/web}/tsconfig.json +0 -0
- /package/templates/{_base/convex.json → convex.json} +0 -0
- /package/templates/{_base/emails → emails}/tsconfig.json +0 -0
- /package/templates/{_base/emails → emails}/welcome_email.tsx +0 -0
- /package/templates/{_base/nx.json → nx.json} +0 -0
- /package/templates/{_base/scripts → scripts}/sync_convex_env.ts +0 -0
- /package/templates/{_base/shared → shared}/assets/image.d.ts +0 -0
- /package/templates/{_base/shared → shared}/assets/tsconfig.json +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/alert_dialog.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/badge.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/basic_data_table.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/button.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/button_group.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/card.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/checkbox.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/command.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/dialog.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/dropdown_menu.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/form.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/input.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/label.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/popover.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/radio_group.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/resizable.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/scroll_area.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/select.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/separator.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/sheet.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/side_bar.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/skeleton.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/spinner.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/switch.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/table.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/text_area.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/tooltip.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/base/utils.ts +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_keyboard_press.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_keyboard_release.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_mouse_click.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_mouse_location.tsx +0 -0
- /package/templates/{_base/shared → shared}/ui/src/hooks/use_outside_click.tsx +0 -0
- /package/templates/{_base/shared → shared}/utils/src/time.ts +0 -0
- /package/templates/{_base/shared → shared}/utils/tsconfig.json +0 -0
- /package/templates/{_base/skills-lock.json → skills-lock.json} +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
4
|
+
|
|
5
|
+
type Module = typeof import("../index.js")
|
|
6
|
+
|
|
7
|
+
type Info = GetInfo<{
|
|
8
|
+
file: "./routes/(auth)/sign-in/index.tsx",
|
|
9
|
+
module: Module
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Matches = [{
|
|
13
|
+
id: "root";
|
|
14
|
+
module: typeof import("../../../../root.js");
|
|
15
|
+
}, {
|
|
16
|
+
id: "routes/(auth)/layout";
|
|
17
|
+
module: typeof import("../../layout.js");
|
|
18
|
+
}, {
|
|
19
|
+
id: "routes/(auth)/sign-in/index";
|
|
20
|
+
module: typeof import("../index.js");
|
|
21
|
+
}];
|
|
22
|
+
|
|
23
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, false>;
|
|
24
|
+
|
|
25
|
+
export namespace Route {
|
|
26
|
+
// links
|
|
27
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
28
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
29
|
+
|
|
30
|
+
// meta
|
|
31
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
32
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
33
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
34
|
+
|
|
35
|
+
// headers
|
|
36
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
37
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
38
|
+
|
|
39
|
+
// middleware
|
|
40
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
41
|
+
|
|
42
|
+
// clientMiddleware
|
|
43
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
44
|
+
|
|
45
|
+
// loader
|
|
46
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
47
|
+
|
|
48
|
+
// clientLoader
|
|
49
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
50
|
+
|
|
51
|
+
// action
|
|
52
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
53
|
+
|
|
54
|
+
// clientAction
|
|
55
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
56
|
+
|
|
57
|
+
// HydrateFallback
|
|
58
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
59
|
+
|
|
60
|
+
// Component
|
|
61
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
62
|
+
|
|
63
|
+
// ErrorBoundary
|
|
64
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
65
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
4
|
+
|
|
5
|
+
type Module = typeof import("../[id].js")
|
|
6
|
+
|
|
7
|
+
type Info = GetInfo<{
|
|
8
|
+
file: "./routes/(dashboard)/(todos)/[id].tsx",
|
|
9
|
+
module: Module
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Matches = [{
|
|
13
|
+
id: "root";
|
|
14
|
+
module: typeof import("../../../../root.js");
|
|
15
|
+
}, {
|
|
16
|
+
id: "routes/(dashboard)/layout";
|
|
17
|
+
module: typeof import("../../layout.js");
|
|
18
|
+
}, {
|
|
19
|
+
id: "routes/(dashboard)/(todos)/layout";
|
|
20
|
+
module: typeof import("../layout.js");
|
|
21
|
+
}, {
|
|
22
|
+
id: "routes/(dashboard)/(todos)/[id]";
|
|
23
|
+
module: typeof import("../[id].js");
|
|
24
|
+
}];
|
|
25
|
+
|
|
26
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, false>;
|
|
27
|
+
|
|
28
|
+
export namespace Route {
|
|
29
|
+
// links
|
|
30
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
31
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
32
|
+
|
|
33
|
+
// meta
|
|
34
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
35
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
36
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
37
|
+
|
|
38
|
+
// headers
|
|
39
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
40
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
41
|
+
|
|
42
|
+
// middleware
|
|
43
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
44
|
+
|
|
45
|
+
// clientMiddleware
|
|
46
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
47
|
+
|
|
48
|
+
// loader
|
|
49
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
50
|
+
|
|
51
|
+
// clientLoader
|
|
52
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
53
|
+
|
|
54
|
+
// action
|
|
55
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
56
|
+
|
|
57
|
+
// clientAction
|
|
58
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
59
|
+
|
|
60
|
+
// HydrateFallback
|
|
61
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
62
|
+
|
|
63
|
+
// Component
|
|
64
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
65
|
+
|
|
66
|
+
// ErrorBoundary
|
|
67
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
68
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
4
|
+
|
|
5
|
+
type Module = typeof import("../index.js")
|
|
6
|
+
|
|
7
|
+
type Info = GetInfo<{
|
|
8
|
+
file: "./routes/(dashboard)/(todos)/index.tsx",
|
|
9
|
+
module: Module
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Matches = [{
|
|
13
|
+
id: "root";
|
|
14
|
+
module: typeof import("../../../../root.js");
|
|
15
|
+
}, {
|
|
16
|
+
id: "routes/(dashboard)/layout";
|
|
17
|
+
module: typeof import("../../layout.js");
|
|
18
|
+
}, {
|
|
19
|
+
id: "routes/(dashboard)/(todos)/layout";
|
|
20
|
+
module: typeof import("../layout.js");
|
|
21
|
+
}, {
|
|
22
|
+
id: "routes/(dashboard)/(todos)/index";
|
|
23
|
+
module: typeof import("../index.js");
|
|
24
|
+
}];
|
|
25
|
+
|
|
26
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, false>;
|
|
27
|
+
|
|
28
|
+
export namespace Route {
|
|
29
|
+
// links
|
|
30
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
31
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
32
|
+
|
|
33
|
+
// meta
|
|
34
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
35
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
36
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
37
|
+
|
|
38
|
+
// headers
|
|
39
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
40
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
41
|
+
|
|
42
|
+
// middleware
|
|
43
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
44
|
+
|
|
45
|
+
// clientMiddleware
|
|
46
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
47
|
+
|
|
48
|
+
// loader
|
|
49
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
50
|
+
|
|
51
|
+
// clientLoader
|
|
52
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
53
|
+
|
|
54
|
+
// action
|
|
55
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
56
|
+
|
|
57
|
+
// clientAction
|
|
58
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
59
|
+
|
|
60
|
+
// HydrateFallback
|
|
61
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
62
|
+
|
|
63
|
+
// Component
|
|
64
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
65
|
+
|
|
66
|
+
// ErrorBoundary
|
|
67
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
68
|
+
}
|
package/templates/apps/web/.react-router/types/src/routes/(dashboard)/(todos)/+types/layout.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
4
|
+
|
|
5
|
+
type Module = typeof import("../layout.js")
|
|
6
|
+
|
|
7
|
+
type Info = GetInfo<{
|
|
8
|
+
file: "./routes/(dashboard)/(todos)/layout.tsx",
|
|
9
|
+
module: Module
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Matches = [{
|
|
13
|
+
id: "root";
|
|
14
|
+
module: typeof import("../../../../root.js");
|
|
15
|
+
}, {
|
|
16
|
+
id: "routes/(dashboard)/layout";
|
|
17
|
+
module: typeof import("../../layout.js");
|
|
18
|
+
}, {
|
|
19
|
+
id: "routes/(dashboard)/(todos)/layout";
|
|
20
|
+
module: typeof import("../layout.js");
|
|
21
|
+
}];
|
|
22
|
+
|
|
23
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, false>;
|
|
24
|
+
|
|
25
|
+
export namespace Route {
|
|
26
|
+
// links
|
|
27
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
28
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
29
|
+
|
|
30
|
+
// meta
|
|
31
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
32
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
33
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
34
|
+
|
|
35
|
+
// headers
|
|
36
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
37
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
38
|
+
|
|
39
|
+
// middleware
|
|
40
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
41
|
+
|
|
42
|
+
// clientMiddleware
|
|
43
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
44
|
+
|
|
45
|
+
// loader
|
|
46
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
47
|
+
|
|
48
|
+
// clientLoader
|
|
49
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
50
|
+
|
|
51
|
+
// action
|
|
52
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
53
|
+
|
|
54
|
+
// clientAction
|
|
55
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
56
|
+
|
|
57
|
+
// HydrateFallback
|
|
58
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
59
|
+
|
|
60
|
+
// Component
|
|
61
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
62
|
+
|
|
63
|
+
// ErrorBoundary
|
|
64
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
65
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
4
|
+
|
|
5
|
+
type Module = typeof import("../index.js")
|
|
6
|
+
|
|
7
|
+
type Info = GetInfo<{
|
|
8
|
+
file: "./routes/(dashboard)/index.tsx",
|
|
9
|
+
module: Module
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Matches = [{
|
|
13
|
+
id: "root";
|
|
14
|
+
module: typeof import("../../../root.js");
|
|
15
|
+
}, {
|
|
16
|
+
id: "routes/(dashboard)/layout";
|
|
17
|
+
module: typeof import("../layout.js");
|
|
18
|
+
}, {
|
|
19
|
+
id: "routes/(dashboard)/index";
|
|
20
|
+
module: typeof import("../index.js");
|
|
21
|
+
}];
|
|
22
|
+
|
|
23
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, false>;
|
|
24
|
+
|
|
25
|
+
export namespace Route {
|
|
26
|
+
// links
|
|
27
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
28
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
29
|
+
|
|
30
|
+
// meta
|
|
31
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
32
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
33
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
34
|
+
|
|
35
|
+
// headers
|
|
36
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
37
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
38
|
+
|
|
39
|
+
// middleware
|
|
40
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
41
|
+
|
|
42
|
+
// clientMiddleware
|
|
43
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
44
|
+
|
|
45
|
+
// loader
|
|
46
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
47
|
+
|
|
48
|
+
// clientLoader
|
|
49
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
50
|
+
|
|
51
|
+
// action
|
|
52
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
53
|
+
|
|
54
|
+
// clientAction
|
|
55
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
56
|
+
|
|
57
|
+
// HydrateFallback
|
|
58
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
59
|
+
|
|
60
|
+
// Component
|
|
61
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
62
|
+
|
|
63
|
+
// ErrorBoundary
|
|
64
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
65
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Generated by React Router
|
|
2
|
+
|
|
3
|
+
import type { GetInfo, GetAnnotations } from "react-router/internal";
|
|
4
|
+
|
|
5
|
+
type Module = typeof import("../layout.js")
|
|
6
|
+
|
|
7
|
+
type Info = GetInfo<{
|
|
8
|
+
file: "./routes/(dashboard)/layout.tsx",
|
|
9
|
+
module: Module
|
|
10
|
+
}>
|
|
11
|
+
|
|
12
|
+
type Matches = [{
|
|
13
|
+
id: "root";
|
|
14
|
+
module: typeof import("../../../root.js");
|
|
15
|
+
}, {
|
|
16
|
+
id: "routes/(dashboard)/layout";
|
|
17
|
+
module: typeof import("../layout.js");
|
|
18
|
+
}];
|
|
19
|
+
|
|
20
|
+
type Annotations = GetAnnotations<Info & { module: Module, matches: Matches }, false>;
|
|
21
|
+
|
|
22
|
+
export namespace Route {
|
|
23
|
+
// links
|
|
24
|
+
export type LinkDescriptors = Annotations["LinkDescriptors"];
|
|
25
|
+
export type LinksFunction = Annotations["LinksFunction"];
|
|
26
|
+
|
|
27
|
+
// meta
|
|
28
|
+
export type MetaArgs = Annotations["MetaArgs"];
|
|
29
|
+
export type MetaDescriptors = Annotations["MetaDescriptors"];
|
|
30
|
+
export type MetaFunction = Annotations["MetaFunction"];
|
|
31
|
+
|
|
32
|
+
// headers
|
|
33
|
+
export type HeadersArgs = Annotations["HeadersArgs"];
|
|
34
|
+
export type HeadersFunction = Annotations["HeadersFunction"];
|
|
35
|
+
|
|
36
|
+
// middleware
|
|
37
|
+
export type MiddlewareFunction = Annotations["MiddlewareFunction"];
|
|
38
|
+
|
|
39
|
+
// clientMiddleware
|
|
40
|
+
export type ClientMiddlewareFunction = Annotations["ClientMiddlewareFunction"];
|
|
41
|
+
|
|
42
|
+
// loader
|
|
43
|
+
export type LoaderArgs = Annotations["LoaderArgs"];
|
|
44
|
+
|
|
45
|
+
// clientLoader
|
|
46
|
+
export type ClientLoaderArgs = Annotations["ClientLoaderArgs"];
|
|
47
|
+
|
|
48
|
+
// action
|
|
49
|
+
export type ActionArgs = Annotations["ActionArgs"];
|
|
50
|
+
|
|
51
|
+
// clientAction
|
|
52
|
+
export type ClientActionArgs = Annotations["ClientActionArgs"];
|
|
53
|
+
|
|
54
|
+
// HydrateFallback
|
|
55
|
+
export type HydrateFallbackProps = Annotations["HydrateFallbackProps"];
|
|
56
|
+
|
|
57
|
+
// Component
|
|
58
|
+
export type ComponentProps = Annotations["ComponentProps"];
|
|
59
|
+
|
|
60
|
+
// ErrorBoundary
|
|
61
|
+
export type ErrorBoundaryProps = Annotations["ErrorBoundaryProps"];
|
|
62
|
+
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "web",
|
|
3
3
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
-
"sourceRoot": "
|
|
4
|
+
"sourceRoot": "apps/web",
|
|
5
5
|
"projectType": "application",
|
|
6
6
|
"tags": [],
|
|
7
7
|
"targets": {
|
|
8
|
+
"typecheck": {
|
|
9
|
+
"executor": "nx:run-commands",
|
|
10
|
+
"options": {
|
|
11
|
+
"cwd": "apps/web",
|
|
12
|
+
"command": "bunx react-router typecheck"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
8
15
|
"dev": {
|
|
9
16
|
"executor": "nx:run-commands",
|
|
10
17
|
"options": {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright (c) SalesStar Limited 2026.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { Route } from "
|
|
5
|
+
import type { Route } from "../+types/root";
|
|
6
6
|
import { isRouteErrorResponse } from "react-router";
|
|
7
7
|
|
|
8
8
|
export const ErrorBoundary = ({ error }: Route.ErrorBoundaryProps) => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ConvexQueryClient } from "@convex-dev/react-query";
|
|
2
|
+
import { ConvexReactClient } from "convex/react";
|
|
3
|
+
|
|
4
|
+
const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string, {
|
|
5
|
+
expectAuth: true,
|
|
6
|
+
logger: true,
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
const convexQueryClient = new ConvexQueryClient(convex);
|
|
10
|
+
|
|
11
|
+
export { convex, convexQueryClient };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
import { convexQueryClient } from "@/web/libs/convex_query_client";
|
|
4
|
+
|
|
5
|
+
const reactQueryClient = new QueryClient({
|
|
6
|
+
defaultOptions: {
|
|
7
|
+
queries: {
|
|
8
|
+
queryFn: convexQueryClient.queryFn(),
|
|
9
|
+
gcTime: 0,
|
|
10
|
+
staleTime: 0,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
convexQueryClient.connect(reactQueryClient);
|
|
16
|
+
|
|
17
|
+
export { reactQueryClient };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getAuth } from "@clerk/react-router/server";
|
|
6
|
+
import { ConvexHttpClient } from "convex/browser";
|
|
7
|
+
import type { LoaderFunctionArgs } from "react-router";
|
|
8
|
+
import { redirect } from "react-router";
|
|
9
|
+
|
|
10
|
+
const CONVEX_URL = process.env.VITE_CONVEX_URL;
|
|
11
|
+
|
|
12
|
+
if (!CONVEX_URL) {
|
|
13
|
+
throw new Error("VITE_CONVEX_URL is not set");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const createConvexClient = async (args: LoaderFunctionArgs): Promise<ConvexHttpClient> => {
|
|
17
|
+
try {
|
|
18
|
+
const auth = await getAuth(args);
|
|
19
|
+
if (!auth.isAuthenticated) {
|
|
20
|
+
throw redirect(`/sign-in?redirect_url=${encodeURIComponent(args.request.url)}`);
|
|
21
|
+
}
|
|
22
|
+
const token = await auth.getToken({ template: "convex" });
|
|
23
|
+
const client = new ConvexHttpClient(CONVEX_URL);
|
|
24
|
+
if (token) {
|
|
25
|
+
client.setAuth(token);
|
|
26
|
+
}
|
|
27
|
+
return client;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error(error);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getAuth } from "@clerk/react-router/server";
|
|
2
|
+
import { type MiddlewareFunction, redirect } from "react-router";
|
|
3
|
+
|
|
4
|
+
const PUBLIC_ROUTES = ["/sign-in"];
|
|
5
|
+
|
|
6
|
+
export const protectedRoute: MiddlewareFunction<Response> = async ({ request, context }, next) => {
|
|
7
|
+
const { pathname } = new URL(request.url);
|
|
8
|
+
const isPublic = PUBLIC_ROUTES.some((route) => pathname.startsWith(route));
|
|
9
|
+
|
|
10
|
+
if (!isPublic) {
|
|
11
|
+
const auth = await getAuth({ request, context } as Parameters<typeof getAuth>[0]);
|
|
12
|
+
if (!auth.isAuthenticated) {
|
|
13
|
+
throw redirect(`/sign-in?redirect_url=${encodeURIComponent(request.url)}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return next();
|
|
17
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ClerkProvider, useAuth } from "@clerk/react-router";
|
|
6
|
+
import { QueryClientProvider } from "@tanstack/react-query";
|
|
7
|
+
import type { Route } from "apps/web/.react-router/types/src/+types/root";
|
|
8
|
+
import { ConvexProviderWithClerk } from "convex/react-clerk";
|
|
9
|
+
|
|
10
|
+
import { convex } from "@/web/libs/convex_query_client";
|
|
11
|
+
import { reactQueryClient } from "@/web/libs/react_query_client";
|
|
12
|
+
|
|
13
|
+
type ApiAuthProviderProps = {
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
loaderData: Route.ComponentProps["loaderData"];
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const ApiAuthProvider = ({ children, loaderData }: ApiAuthProviderProps) => {
|
|
19
|
+
return (
|
|
20
|
+
<ClerkProvider signInUrl="/sign-in" loaderData={loaderData}>
|
|
21
|
+
<ConvexProviderWithClerk client={convex} useAuth={useAuth}>
|
|
22
|
+
<QueryClientProvider client={reactQueryClient}>{children}</QueryClientProvider>
|
|
23
|
+
</ConvexProviderWithClerk>
|
|
24
|
+
</ClerkProvider>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ReactNode } from "react";
|
|
6
|
+
import { createContext, useContext } from "react";
|
|
7
|
+
|
|
8
|
+
export type GlobalContextValue = Record<string, never>;
|
|
9
|
+
|
|
10
|
+
const GlobalContext = createContext<GlobalContextValue | undefined>(undefined);
|
|
11
|
+
|
|
12
|
+
type GlobalProviderProps = {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const GlobalProvider = ({ children }: GlobalProviderProps) => {
|
|
17
|
+
return <GlobalContext.Provider value={{}}>{children}</GlobalContext.Provider>;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const useGlobal = (): GlobalContextValue => {
|
|
21
|
+
const context = useContext(GlobalContext);
|
|
22
|
+
|
|
23
|
+
if (context === undefined) {
|
|
24
|
+
throw new Error("useGlobal must be used within a GlobalProvider");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return context;
|
|
28
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Aron Weston 2026.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createContext, type ReactNode, useContext, useEffect, useMemo, useRef } from "react";
|
|
6
|
+
import { useNavigation } from "react-router";
|
|
7
|
+
import { LoadingBarContainer, useLoadingBar } from "react-top-loading-bar";
|
|
8
|
+
|
|
9
|
+
export type NavigationLoadingBarApi = {
|
|
10
|
+
start: () => void;
|
|
11
|
+
complete: () => void;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const NavigationLoadingBarContext = createContext<NavigationLoadingBarApi | null>(null);
|
|
15
|
+
|
|
16
|
+
type NavigationLoadingBarProviderProps = {
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const NavigationLoadingBarInner = ({ children }: NavigationLoadingBarProviderProps) => {
|
|
21
|
+
const navigation = useNavigation();
|
|
22
|
+
|
|
23
|
+
const { start, complete } = useLoadingBar({
|
|
24
|
+
color: "hsl(var(--primary))",
|
|
25
|
+
height: 2,
|
|
26
|
+
shadow: true,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const api = useMemo((): NavigationLoadingBarApi => {
|
|
30
|
+
return { start, complete };
|
|
31
|
+
}, [start, complete]);
|
|
32
|
+
|
|
33
|
+
const skippedInitialIdle = useRef(false);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (navigation.state !== "idle") {
|
|
37
|
+
start();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!skippedInitialIdle.current) {
|
|
42
|
+
skippedInitialIdle.current = true;
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
complete();
|
|
47
|
+
}, [navigation.state, start, complete]);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<NavigationLoadingBarContext.Provider value={api}>
|
|
51
|
+
{children}
|
|
52
|
+
</NavigationLoadingBarContext.Provider>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const NavigationLoadingBarProvider = ({ children }: NavigationLoadingBarProviderProps) => {
|
|
57
|
+
return (
|
|
58
|
+
<LoadingBarContainer>
|
|
59
|
+
<NavigationLoadingBarInner>{children}</NavigationLoadingBarInner>
|
|
60
|
+
</LoadingBarContainer>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export const useNavigationLoadingBar = (): NavigationLoadingBarApi => {
|
|
65
|
+
const ctx = useContext(NavigationLoadingBarContext);
|
|
66
|
+
|
|
67
|
+
if (!ctx) {
|
|
68
|
+
throw new Error("useNavigationLoadingBar must be used within NavigationLoadingBarProvider");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return ctx;
|
|
72
|
+
};
|