diff --git a/app/api/news.py b/app/api/news.py index 6da312a..3823870 100644 --- a/app/api/news.py +++ b/app/api/news.py @@ -4,7 +4,7 @@ from typing import Annotated from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel -from sqlalchemy import select +from sqlalchemy import String, select from sqlalchemy.ext.asyncio import AsyncSession from core.auth import get_current_user @@ -116,7 +116,12 @@ async def list_articles( Document.deleted_at == None, ) if source: - query = query.where(Document.ai_sub_group == source) + if '/' in source: + # 신문사/분야 형태 → ai_tags로 필터 + query = query.where(Document.ai_tags.cast(String).contains(source)) + else: + # 신문사만 → ai_sub_group + query = query.where(Document.ai_sub_group == source) if unread_only: query = query.where(Document.is_read == False) diff --git a/frontend/src/routes/news/+page.svelte b/frontend/src/routes/news/+page.svelte index d2df3c0..434d4d0 100644 --- a/frontend/src/routes/news/+page.svelte +++ b/frontend/src/routes/news/+page.svelte @@ -20,18 +20,23 @@ let selectedArticle = $state(null); let filterSource = $state(''); let showUnreadOnly = $state(false); - let sources = $state([]); + let sourceTree = $state({}); // { 경향신문: ['문화', '사회'], NYT: ['World'] } let currentPage = $state(1); let noteEditing = $state(false); let noteText = $state(''); + let expandedSources = $state({}); onMount(async () => { try { const srcData = await api('/news/sources'); - // 신문사별 유니크 - const names = new Set(); - srcData.forEach(s => names.add(s.name.split(' ')[0])); - sources = [...names]; + const tree = {}; + srcData.forEach(s => { + const paper = s.name.split(' ')[0]; + const cat = s.category || ''; + if (!tree[paper]) tree[paper] = []; + if (cat && !tree[paper].includes(cat)) tree[paper].push(cat); + }); + sourceTree = tree; } catch (e) {} loadArticles(); }); @@ -127,11 +132,26 @@ class="w-full text-left px-2 py-1.5 rounded text-sm mb-1 {filterSource === '' ? 'bg-[var(--accent)]/15 text-[var(--accent)]' : 'text-[var(--text-dim)] hover:bg-[var(--surface)]'}" >📰 전체 - {#each sources as src} - + {#each Object.entries(sourceTree) as [paper, categories]} +