import { useState, useRef, useEffect } from 'react'; import type { HistoryEntry } from '../types'; interface UrlInputProps { onLoad: (url: string) => void; isLoading: boolean; needsAttention: boolean; error: string | null; } const HISTORY_KEY = 'mana-viewer-history'; function getHistory(): HistoryEntry[] { try { return JSON.parse(localStorage.getItem(HISTORY_KEY) || '[]'); } catch { return []; } } function saveHistory(entry: HistoryEntry) { const history = getHistory().filter((h) => h.url !== entry.url); history.unshift(entry); localStorage.setItem(HISTORY_KEY, JSON.stringify(history.slice(0, 20))); } export function UrlInput({ onLoad, isLoading, needsAttention, error, }: UrlInputProps) { const [url, setUrl] = useState(''); const [history, setHistory] = useState(getHistory); const inputRef = useRef(null); useEffect(() => { inputRef.current?.focus(); }, []); const handleLoad = () => { if (!url.trim()) return; saveHistory({ url, title: url, timestamp: Date.now() }); setHistory(getHistory()); onLoad(url); }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') handleLoad(); }; return (
{isLoading && (
e.stopPropagation()}>
{needsAttention ? '열린 창에서 사이트 인증(캡차/로그인 등)을 완료해주세요.' : '챕터를 불러오는 중...'}
)}
{/* Logo / Hero */}
마나 뷰어

만화 URL을 입력하면 쾌적한 뷰어로 읽을 수 있습니다

{/* URL Input */}
setUrl(e.target.value)} onKeyDown={handleKeyDown} disabled={isLoading} />
{/* Needs-attention hint: the site's own challenge (Cloudflare/login/etc.) is being shown in a real browser window for the user to solve. */} {isLoading && needsAttention && (
열린 창에서 사이트 인증(캡차/로그인 등)을 완료해주세요.
)} {/* Error display */} {error && (
{error}
)}
{/* History */} {history.length > 0 && (

최근 본 만화

{history.map((entry) => { const displayTitle = entry.chapterTitle || (entry.title && entry.title !== entry.url ? entry.title : null); return (
); })}
)} {/* Hint */}
페이지 이동 F 전체화면 S 설정
); }