11import snapshot from "../data/homeSnapshot.json" ;
2- import { civicSections , getTaxWatchMovementArticles } from "../data/civicSections" ;
3- import { ArrowRight , ChevronLeft , ChevronRight , Clock , Megaphone } from "lucide-react" ;
2+ import { ArrowRight , ChevronLeft , ChevronRight , Clock } from "lucide-react" ;
43import { useEffect , useState , type CSSProperties , type ReactNode } from "react" ;
54import { Link } from "react-router-dom" ;
65import FeaturedStoryMedia from "../components/FeaturedStoryMedia" ;
@@ -229,17 +228,20 @@ export default function Home() {
229228 seedLanguageCandidates . sort ( ( a , b ) => newestInSection ( { path : `/seed-language/${ a . slug } ` , date : a . date } , { path : `/seed-language/${ b . slug } ` , date : b . date } ) ) ;
230229 // Reserve the lead and existing desks before the historical carousel.
231230 const claimedHomePaths = new Set ( activeFeaturedPath ? [ getHomeTopic ( activeFeaturedPath ) ] : [ ] ) ;
232- const civicSidebarItems = civicSections . filter ( ( section ) => section . key !== "notices" ) . map ( ( section ) => {
233- if ( section . key === "campaign" ) {
234- const path = "/briefings/korean-civic-tax-watch-movement-ktr" ;
235- claimedHomePaths . add ( getHomeTopic ( path ) ) ;
236- return { section, article : featuredCandidates . find ( ( item ) => item . path === path ) } ;
237- }
238- const sectionArticles = getTaxWatchMovementArticles ( language , featuredCandidates ) ;
239- const article = [ ...sectionArticles ] . sort ( newestInSection ) . find ( ( item ) => ! claimedHomePaths . has ( getHomeTopic ( item . path ) ) ) ;
240- if ( article ) claimedHomePaths . add ( getHomeTopic ( article . path ) ) ;
241- return { section, article } ;
242- } ) ;
231+ // Keep the right rail focused on No More Tax commentary; serialized ATR
232+ // chapters are already available in the dedicated Editorial Series section.
233+ // The shared published-content registry prevents drafts from appearing here.
234+ const noMoreTaxSidebarPaths = new Set ( [
235+ "/columns/no-more-tax-increases-civic-declaration-2026" ,
236+ "/columns/france-fiscal-crisis-korea-spending-no-more-tax-2026" ,
237+ "/columns/jangjado-future-response-fund-no-more-tax-2026" ,
238+ "/briefings/korean-civic-tax-watch-movement-ktr" ,
239+ ] ) ;
240+ const noMoreTaxSidebarArticles = featuredCandidates
241+ . filter ( ( article ) => noMoreTaxSidebarPaths . has ( article . path ) && ! claimedHomePaths . has ( getHomeTopic ( article . path ) ) )
242+ . sort ( newestInSection )
243+ . slice ( 0 , 2 ) ;
244+ noMoreTaxSidebarArticles . forEach ( ( article ) => claimedHomePaths . add ( getHomeTopic ( article . path ) ) ) ;
243245 const seedLanguageArticle = claimFirstUnseen (
244246 seedLanguageCandidates ,
245247 ( item ) => `/seed-language/${ item . slug } ` ,
@@ -269,7 +271,7 @@ export default function Home() {
269271
270272 const upperArticlePaths = new Set ( [
271273 activeFeaturedPath ,
272- ...civicSidebarItems . map ( ( item ) => item . article ? .path ) ,
274+ ...noMoreTaxSidebarArticles . map ( ( article ) => article . path ) ,
273275 seedLanguageArticle ? `/seed-language/${ seedLanguageArticle . slug } ` : undefined ,
274276 ...visibleHotIssueCards . map ( ( card ) => card . to ) ,
275277 ...newsTrackingCards . map ( ( card ) => card . to ) ,
@@ -482,10 +484,8 @@ export default function Home() {
482484 < p className = "mt-3 text-sm text-charcoal/55" > { ko ? "오늘의 기사를 불러오고 있습니다." : "Loading today’s story." } </ p >
483485 </ div >
484486 ) }
485- < aside className = "divide-y divide-green-deep/15 border-y border-green-deep/20 xl:flex xl:h-full xl:flex-col xl:border-t-0" aria-label = { ko ? "시민운동과 시민언어" : "Civic action and language" } >
486- { civicSidebarItems . map ( ( { section, article } ) => {
487- if ( section . key === "campaign" ) return (
488- < div key = { section . key } className = "relative my-3 xl:mb-3 xl:mt-0" >
487+ < aside className = "divide-y divide-green-deep/15 border-y border-green-deep/20 xl:flex xl:h-full xl:flex-col xl:border-t-0" aria-label = { ko ? "No More Tax 운동과 시민언어" : "No More Tax campaign and civic language" } >
488+ < div className = "relative my-3 xl:mb-3 xl:mt-0" >
489489 < Link to = "/civic-campaign#campaign-signature" aria-label = { ko ? "NO MORE TAX! 증세 반대 서명페이지로 이동" : "NO MORE TAX! Go to the petition page" } className = "group block overflow-hidden bg-navy transition-opacity hover:opacity-90 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-green-deep" >
490490 < SafeImage
491491 src = { resolveImageSrc ( "/images/civic/no-more-tax-fiscal-balloon-banner.webp" ) }
@@ -501,24 +501,29 @@ export default function Home() {
501501 { ko ? "No More Tax 운동 소개·서명" : "No More Tax campaign and petition" } < ArrowRight size = { 14 } aria-hidden = "true" />
502502 </ Link >
503503 < Link to = "/tax-watch-movement" className = "inline-flex items-center gap-1 underline underline-offset-4 hover:text-green-mid" >
504- { ko ? "세금감시운동 활동 기록 " : "Tax watch movement reports " } < ArrowRight size = { 14 } aria-hidden = "true" />
504+ { ko ? "운동 관련 기사 전체보기 " : "All campaign coverage " } < ArrowRight size = { 14 } aria-hidden = "true" />
505505 </ Link >
506506 </ nav >
507507 </ div >
508- ) ;
509- const title = article ?. title ?? section . title [ language ] ;
510- const summary = article ?. summary ?? section . description [ language ] ;
511- return < Link key = { section . key } to = { article ?. path ?? section . path } className = "group cursor-pointer transition-colors duration-200 hover:bg-green-deep/5 focus-visible:bg-green-deep/5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-deep grid grid-cols-[96px_minmax(0,1fr)] gap-3 py-3.5 sm:grid-cols-[120px_minmax(0,1fr)] sm:gap-4 xl:flex-1 xl:grid-cols-[112px_minmax(0,1fr)] xl:content-start xl:py-3 xl:first:pt-0" >
512- < div className = "flex items-center justify-center overflow-hidden bg-green-deep text-white" >
513- { article ? < SafeImage src = { resolveImageSrc ( article . image . src ) } alt = { article . image . alt } className = "aspect-[4/3] h-full max-h-[110px] w-full object-cover" /> : < Megaphone size = { 34 } aria-hidden = "true" className = "my-6" /> }
508+ { noMoreTaxSidebarArticles . length > 0 && (
509+ < div className = "py-3" >
510+ < div className = "flex items-center justify-between gap-3 pb-1" >
511+ < h2 className = "text-xs font-black tracking-[.06em] text-green-deep" > { ko ? "NO MORE TAX · 관련 기사" : "NO MORE TAX · CAMPAIGN COVERAGE" } </ h2 >
512+ < Link to = "/tax-watch-movement" className = "shrink-0 text-xs font-bold text-green-deep underline underline-offset-4 hover:text-green-mid" > { ko ? "더보기" : "More" } </ Link >
514513 </ div >
515- < div className = "min-w-0" >
516- < p className = "text-sm font-black text-green-deep" > { section . title [ language ] } { section . key === "cases" && article ?. path . match ( / t a x p a y e r - m o v e m e n t - ( \d { 2 } ) - / ) && < span className = "ml-1.5" aria-label = { ko ? `연재 ${ Number ( article . path . match ( / t a x p a y e r - m o v e m e n t - ( \d { 2 } ) - / ) ! [ 1 ] ) } 편` : `Part ${ Number ( article . path . match ( / t a x p a y e r - m o v e m e n t - ( \d { 2 } ) - / ) ! [ 1 ] ) } ` } > { String . fromCodePoint ( 0x245f + Number ( article . path . match ( / t a x p a y e r - m o v e m e n t - ( \d { 2 } ) - / ) ! [ 1 ] ) ) } </ span > } </ p >
517- < h2 className = "editorial-title mt-1 line-clamp-2 break-keep text-[1.02rem] font-bold leading-snug text-navy transition-colors group-hover:text-green-mid group-focus-visible:text-green-mid sm:text-[1.08rem]" > { title } </ h2 >
518- < p className = "home-compact-summary mt-1 line-clamp-2" > { summary } </ p >
514+ < div className = "divide-y divide-green-deep/15" >
515+ { noMoreTaxSidebarArticles . map ( ( article ) => (
516+ < Link key = { article . path } to = { article . path } className = "group grid min-w-0 grid-cols-[96px_minmax(0,1fr)] gap-3 py-2.5 transition-colors hover:bg-green-deep/5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-deep sm:grid-cols-[120px_minmax(0,1fr)] xl:grid-cols-[112px_minmax(0,1fr)]" >
517+ < SafeImage src = { resolveImageSrc ( article . image . src ) } alt = { article . image . alt } loading = "lazy" className = "aspect-[4/3] w-full object-cover" />
518+ < div className = "min-w-0" >
519+ < h3 className = "editorial-title line-clamp-2 break-keep text-[1.02rem] font-bold leading-snug text-navy transition-colors group-hover:text-green-mid sm:text-[1.08rem]" > { article . title } </ h3 >
520+ < p className = "home-compact-summary mt-1 line-clamp-2" > { article . summary } </ p >
521+ </ div >
522+ </ Link >
523+ ) ) }
519524 </ div >
520- </ Link > ;
521- } ) }
525+ </ div >
526+ ) }
522527 { seedLanguageArticle && (
523528 < Link to = { `/seed-language/${ seedLanguageArticle . slug } ` } className = "group cursor-pointer transition-colors duration-200 hover:bg-green-deep/5 focus-visible:bg-green-deep/5 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-deep grid grid-cols-[96px_minmax(0,1fr)] gap-3 py-3.5 sm:grid-cols-[120px_minmax(0,1fr)] sm:gap-4 xl:flex-1 xl:grid-cols-[112px_minmax(0,1fr)] xl:content-start xl:py-3" >
524529 < div className = "relative flex aspect-[4/3] h-full max-h-[96px] w-full flex-col items-center justify-center overflow-hidden border border-green-deep/20 bg-green-deep text-center" style = { { containerType : "inline-size" } } >
0 commit comments