ZIP/WAREHOUSE/news.php
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>주요 뉴스 위젯</title>
    <!-- Tailwind CSS CDN -->
    <script src="https://cdn.tailwindcss.com"></script>
    <!-- React 및 Babel CDN -->
    <script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <style>
        @import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css');
        body { font-family: 'Pretendard', sans-serif; }
        .line-clamp-2 {
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }
        /* 스크롤바 숨기기 */
        .hide-scrollbar::-webkit-scrollbar { display: none; }
        .hide-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
    </style>
</head>
<body>
    <div id="root"></div>

    <script type="text/babel">
        const { useState, useEffect, useCallback } = React;

        // --- 아이콘 컴포넌트 ---
        const NewspaperIcon = ({ className }) => (
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
                <path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2Zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"></path>
                <path d="M18 14h-8"></path><path d="M15 18h-5"></path><path d="M10 6h8v4h-8V6Z"></path>
            </svg>
        );

        const ExternalLinkIcon = ({ className }) => (
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
                <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" x2="21" y1="14" y2="3"></line>
            </svg>
        );

        const RefreshIcon = ({ className }) => (
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
                <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path><path d="M21 3v5h-5"></path><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path><path d="M8 16H3v5"></path>
            </svg>
        );

        const ClockIcon = ({ className }) => (
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
                <circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline>
            </svg>
        );

        const ChevronRightIcon = ({ className }) => (
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
                <polyline points="9 18 15 12 9 6"></polyline>
            </svg>
        );

        function NewsWidget() {
            const [loading, setLoading] = useState(true);
            const [newsData, setNewsData] = useState([]);
            const [activeTab, setActiveTab] = useState('latest'); // 'latest' 또는 'popular'

            // 뉴스 데이터 가상 fetch 함수
            const fetchNews = useCallback(() => {
                setLoading(true);
                
                // 실제 환경에서는 API URL에 activeTab 파라미터를 실어 보냅니다.
                setTimeout(() => {
                    const mockData = {
                        latest: [
                            { id: 1, category: '경제', title: '코스피, 외인 매수세에 2600선 회복... 반도체주 강세', source: '경제일보', time: '방금 전', url: 'https://news.naver.com' },
                            { id: 2, category: 'IT/과학', title: '차세대 AI 모델 공개 임박, 업계 판도 바뀔까?', source: '테크뉴스', time: '12분 전', url: 'https://news.naver.com' },
                            { id: 3, category: '생활', title: '내일부터 전국 흐리고 비... 출근길 우산 챙기세요', source: '웨더뉴스', time: '45분 전', url: 'https://news.naver.com' }
                        ],
                        popular: [
                            { id: 10, category: '사회', title: '주말 고속도로 정체 극심... 평소보다 2시간 더 소요', source: '연합뉴스', time: '1시간 전', url: 'https://news.naver.com' },
                            { id: 11, category: '경제', title: '금리 동결 결정에 시장 안도... 환율 안정세', source: '금융신문', time: '2시간 전', url: 'https://news.naver.com' },
                            { id: 12, category: 'IT', title: '신형 스마트폰 사전예약 폭주... 재고 부족 우려', source: '디지털포커스', time: '3시간 전', url: 'https://news.naver.com' }
                        ]
                    };
                    
                    setNewsData(mockData[activeTab]);
                    setLoading(false);
                }, 600);
            }, [activeTab]);

            // 탭이 바뀌거나 처음 로드될 때 실행
            useEffect(() => {
                fetchNews();
            }, [fetchNews]);

            // 더보기 버튼 클릭 시 네이버 뉴스로 이동
            const handleMoreClick = () => {
                window.open('https://news.naver.com', '_blank');
            };

            return (
                <div className="min-h-screen bg-gradient-to-br from-gray-900 via-slate-900 to-black flex items-center justify-center p-4">
                    <div className="bg-gray-800 rounded-3xl shadow-2xl overflow-hidden max-w-sm w-full relative border border-gray-700 flex flex-col h-[520px]">
                        
                        {/* 헤더 섹션 */}
                        <div className="relative z-10 p-6 pb-4 bg-gray-800/90 backdrop-blur-md border-b border-gray-700">
                            <div className="flex justify-between items-center mb-4">
                                <div className="flex items-center space-x-2">
                                    <div className="p-2 bg-rose-500 rounded-lg shadow-lg shadow-rose-500/20">
                                        <NewspaperIcon className="w-5 h-5 text-white" />
                                    </div>
                                    <span className="text-white font-bold text-lg">주요 뉴스</span>
                                </div>
                                <button 
                                    onClick={fetchNews}
                                    disabled={loading}
                                    title="새로고침"
                                    className="p-2 hover:bg-gray-700 rounded-full transition-colors text-gray-400 hover:text-white"
                                >
                                    <RefreshIcon className={`w-4 h-4 ${loading ? 'animate-spin' : ''}`} />
                                </button>
                            </div>

                            {/* 탭 버튼 */}
                            <div className="flex space-x-1 bg-gray-700/50 p-1 rounded-xl">
                                <button 
                                    onClick={() => setActiveTab('latest')}
                                    className={`flex-1 py-1.5 text-xs font-medium rounded-lg transition-all ${
                                        activeTab === 'latest' ? 'bg-gray-600 text-white shadow-sm' : 'text-gray-400 hover:text-gray-200'
                                    }`}
                                >
                                    최신순
                                </button>
                                <button 
                                    onClick={() => setActiveTab('popular')}
                                    className={`flex-1 py-1.5 text-xs font-medium rounded-lg transition-all ${
                                        activeTab === 'popular' ? 'bg-gray-600 text-white shadow-sm' : 'text-gray-400 hover:text-gray-200'
                                    }`}
                                >
                                    많이 본 뉴스
                                </button>
                            </div>
                        </div>

                        {/* 리스트 섹션 */}
                        <div className="flex-1 overflow-y-auto p-4 space-y-3 hide-scrollbar">
                            {loading ? (
                                <div className="flex flex-col items-center justify-center h-full space-y-3">
                                    <div className="w-8 h-8 border-2 border-rose-500 border-t-transparent rounded-full animate-spin"></div>
                                    <span className="text-xs text-gray-500 font-medium">데이터를 가져오는 중...</span>
                                </div>
                            ) : (
                                newsData.map((news) => (
                                    <a 
                                        key={news.id} 
                                        href={news.url} 
                                        target="_blank"
                                        className="block group bg-gray-700/30 hover:bg-gray-700/60 rounded-xl p-4 transition-all duration-200 border border-gray-700/50 hover:border-gray-600 active:scale-[0.98]"
                                    >
                                        <div className="flex justify-between items-start mb-2">
                                            <span className="px-2 py-0.5 rounded-md bg-gray-600/50 text-gray-300 text-[10px] font-medium border border-gray-600">
                                                {news.category}
                                            </span>
                                            <ExternalLinkIcon className="w-3 h-3 text-gray-500 group-hover:text-rose-400 transition-colors" />
                                        </div>
                                        <h3 className="text-gray-100 font-semibold text-sm leading-snug mb-3 line-clamp-2 group-hover:text-rose-100 transition-colors">
                                            {news.title}
                                        </h3>
                                        <div className="flex items-center justify-between text-[11px] text-gray-500">
                                            <span className="font-medium text-gray-400">{news.source}</span>
                                            <div className="flex items-center space-x-1">
                                                <ClockIcon className="w-3 h-3" />
                                                <span>{news.time}</span>
                                            </div>
                                        </div>
                                    </a>
                                ))
                            )}
                        </div>

                        {/* 푸터 섹션 (더보기 버튼) */}
                        <div className="p-4 bg-gray-800 border-t border-gray-700">
                            <button 
                                onClick={handleMoreClick}
                                className="w-full py-2.5 flex items-center justify-center space-x-1 text-sm font-medium text-gray-400 hover:text-white bg-gray-700/40 hover:bg-gray-700 rounded-xl transition-all group"
                            >
                                <span>뉴스 더보기</span>
                                <ChevronRightIcon className="w-4 h-4 group-hover:translate-x-1 transition-transform" />
                            </button>
                        </div>
                    </div>
                </div>
            );
        }

        const root = ReactDOM.createRoot(document.getElementById('root'));
        root.render(<NewsWidget />);
    </script>
</body>
</html>