nipponboardspt 2.0.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/.lovable/plan/nippon-boards-landing-page-2026-09-22.md +27 -0
- package/.lovable/project.json +5 -0
- package/.prettierignore +8 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +10 -0
- package/README.md +134 -0
- package/bun.lock +1048 -0
- package/bunfig.toml +7 -0
- package/components.json +22 -0
- package/eslint.config.js +40 -0
- package/package.json +91 -0
- package/public/favicon.svg +7 -0
- package/public/robots.txt +14 -0
- package/roadmap.md +6 -0
- package/src/assets/nippon-ecu-bench.jpg +0 -0
- package/src/assets/nippon-hero-lab.jpg +0 -0
- package/src/assets/nippon-microsolder.jpg +0 -0
- package/src/components/Button.tsx +37 -0
- package/src/components/ui/accordion.tsx +51 -0
- package/src/components/ui/alert-dialog.tsx +115 -0
- package/src/components/ui/alert.tsx +49 -0
- package/src/components/ui/aspect-ratio.tsx +5 -0
- package/src/components/ui/avatar.tsx +47 -0
- package/src/components/ui/badge.tsx +32 -0
- package/src/components/ui/breadcrumb.tsx +101 -0
- package/src/components/ui/button.tsx +49 -0
- package/src/components/ui/calendar.tsx +177 -0
- package/src/components/ui/card.tsx +55 -0
- package/src/components/ui/carousel.tsx +240 -0
- package/src/components/ui/chart.tsx +331 -0
- package/src/components/ui/checkbox.tsx +26 -0
- package/src/components/ui/collapsible.tsx +11 -0
- package/src/components/ui/command.tsx +143 -0
- package/src/components/ui/context-menu.tsx +186 -0
- package/src/components/ui/dialog.tsx +104 -0
- package/src/components/ui/drawer.tsx +98 -0
- package/src/components/ui/dropdown-menu.tsx +187 -0
- package/src/components/ui/form.tsx +171 -0
- package/src/components/ui/hover-card.tsx +27 -0
- package/src/components/ui/input-otp.tsx +73 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +21 -0
- package/src/components/ui/menubar.tsx +228 -0
- package/src/components/ui/navigation-menu.tsx +120 -0
- package/src/components/ui/pagination.tsx +98 -0
- package/src/components/ui/popover.tsx +31 -0
- package/src/components/ui/progress.tsx +25 -0
- package/src/components/ui/radio-group.tsx +36 -0
- package/src/components/ui/resizable.tsx +37 -0
- package/src/components/ui/scroll-area.tsx +44 -0
- package/src/components/ui/select.tsx +152 -0
- package/src/components/ui/separator.tsx +24 -0
- package/src/components/ui/sheet.tsx +122 -0
- package/src/components/ui/sidebar.tsx +744 -0
- package/src/components/ui/skeleton.tsx +7 -0
- package/src/components/ui/slider.tsx +23 -0
- package/src/components/ui/sonner.tsx +23 -0
- package/src/components/ui/switch.tsx +27 -0
- package/src/components/ui/table.tsx +94 -0
- package/src/components/ui/tabs.tsx +53 -0
- package/src/components/ui/textarea.tsx +21 -0
- package/src/components/ui/toggle-group.tsx +57 -0
- package/src/components/ui/toggle.tsx +42 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/lib/error-capture.ts +81 -0
- package/src/lib/error-page.ts +30 -0
- package/src/lib/lovable-error-reporting.ts +59 -0
- package/src/lib/utils.ts +6 -0
- package/src/routeTree.gen.ts +69 -0
- package/src/router.tsx +16 -0
- package/src/routes/README.md +21 -0
- package/src/routes/__root.tsx +123 -0
- package/src/routes/index.tsx +314 -0
- package/src/server.ts +61 -0
- package/src/start.ts +29 -0
- package/src/styles.css +259 -0
- package/tsconfig.json +30 -0
- package/vite.config.ts +15 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as SliderPrimitive from "@radix-ui/react-slider";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
const Slider = React.forwardRef<
|
|
7
|
+
React.ElementRef<typeof SliderPrimitive.Root>,
|
|
8
|
+
React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
|
|
9
|
+
>(({ className, ...props }, ref) => (
|
|
10
|
+
<SliderPrimitive.Root
|
|
11
|
+
ref={ref}
|
|
12
|
+
className={cn("relative flex w-full touch-none select-none items-center", className)}
|
|
13
|
+
{...props}
|
|
14
|
+
>
|
|
15
|
+
<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
|
|
16
|
+
<SliderPrimitive.Range className="absolute h-full bg-primary" />
|
|
17
|
+
</SliderPrimitive.Track>
|
|
18
|
+
<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
|
|
19
|
+
</SliderPrimitive.Root>
|
|
20
|
+
));
|
|
21
|
+
Slider.displayName = SliderPrimitive.Root.displayName;
|
|
22
|
+
|
|
23
|
+
export { Slider };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Toaster as Sonner } from "sonner";
|
|
2
|
+
|
|
3
|
+
type ToasterProps = React.ComponentProps<typeof Sonner>;
|
|
4
|
+
|
|
5
|
+
const Toaster = ({ ...props }: ToasterProps) => {
|
|
6
|
+
return (
|
|
7
|
+
<Sonner
|
|
8
|
+
className="toaster group"
|
|
9
|
+
toastOptions={{
|
|
10
|
+
classNames: {
|
|
11
|
+
toast:
|
|
12
|
+
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
|
13
|
+
description: "group-[.toast]:text-muted-foreground",
|
|
14
|
+
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
|
15
|
+
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
|
16
|
+
},
|
|
17
|
+
}}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export { Toaster };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as SwitchPrimitives from "@radix-ui/react-switch";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
const Switch = React.forwardRef<
|
|
7
|
+
React.ElementRef<typeof SwitchPrimitives.Root>,
|
|
8
|
+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
|
|
9
|
+
>(({ className, ...props }, ref) => (
|
|
10
|
+
<SwitchPrimitives.Root
|
|
11
|
+
className={cn(
|
|
12
|
+
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
13
|
+
className,
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
ref={ref}
|
|
17
|
+
>
|
|
18
|
+
<SwitchPrimitives.Thumb
|
|
19
|
+
className={cn(
|
|
20
|
+
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
|
|
21
|
+
)}
|
|
22
|
+
/>
|
|
23
|
+
</SwitchPrimitives.Root>
|
|
24
|
+
));
|
|
25
|
+
Switch.displayName = SwitchPrimitives.Root.displayName;
|
|
26
|
+
|
|
27
|
+
export { Switch };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const Table = React.forwardRef<HTMLTableElement, React.HTMLAttributes<HTMLTableElement>>(
|
|
6
|
+
({ className, ...props }, ref) => (
|
|
7
|
+
<div className="relative w-full overflow-auto">
|
|
8
|
+
<table ref={ref} className={cn("w-full caption-bottom text-sm", className)} {...props} />
|
|
9
|
+
</div>
|
|
10
|
+
),
|
|
11
|
+
);
|
|
12
|
+
Table.displayName = "Table";
|
|
13
|
+
|
|
14
|
+
const TableHeader = React.forwardRef<
|
|
15
|
+
HTMLTableSectionElement,
|
|
16
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
17
|
+
>(({ className, ...props }, ref) => (
|
|
18
|
+
<thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
|
|
19
|
+
));
|
|
20
|
+
TableHeader.displayName = "TableHeader";
|
|
21
|
+
|
|
22
|
+
const TableBody = React.forwardRef<
|
|
23
|
+
HTMLTableSectionElement,
|
|
24
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
25
|
+
>(({ className, ...props }, ref) => (
|
|
26
|
+
<tbody ref={ref} className={cn("[&_tr:last-child]:border-0", className)} {...props} />
|
|
27
|
+
));
|
|
28
|
+
TableBody.displayName = "TableBody";
|
|
29
|
+
|
|
30
|
+
const TableFooter = React.forwardRef<
|
|
31
|
+
HTMLTableSectionElement,
|
|
32
|
+
React.HTMLAttributes<HTMLTableSectionElement>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<tfoot
|
|
35
|
+
ref={ref}
|
|
36
|
+
className={cn("border-t bg-muted/50 font-medium [&>tr]:last:border-b-0", className)}
|
|
37
|
+
{...props}
|
|
38
|
+
/>
|
|
39
|
+
));
|
|
40
|
+
TableFooter.displayName = "TableFooter";
|
|
41
|
+
|
|
42
|
+
const TableRow = React.forwardRef<HTMLTableRowElement, React.HTMLAttributes<HTMLTableRowElement>>(
|
|
43
|
+
({ className, ...props }, ref) => (
|
|
44
|
+
<tr
|
|
45
|
+
ref={ref}
|
|
46
|
+
className={cn(
|
|
47
|
+
"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
|
|
48
|
+
className,
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
TableRow.displayName = "TableRow";
|
|
55
|
+
|
|
56
|
+
const TableHead = React.forwardRef<
|
|
57
|
+
HTMLTableCellElement,
|
|
58
|
+
React.ThHTMLAttributes<HTMLTableCellElement>
|
|
59
|
+
>(({ className, ...props }, ref) => (
|
|
60
|
+
<th
|
|
61
|
+
ref={ref}
|
|
62
|
+
className={cn(
|
|
63
|
+
"h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
64
|
+
className,
|
|
65
|
+
)}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
));
|
|
69
|
+
TableHead.displayName = "TableHead";
|
|
70
|
+
|
|
71
|
+
const TableCell = React.forwardRef<
|
|
72
|
+
HTMLTableCellElement,
|
|
73
|
+
React.TdHTMLAttributes<HTMLTableCellElement>
|
|
74
|
+
>(({ className, ...props }, ref) => (
|
|
75
|
+
<td
|
|
76
|
+
ref={ref}
|
|
77
|
+
className={cn(
|
|
78
|
+
"p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
|
|
79
|
+
className,
|
|
80
|
+
)}
|
|
81
|
+
{...props}
|
|
82
|
+
/>
|
|
83
|
+
));
|
|
84
|
+
TableCell.displayName = "TableCell";
|
|
85
|
+
|
|
86
|
+
const TableCaption = React.forwardRef<
|
|
87
|
+
HTMLTableCaptionElement,
|
|
88
|
+
React.HTMLAttributes<HTMLTableCaptionElement>
|
|
89
|
+
>(({ className, ...props }, ref) => (
|
|
90
|
+
<caption ref={ref} className={cn("mt-4 text-sm text-muted-foreground", className)} {...props} />
|
|
91
|
+
));
|
|
92
|
+
TableCaption.displayName = "TableCaption";
|
|
93
|
+
|
|
94
|
+
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
3
|
+
|
|
4
|
+
import { cn } from "@/lib/utils";
|
|
5
|
+
|
|
6
|
+
const Tabs = TabsPrimitive.Root;
|
|
7
|
+
|
|
8
|
+
const TabsList = React.forwardRef<
|
|
9
|
+
React.ElementRef<typeof TabsPrimitive.List>,
|
|
10
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
|
11
|
+
>(({ className, ...props }, ref) => (
|
|
12
|
+
<TabsPrimitive.List
|
|
13
|
+
ref={ref}
|
|
14
|
+
className={cn(
|
|
15
|
+
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
|
16
|
+
className,
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
));
|
|
21
|
+
TabsList.displayName = TabsPrimitive.List.displayName;
|
|
22
|
+
|
|
23
|
+
const TabsTrigger = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
|
25
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
|
26
|
+
>(({ className, ...props }, ref) => (
|
|
27
|
+
<TabsPrimitive.Trigger
|
|
28
|
+
ref={ref}
|
|
29
|
+
className={cn(
|
|
30
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background cursor-pointer transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
));
|
|
36
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
|
37
|
+
|
|
38
|
+
const TabsContent = React.forwardRef<
|
|
39
|
+
React.ElementRef<typeof TabsPrimitive.Content>,
|
|
40
|
+
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
|
41
|
+
>(({ className, ...props }, ref) => (
|
|
42
|
+
<TabsPrimitive.Content
|
|
43
|
+
ref={ref}
|
|
44
|
+
className={cn(
|
|
45
|
+
"mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
/>
|
|
50
|
+
));
|
|
51
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
|
52
|
+
|
|
53
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import { cn } from "@/lib/utils";
|
|
4
|
+
|
|
5
|
+
const Textarea = React.forwardRef<HTMLTextAreaElement, React.ComponentProps<"textarea">>(
|
|
6
|
+
({ className, ...props }, ref) => {
|
|
7
|
+
return (
|
|
8
|
+
<textarea
|
|
9
|
+
className={cn(
|
|
10
|
+
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
11
|
+
className,
|
|
12
|
+
)}
|
|
13
|
+
ref={ref}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
Textarea.displayName = "Textarea";
|
|
20
|
+
|
|
21
|
+
export { Textarea };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
|
|
5
|
+
import { type VariantProps } from "class-variance-authority";
|
|
6
|
+
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
|
+
import { toggleVariants } from "@/components/ui/toggle";
|
|
9
|
+
|
|
10
|
+
const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
|
|
11
|
+
size: "default",
|
|
12
|
+
variant: "default",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const ToggleGroup = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root> &
|
|
18
|
+
VariantProps<typeof toggleVariants>
|
|
19
|
+
>(({ className, variant, size, children, ...props }, ref) => (
|
|
20
|
+
<ToggleGroupPrimitive.Root
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={cn("flex items-center justify-center gap-1", className)}
|
|
23
|
+
{...props}
|
|
24
|
+
>
|
|
25
|
+
<ToggleGroupContext.Provider value={{ variant, size }}>{children}</ToggleGroupContext.Provider>
|
|
26
|
+
</ToggleGroupPrimitive.Root>
|
|
27
|
+
));
|
|
28
|
+
|
|
29
|
+
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
|
|
30
|
+
|
|
31
|
+
const ToggleGroupItem = React.forwardRef<
|
|
32
|
+
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
|
|
33
|
+
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item> &
|
|
34
|
+
VariantProps<typeof toggleVariants>
|
|
35
|
+
>(({ className, children, variant, size, ...props }, ref) => {
|
|
36
|
+
const context = React.useContext(ToggleGroupContext);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<ToggleGroupPrimitive.Item
|
|
40
|
+
ref={ref}
|
|
41
|
+
className={cn(
|
|
42
|
+
toggleVariants({
|
|
43
|
+
variant: context.variant || variant,
|
|
44
|
+
size: context.size || size,
|
|
45
|
+
}),
|
|
46
|
+
className,
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
{children}
|
|
51
|
+
</ToggleGroupPrimitive.Item>
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
|
|
56
|
+
|
|
57
|
+
export { ToggleGroup, ToggleGroupItem };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import * as TogglePrimitive from "@radix-ui/react-toggle";
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
4
|
+
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
|
|
7
|
+
const toggleVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium cursor-pointer transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 disabled:cursor-not-allowed data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-transparent",
|
|
13
|
+
outline:
|
|
14
|
+
"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
default: "h-9 px-2 min-w-9",
|
|
18
|
+
sm: "h-8 px-1.5 min-w-8",
|
|
19
|
+
lg: "h-10 px-2.5 min-w-10",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
defaultVariants: {
|
|
23
|
+
variant: "default",
|
|
24
|
+
size: "default",
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const Toggle = React.forwardRef<
|
|
30
|
+
React.ElementRef<typeof TogglePrimitive.Root>,
|
|
31
|
+
React.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & VariantProps<typeof toggleVariants>
|
|
32
|
+
>(({ className, variant, size, ...props }, ref) => (
|
|
33
|
+
<TogglePrimitive.Root
|
|
34
|
+
ref={ref}
|
|
35
|
+
className={cn(toggleVariants({ variant, size, className }))}
|
|
36
|
+
{...props}
|
|
37
|
+
/>
|
|
38
|
+
));
|
|
39
|
+
|
|
40
|
+
Toggle.displayName = TogglePrimitive.Root.displayName;
|
|
41
|
+
|
|
42
|
+
export { Toggle, toggleVariants };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils";
|
|
7
|
+
|
|
8
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
9
|
+
|
|
10
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
11
|
+
|
|
12
|
+
const TooltipTrigger = TooltipPrimitive.Trigger;
|
|
13
|
+
|
|
14
|
+
const TooltipContent = React.forwardRef<
|
|
15
|
+
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
16
|
+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
|
17
|
+
>(({ className, sideOffset = 4, ...props }, ref) => (
|
|
18
|
+
<TooltipPrimitive.Portal>
|
|
19
|
+
<TooltipPrimitive.Content
|
|
20
|
+
ref={ref}
|
|
21
|
+
sideOffset={sideOffset}
|
|
22
|
+
className={cn(
|
|
23
|
+
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--radix-tooltip-content-transform-origin)",
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
</TooltipPrimitive.Portal>
|
|
29
|
+
));
|
|
30
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
31
|
+
|
|
32
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
const MOBILE_BREAKPOINT = 768;
|
|
4
|
+
|
|
5
|
+
export function useIsMobile() {
|
|
6
|
+
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined);
|
|
7
|
+
|
|
8
|
+
React.useEffect(() => {
|
|
9
|
+
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
|
|
10
|
+
const onChange = () => {
|
|
11
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
12
|
+
};
|
|
13
|
+
mql.addEventListener("change", onChange);
|
|
14
|
+
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
15
|
+
return () => mql.removeEventListener("change", onChange);
|
|
16
|
+
}, []);
|
|
17
|
+
|
|
18
|
+
return !!isMobile;
|
|
19
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Captures the original Error out-of-band so server.ts can recover the stack
|
|
2
|
+
// when h3 has already swallowed the throw into a generic 500 Response.
|
|
3
|
+
|
|
4
|
+
let lastCapturedError: { error: unknown; at: number } | undefined;
|
|
5
|
+
const TTL_MS = 5_000;
|
|
6
|
+
|
|
7
|
+
function record(error: unknown) {
|
|
8
|
+
lastCapturedError = { error, at: Date.now() };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// h3's HTTPError serializes to {"status":500,"unhandled":true,"message":"HTTPError"} —
|
|
12
|
+
// no stack, no cause — so a plain console.error(error) reaches the log pipeline with
|
|
13
|
+
// the failure detail stripped. Expand Error-like args into a string that keeps the
|
|
14
|
+
// message, stack, and the full cause chain.
|
|
15
|
+
const CAUSE_DEPTH_LIMIT = 5;
|
|
16
|
+
const DESCRIPTION_LENGTH_LIMIT = 8_000;
|
|
17
|
+
|
|
18
|
+
export function describeError(error: unknown): string {
|
|
19
|
+
const parts: string[] = [];
|
|
20
|
+
let current: unknown = error;
|
|
21
|
+
for (let depth = 0; depth < CAUSE_DEPTH_LIMIT && current != null; depth++) {
|
|
22
|
+
if (!(current instanceof Error)) {
|
|
23
|
+
parts.push(typeof current === "string" ? current : safeStringify(current));
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
const label = depth === 0 ? "" : "caused by: ";
|
|
27
|
+
const status = describeStatus(current);
|
|
28
|
+
parts.push(`${label}${current.stack ?? `${current.name}: ${current.message}`}${status}`);
|
|
29
|
+
current = current.cause;
|
|
30
|
+
}
|
|
31
|
+
return parts.join("\n").slice(0, DESCRIPTION_LENGTH_LIMIT);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function describeStatus(error: Error): string {
|
|
35
|
+
const { status, statusCode } = error as { status?: unknown; statusCode?: unknown };
|
|
36
|
+
const value = status ?? statusCode;
|
|
37
|
+
return typeof value === "number" ? ` (status ${value})` : "";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function safeStringify(value: unknown): string {
|
|
41
|
+
try {
|
|
42
|
+
return JSON.stringify(value) ?? String(value);
|
|
43
|
+
} catch {
|
|
44
|
+
return String(value);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isErrorLike(value: unknown): value is Error {
|
|
49
|
+
return value instanceof Error;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Wrap console.error so errors logged by any layer — including h3's internal
|
|
53
|
+
// unhandled-error logging, which this file cannot hook directly — are both
|
|
54
|
+
// recorded for consumeLastCapturedError and expanded before serialization.
|
|
55
|
+
const originalConsoleError = console.error.bind(console);
|
|
56
|
+
console.error = (...args: unknown[]) => {
|
|
57
|
+
const expanded = args.map((arg) => {
|
|
58
|
+
if (!isErrorLike(arg)) return arg;
|
|
59
|
+
record(arg);
|
|
60
|
+
return describeError(arg);
|
|
61
|
+
});
|
|
62
|
+
originalConsoleError(...expanded);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
if (typeof globalThis.addEventListener === "function") {
|
|
66
|
+
globalThis.addEventListener("error", (event) => record((event as ErrorEvent).error ?? event));
|
|
67
|
+
globalThis.addEventListener("unhandledrejection", (event) =>
|
|
68
|
+
record((event as PromiseRejectionEvent).reason),
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function consumeLastCapturedError(): unknown {
|
|
73
|
+
if (!lastCapturedError) return undefined;
|
|
74
|
+
if (Date.now() - lastCapturedError.at > TTL_MS) {
|
|
75
|
+
lastCapturedError = undefined;
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const { error } = lastCapturedError;
|
|
79
|
+
lastCapturedError = undefined;
|
|
80
|
+
return error;
|
|
81
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export function renderErrorPage(): string {
|
|
2
|
+
return `<!doctype html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<title>This page didn't load</title>
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
8
|
+
<style>
|
|
9
|
+
body { font: 15px/1.5 system-ui, -apple-system, sans-serif; background: #fafafa; color: #111; display: grid; place-items: center; min-height: 100vh; margin: 0; padding: 1.5rem; }
|
|
10
|
+
.card { max-width: 28rem; width: 100%; text-align: center; padding: 2rem; }
|
|
11
|
+
h1 { font-size: 1.25rem; margin: 0 0 0.5rem; }
|
|
12
|
+
p { color: #4b5563; margin: 0 0 1.5rem; }
|
|
13
|
+
.actions { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; }
|
|
14
|
+
a, button { padding: 0.5rem 1rem; border-radius: 0.375rem; font: inherit; cursor: pointer; text-decoration: none; border: 1px solid transparent; }
|
|
15
|
+
.primary { background: #111; color: #fff; }
|
|
16
|
+
.secondary { background: #fff; color: #111; border-color: #d1d5db; }
|
|
17
|
+
</style>
|
|
18
|
+
</head>
|
|
19
|
+
<body>
|
|
20
|
+
<div class="card">
|
|
21
|
+
<h1>This page didn't load</h1>
|
|
22
|
+
<p>Something went wrong on our end. You can try refreshing or head back home.</p>
|
|
23
|
+
<div class="actions">
|
|
24
|
+
<button class="primary" onclick="location.reload()">Try again</button>
|
|
25
|
+
<a class="secondary" href="/">Go home</a>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</body>
|
|
29
|
+
</html>`;
|
|
30
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
type LovableErrorOptions = {
|
|
2
|
+
mechanism?: "manual" | "onerror" | "unhandledrejection" | "react_error_boundary";
|
|
3
|
+
handled?: boolean;
|
|
4
|
+
severity?: "error" | "warning" | "info";
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type LovableEvents = {
|
|
8
|
+
track?: (event: string, properties?: Record<string, unknown>) => string | null;
|
|
9
|
+
captureException?: (
|
|
10
|
+
error: unknown,
|
|
11
|
+
context?: Record<string, unknown>,
|
|
12
|
+
options?: LovableErrorOptions,
|
|
13
|
+
) => void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
declare global {
|
|
17
|
+
interface Window {
|
|
18
|
+
__lovableEvents?: LovableEvents;
|
|
19
|
+
__lovableReportRuntimeError?: (payload: {
|
|
20
|
+
message: string;
|
|
21
|
+
stack?: string;
|
|
22
|
+
filename?: string;
|
|
23
|
+
}) => void;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function reportLovableError(error: unknown, context: Record<string, unknown> = {}) {
|
|
28
|
+
if (typeof window === "undefined") return;
|
|
29
|
+
window.__lovableEvents?.captureException?.(
|
|
30
|
+
error,
|
|
31
|
+
{
|
|
32
|
+
source: "react_error_boundary",
|
|
33
|
+
route: window.location.pathname,
|
|
34
|
+
...context,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
mechanism: "react_error_boundary",
|
|
38
|
+
handled: false,
|
|
39
|
+
severity: "error",
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
// Prod React does not rethrow boundary-caught errors to window.onerror, so the
|
|
43
|
+
// editor's telemetry never sees them. Forward to lovable.js's reporting hook,
|
|
44
|
+
// which is present only inside the editor preview.
|
|
45
|
+
// Loaders and server fns commonly throw a raw Response; String(it) is the
|
|
46
|
+
// opaque "[object Response]", so pull out the status and URL instead.
|
|
47
|
+
const message =
|
|
48
|
+
error instanceof Response
|
|
49
|
+
? `Response ${error.status}${error.url ? ` at ${error.url}` : ""}`
|
|
50
|
+
: error instanceof Error
|
|
51
|
+
? error.message
|
|
52
|
+
: String(error);
|
|
53
|
+
const stack = error instanceof Error ? error.stack : undefined;
|
|
54
|
+
window.__lovableReportRuntimeError?.({
|
|
55
|
+
message,
|
|
56
|
+
...(stack !== undefined && { stack }),
|
|
57
|
+
filename: window.location.pathname,
|
|
58
|
+
});
|
|
59
|
+
}
|
package/src/lib/utils.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
// @ts-nocheck
|
|
4
|
+
|
|
5
|
+
// noinspection JSUnusedGlobalSymbols
|
|
6
|
+
|
|
7
|
+
// This file was automatically generated by TanStack Router.
|
|
8
|
+
// You should NOT make any changes in this file as it will be overwritten.
|
|
9
|
+
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
|
|
10
|
+
|
|
11
|
+
import { Route as rootRouteImport } from './routes/__root'
|
|
12
|
+
import { Route as IndexRouteImport } from './routes/index'
|
|
13
|
+
|
|
14
|
+
const IndexRoute = IndexRouteImport.update({
|
|
15
|
+
id: '/',
|
|
16
|
+
path: '/',
|
|
17
|
+
getParentRoute: () => rootRouteImport,
|
|
18
|
+
} as any)
|
|
19
|
+
|
|
20
|
+
export interface FileRoutesByFullPath {
|
|
21
|
+
'/': typeof IndexRoute
|
|
22
|
+
}
|
|
23
|
+
export interface FileRoutesByTo {
|
|
24
|
+
'/': typeof IndexRoute
|
|
25
|
+
}
|
|
26
|
+
export interface FileRoutesById {
|
|
27
|
+
__root__: typeof rootRouteImport
|
|
28
|
+
'/': typeof IndexRoute
|
|
29
|
+
}
|
|
30
|
+
export interface FileRouteTypes {
|
|
31
|
+
fileRoutesByFullPath: FileRoutesByFullPath
|
|
32
|
+
fullPaths: '/'
|
|
33
|
+
fileRoutesByTo: FileRoutesByTo
|
|
34
|
+
to: '/'
|
|
35
|
+
id: '__root__' | '/'
|
|
36
|
+
fileRoutesById: FileRoutesById
|
|
37
|
+
}
|
|
38
|
+
export interface RootRouteChildren {
|
|
39
|
+
IndexRoute: typeof IndexRoute
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
declare module '@tanstack/react-router' {
|
|
43
|
+
interface FileRoutesByPath {
|
|
44
|
+
'/': {
|
|
45
|
+
id: '/'
|
|
46
|
+
path: '/'
|
|
47
|
+
fullPath: '/'
|
|
48
|
+
preLoaderRoute: typeof IndexRouteImport
|
|
49
|
+
parentRoute: typeof rootRouteImport
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const rootRouteChildren: RootRouteChildren = {
|
|
55
|
+
IndexRoute: IndexRoute,
|
|
56
|
+
}
|
|
57
|
+
export const routeTree = rootRouteImport
|
|
58
|
+
._addFileChildren(rootRouteChildren)
|
|
59
|
+
._addFileTypes<FileRouteTypes>()
|
|
60
|
+
|
|
61
|
+
import type { getRouter } from './router.tsx'
|
|
62
|
+
import type { startInstance } from './start.ts'
|
|
63
|
+
declare module '@tanstack/react-start' {
|
|
64
|
+
interface Register {
|
|
65
|
+
ssr: true
|
|
66
|
+
router: Awaited<ReturnType<typeof getRouter>>
|
|
67
|
+
config: Awaited<ReturnType<typeof startInstance.getOptions>>
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/router.tsx
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { createRouter } from "@tanstack/react-router";
|
|
3
|
+
import { routeTree } from "./routeTree.gen";
|
|
4
|
+
|
|
5
|
+
export const getRouter = () => {
|
|
6
|
+
const queryClient = new QueryClient();
|
|
7
|
+
|
|
8
|
+
const router = createRouter({
|
|
9
|
+
routeTree,
|
|
10
|
+
context: { queryClient },
|
|
11
|
+
scrollRestoration: true,
|
|
12
|
+
defaultPreloadStaleTime: 0,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return router;
|
|
16
|
+
};
|