Redesign blog as desktop OS
All checks were successful
Deploy blog-frontend / build-and-deploy (push) Successful in 2m10s

This commit is contained in:
박원엽
2026-05-29 09:46:00 +09:00
parent ab585b5faa
commit 7f9bc1f83b
24 changed files with 1016 additions and 592 deletions

View File

@@ -0,0 +1,70 @@
import { clsx } from 'clsx';
import { HTMLAttributes, ReactNode } from 'react';
type WindowSurfaceElement = 'div' | 'section' | 'article' | 'aside' | 'main';
interface WindowSurfaceProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
as?: WindowSurfaceElement;
title?: ReactNode;
subtitle?: ReactNode;
controls?: ReactNode;
showTrafficLights?: boolean;
bodyClassName?: string;
}
export default function WindowSurface({
as: Component = 'section',
title,
subtitle,
controls,
showTrafficLights = true,
className,
bodyClassName,
children,
...props
}: WindowSurfaceProps) {
const hasTitlebar = Boolean(title || subtitle || controls || showTrafficLights);
return (
<Component
className={clsx(
'overflow-hidden rounded-lg border border-[var(--window-border)] bg-[var(--window-bg)] shadow-[var(--shadow-window)] backdrop-blur-2xl',
className,
)}
{...props}
>
{hasTitlebar && (
<div className="flex min-h-11 items-center justify-between gap-4 border-b border-[var(--color-line)] bg-[var(--window-titlebar)] px-4 py-2.5">
<div className="flex min-w-0 items-center gap-3">
{showTrafficLights && (
<div className="flex shrink-0 items-center gap-1.5" aria-hidden="true">
<span className="h-3 w-3 rounded-full border border-black/10 bg-[#ff5f57]" />
<span className="h-3 w-3 rounded-full border border-black/10 bg-[#ffbd2e]" />
<span className="h-3 w-3 rounded-full border border-black/10 bg-[#28c840]" />
</div>
)}
{(title || subtitle) && (
<div className="min-w-0">
{title && (
<div className="truncate text-sm font-semibold text-[var(--color-text)]">
{title}
</div>
)}
{subtitle && (
<div className="truncate text-xs font-medium text-[var(--color-text-subtle)]">
{subtitle}
</div>
)}
</div>
)}
</div>
{controls && <div className="shrink-0">{controls}</div>}
</div>
)}
<div className={bodyClassName}>{children}</div>
</Component>
);
}