70 lines
1.8 KiB
React
70 lines
1.8 KiB
React
import { Button } from "./ui/button.jsx";
|
|
|
|
/**
|
|
* @param {{
|
|
* eyebrow: string,
|
|
* title: string,
|
|
* description: string,
|
|
* actionLabel?: string,
|
|
* onAction?: () => void,
|
|
* tone?: "neutral" | "danger" | "warning"
|
|
* }} props
|
|
*/
|
|
function StateSurface({
|
|
eyebrow,
|
|
title,
|
|
description,
|
|
actionLabel,
|
|
onAction,
|
|
tone = "neutral",
|
|
}) {
|
|
return (
|
|
<section className={`state-surface state-surface--${tone}`}>
|
|
<p className="state-surface__eyebrow">{eyebrow}</p>
|
|
<h2>{title}</h2>
|
|
<p>{description}</p>
|
|
{actionLabel ? <Button onClick={onAction}>{actionLabel}</Button> : null}
|
|
</section>
|
|
);
|
|
}
|
|
|
|
/** @param {{ onSignIn?: () => void }} props */
|
|
export function AuthRequiredSurface({ onSignIn }) {
|
|
return (
|
|
<StateSurface
|
|
eyebrow="401 · 인증 필요"
|
|
title="로그인이 필요합니다."
|
|
description="세션을 시작한 뒤 이전 작업을 안전하게 계속할 수 있습니다."
|
|
actionLabel="로그인 시작"
|
|
onAction={onSignIn}
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** @param {{ onNavigate?: () => void }} props */
|
|
export function ForbiddenSurface({ onNavigate }) {
|
|
return (
|
|
<StateSurface
|
|
eyebrow="403 · 권한 없음"
|
|
title="접근할 수 없습니다."
|
|
description="권한을 확인하거나 접근 가능한 화면으로 이동하세요."
|
|
actionLabel="안전한 화면으로 이동"
|
|
onAction={onNavigate}
|
|
tone="warning"
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** @param {{ onNavigate?: () => void }} props */
|
|
export function NotFoundSurface({ onNavigate }) {
|
|
return (
|
|
<StateSurface
|
|
eyebrow="404 · 찾을 수 없음"
|
|
title="요청한 화면이 없습니다."
|
|
description="주소를 확인하거나 시작 화면으로 돌아가세요."
|
|
actionLabel="시작 화면으로 이동"
|
|
onAction={onNavigate}
|
|
/>
|
|
);
|
|
}
|