File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 2424 "@resolid/app-log" : " workspace:^" ,
2525 "@resolid/app-log-file" : " workspace:^" ,
2626 "@resolid/core" : " workspace:^" ,
27- "@resolid/react-ui" : " https://pkg.pr.new/resolid/react-ui/@resolid/react-ui@9ac19f2 " ,
27+ "@resolid/react-ui" : " https://pkg.pr.new/resolid/react-ui/@resolid/react-ui@bea86da " ,
2828 "@tailwindcss/typography" : " ^0.5.19" ,
2929 "@vercel/analytics" : " ^1.6.1" ,
3030 "@vercel/functions" : " ^3.3.6" ,
3131 "@vercel/speed-insights" : " ^1.3.1" ,
3232 "isbot" : " ^5.1.32" ,
33- "mysql2" : " ^3.16.0 " ,
33+ "mysql2" : " ^3.16.1 " ,
3434 "react" : " ^19.2.3" ,
3535 "react-dom" : " ^19.2.3" ,
3636 "react-router" : " ^7.12.0" ,
4242 "@tailwindcss/vite" : " ^4.1.18" ,
4343 "@types/react" : " ^19.2.8" ,
4444 "@types/react-dom" : " ^19.2.3" ,
45+ "babel-plugin-react-compiler" : " ^1.0.0" ,
4546 "vite" : " ^7.3.1" ,
47+ "vite-bundle-analyzer" : " ^1.3.2" ,
48+ "vite-plugin-babel" : " ^1.4.1" ,
4649 "vite-plugin-inspect" : " ^11.3.3" ,
4750 "vite-tsconfig-paths" : " ^6.0.4"
4851 },
Original file line number Diff line number Diff line change 1+ import {
2+ Button ,
3+ type ColorMode ,
4+ DropdownMenu ,
5+ DropdownMenuArrow ,
6+ DropdownMenuContent ,
7+ DropdownMenuItem ,
8+ DropdownMenuTrigger ,
9+ useColorModeDispatch ,
10+ useColorModeState ,
11+ } from "@resolid/react-ui" ;
12+ import { SpriteIcon } from "~/components/sprite-icon" ;
13+
14+ const colorModes = {
15+ light : {
16+ label : "亮色模式" ,
17+ icon : "sun" ,
18+ } ,
19+ dark : {
20+ label : "暗色模式" ,
21+ icon : "moon" ,
22+ } ,
23+ auto : {
24+ label : "跟随系统" ,
25+ icon : "auto" ,
26+ } ,
27+ } ;
28+
29+ export const ColorModeToggle = ( ) => {
30+ const colorMode = useColorModeState ( ) ;
31+ const setColorMode = useColorModeDispatch ( ) ;
32+
33+ return (
34+ < DropdownMenu placement = { "bottom" } >
35+ < DropdownMenuTrigger
36+ render = { ( props ) => (
37+ < Button
38+ aria-label = { "颜色模式" }
39+ color = { "neutral" }
40+ variant = { "ghost" }
41+ size = { "sm" }
42+ iconOnly
43+ { ...props }
44+ />
45+ ) }
46+ >
47+ < SpriteIcon size = { "1.325em" } name = { colorModes [ colorMode ] ?. icon } />
48+ </ DropdownMenuTrigger >
49+ < DropdownMenuContent className = { "text-sm" } >
50+ < DropdownMenuArrow />
51+ { Object . entries ( colorModes ) . map ( ( [ key , mode ] ) => {
52+ return (
53+ < DropdownMenuItem
54+ key = { key }
55+ label = { key }
56+ className = { colorMode == key ? "text-link" : "" }
57+ onSelect = { ( ) => {
58+ setColorMode ( key as ColorMode ) ;
59+ } }
60+ >
61+ < SpriteIcon name = { mode . icon } className = { "me-1.5" } />
62+ { mode . label }
63+ </ DropdownMenuItem >
64+ ) ;
65+ } ) }
66+ </ DropdownMenuContent >
67+ </ DropdownMenu >
68+ ) ;
69+ } ;
Original file line number Diff line number Diff line change 1+ import { isRouteErrorResponse } from "react-router" ;
2+ import { HistoryBack } from "~/components/history-link" ;
3+
4+ export type ErrorComponentProps = { error : unknown } ;
5+
6+ export const ErrorComponent = ( { error } : ErrorComponentProps ) => {
7+ if ( isRouteErrorResponse ( error ) && error . status == 404 ) {
8+ return (
9+ < div className = { "relative mx-auto flex max-w-144 justify-center px-4 py-8" } >
10+ < svg
11+ className = { "absolute inset-x-4 top-20 fill-fg-normal/5" }
12+ xmlns = "http://www.w3.org/2000/svg"
13+ viewBox = "0 0 362 145"
14+ >
15+ < path d = "M62.6 142c-2.133 0-3.2-1.067-3.2-3.2V118h-56c-2 0-3-1-3-3V92.8c0-1.333.4-2.733 1.2-4.2L58.2 4c.8-1.333 2.067-2 3.8-2h28c2 0 3 1 3 3v85.4h11.2c.933 0 1.733.333 2.4 1 .667.533 1 1.267 1 2.2v21.2c0 .933-.333 1.733-1 2.4-.667.533-1.467.8-2.4.8H93v20.8c0 2.133-1.067 3.2-3.2 3.2H62.6zM33 90.4h26.4V51.2L33 90.4zm148.67 54.2c-7.333 0-14.333-1.333-21-4-6.666-2.667-12.866-6.733-18.6-12.2-5.733-5.467-10.266-13-13.6-22.6-3.333-9.6-5-20.667-5-33.2 0-12.533 1.667-23.6 5-33.2 3.334-9.6 7.867-17.133 13.6-22.6 5.734-5.467 11.934-9.533 18.6-12.2 6.667-2.8 13.667-4.2 21-4.2 7.467 0 14.534 1.4 21.2 4.2 6.667 2.667 12.8 6.733 18.4 12.2 5.734 5.467 10.267 13 13.6 22.6 3.334 9.6 5 20.667 5 33.2 0 12.533-1.666 23.6-5 33.2-3.333 9.6-7.866 17.133-13.6 22.6-5.6 5.467-11.733 9.533-18.4 12.2-6.666 2.667-13.733 4-21.2 4zm0-31c9.067 0 15.6-3.733 19.6-11.2 4.134-7.6 6.2-17.533 6.2-29.8s-2.066-22.2-6.2-29.8c-4.133-7.6-10.666-11.4-19.6-11.4-8.933 0-15.466 3.8-19.6 11.4-4 7.6-6 17.533-6 29.8s2 22.2 6 29.8c4.134 7.467 10.667 11.2 19.6 11.2zM316.116 142c-2.134 0-3.2-1.067-3.2-3.2V118h-56c-2 0-3-1-3-3V92.8c0-1.333.4-2.733 1.2-4.2l56.6-84.6c.8-1.333 2.066-2 3.8-2h28c2 0 3 1 3 3v85.4h11.2c.933 0 1.733.333 2.4 1 .666.533 1 1.267 1 2.2v21.2c0 .933-.334 1.733-1 2.4-.667.533-1.467.8-2.4.8h-11.2v20.8c0 2.133-1.067 3.2-3.2 3.2h-27.2zm-29.6-51.6h26.4V51.2l-26.4 39.2z" />
16+ </ svg >
17+ < div className = { "z-base prose mt-32 max-w-144 text-center dark:prose-invert" } >
18+ < h1 > { error . data } </ h1 >
19+ < p >
20+ 您尝试打开的页面不存在。您可能输入了错误的地址,或该页面已被移动到另一个
21+ URL。如果您认为这是一个错误,请联系支持。
22+ </ p >
23+ < div className = { "not-prose mt-12" } >
24+ < HistoryBack />
25+ </ div >
26+ </ div >
27+ </ div >
28+ ) ;
29+ }
30+
31+ if ( error instanceof Error ) {
32+ return (
33+ < div className = { "max-w-2xl mx-auto prose px-4 py-8 dark:prose-invert" } >
34+ < h1 className = { "text-center" } > 发生了错误</ h1 >
35+ < p > { error . message } </ p >
36+ < p > 堆栈跟踪:</ p >
37+ < pre className = { "scrollbar scrollbar-base max-h-60" } > { error . stack } </ pre >
38+ < div className = { "not-prose mt-12 text-center" } >
39+ < HistoryBack />
40+ </ div >
41+ </ div >
42+ ) ;
43+ }
44+
45+ return (
46+ < div className = { "max-w-2xl mx-auto prose px-4 py-8 dark:prose-invert" } >
47+ < h1 className = { "text-center" } > 未知错误</ h1 >
48+ < p className = { "text-center" } > 您尝试打开的页面发生了未知的错误,请联系支持。</ p >
49+ < div className = { "not-prose mt-12 text-center" } >
50+ < HistoryBack />
51+ </ div >
52+ </ div >
53+ ) ;
54+ } ;
Original file line number Diff line number Diff line change 1+ import { startTransition , StrictMode } from "react" ;
2+ import { hydrateRoot } from "react-dom/client" ;
3+ import { HydratedRouter } from "react-router/dom" ;
4+
5+ startTransition ( ( ) => {
6+ hydrateRoot (
7+ document ,
8+ < StrictMode >
9+ < HydratedRouter unstable_useTransitions />
10+ </ StrictMode > ,
11+ ) ;
12+ } ) ;
Original file line number Diff line number Diff line change 77 TooltipTrigger ,
88} from "@resolid/react-ui" ;
99import { Link , Outlet } from "react-router" ;
10+ import { ColorModeToggle } from "~/components/color-mode-toggle" ;
1011import { HistoryLink } from "~/components/history-link" ;
1112import { ResolidLogo } from "~/components/resolid-logo" ;
1213import { ResolidUiLogo } from "~/components/resolid-ui-logo" ;
@@ -21,6 +22,7 @@ export default function SiteLayout() {
2122 < ResolidLogo />
2223 </ Link >
2324 < div className = { "inline-flex items-center gap-1 text-fg-muted" } >
25+ < ColorModeToggle />
2426 < Tooltip placement = { "bottom" } >
2527 < TooltipTrigger
2628 render = { ( props ) => (
Original file line number Diff line number Diff line change 11import { ConfigProvider } from "@resolid/react-ui" ;
22import type { PropsWithChildren } from "react" ;
33import { Outlet , Scripts , ScrollRestoration } from "react-router" ;
4+ import { ErrorComponent } from "~/components/error-component" ;
45import { RouteProcessBar } from "~/components/route-process-bar" ;
56import { VercelAnalytics } from "~/extensions/vercel/vercel-analytics" ;
67import { VercelSpeedInsights } from "~/extensions/vercel/vercel-speed-insights" ;
@@ -47,6 +48,8 @@ export const Layout = ({ children }: PropsWithChildren) => {
4748 ) ;
4849} ;
4950
51+ export const ErrorBoundary = ErrorComponent ;
52+
5053export default function Root ( ) {
5154 return < Outlet /> ;
5255}
You can’t perform that action at this time.
0 commit comments