여러 줄 주석이 설명보다 경위(예전·실측·지적)를 적고 있어 읽는 사람이 결론을 찾기 어려웠다. - ts·tsx·js·mjs·css·py 478개: 여러 줄 주석은 첫 문장 한 줄로, 과거형·날짜 문장은 삭제 - 주석 위치는 TypeScript 파서·파이썬 tokenize/ast 로 찾는다 — 문자열 안의 # · /* 는 건드리지 않는다 - eslint·ts·noqa·type: ignore 같은 지시 주석은 그대로 둔다 파이썬 275개 정리 전후 AST 동일, TS 298개 주석 뺀 토큰 동일(빈 JSX 주석 10곳만 차이). site·frontend·admin tsc, site vitest 105 passed Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
import {isRouteErrorResponse, Links, Meta, Outlet, Scripts, ScrollRestoration} from 'react-router';
|
|
import type {LinksFunction, MetaFunction} from 'react-router';
|
|
import {Providers} from '@/app/provider';
|
|
import './index.css';
|
|
|
|
/** 문서 껍데기. */
|
|
const PUBLISH_HOST = import.meta.env.VITE_PUBLISH_HOST || 'web4ai.o2osolution.ai';
|
|
export const ORIGIN = `https://${PUBLISH_HOST}`;
|
|
|
|
export const links: LinksFunction = () => [
|
|
{rel: 'icon', type: 'image/png', sizes: '32x32', href: '/brand/favicon-w4a.png'},
|
|
{rel: 'icon', type: 'image/svg+xml', href: '/brand/favicon-w4a.svg?v=14'},
|
|
// self-host Pretendard 가 어떤 환경에서든 못 뜰 때 한글이 굴림/맑은고딕으로 떨어지지 않게 하는 안전망
|
|
{rel: 'preconnect', href: 'https://fonts.googleapis.com'},
|
|
{rel: 'preconnect', href: 'https://fonts.gstatic.com', crossOrigin: 'anonymous'},
|
|
{
|
|
rel: 'stylesheet',
|
|
href: 'https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300..900&family=Noto+Serif+KR:wght@400;600;700&display=swap',
|
|
},
|
|
// 7080 아이템(가요 다방·일력·승차권) 전용.
|
|
{
|
|
rel: 'stylesheet',
|
|
href: 'https://fonts.googleapis.com/css2?family=Gugi&family=Gowun+Batang:wght@400;700&family=Nanum+Pen+Script&display=swap',
|
|
},
|
|
];
|
|
|
|
/** 라우트가 자기 것을 안 내놓을 때의 기본값. */
|
|
export const meta: MetaFunction = () => [
|
|
{title: 'Web4Ai'},
|
|
{property: 'og:site_name', content: 'Web4Ai'},
|
|
{property: 'og:locale', content: 'ko_KR'},
|
|
{property: 'og:type', content: 'website'},
|
|
{name: 'twitter:card', content: 'summary_large_image'},
|
|
];
|
|
|
|
export function Layout({children}: {children: React.ReactNode}) {
|
|
return (
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charSet="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
<meta name="theme-color" content="#1463ff" />
|
|
<Meta />
|
|
<Links />
|
|
</head>
|
|
<body>
|
|
{children}
|
|
<ScrollRestoration />
|
|
<Scripts />
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
|
|
export default function Root() {
|
|
return (
|
|
<Providers>
|
|
<Outlet />
|
|
</Providers>
|
|
);
|
|
}
|
|
|
|
export function ErrorBoundary({error}: {error: unknown}) {
|
|
const is404 = isRouteErrorResponse(error) && error.status === 404;
|
|
return (
|
|
<div className="flex min-h-screen flex-col items-center justify-center gap-3 px-6 text-center">
|
|
<p className="text-5xl font-extrabold tracking-tight">{is404 ? '404' : '오류'}</p>
|
|
<p className="text-muted-foreground">
|
|
{is404 ? '없는 주소입니다.' : '화면을 그리는 중 문제가 생겼습니다.'}
|
|
</p>
|
|
<a href="/" className="underline underline-offset-4">
|
|
홈으로
|
|
</a>
|
|
</div>
|
|
);
|
|
}
|