@@ -19,35 +19,86 @@ const seriesPosts = posts
1919 });
2020---
2121
22- {
23- seriesPosts .length > 0 && (
24- <nav class = " series-container mb-8 p-4 bg-[var(--color-bg-secondary)] rounded-lg border border-[var(--color-border)]" aria-label = { ` Series: ${series } ` } >
25- <h3 class = " text-sm font-bold uppercase tracking-wider text-[var(--color-text-secondary)] mb-3" >
26- Series: { series }
27- </h3 >
28- <ul class = " space-y-2" >
29- { seriesPosts .map ((post ) => {
30- const isCurrent = post .slug === currentSlug ;
31- return (
32- <li class = " flex items-start gap-2" >
33- <span class = " mt-1.5 w-1.5 h-1.5 rounded-full bg-[var(--color-text-secondary)] flex-shrink-0 opacity-50" />
34- { isCurrent ? (
35- <span class = " text-sm font-medium text-[var(--color-accent)]" >
36- { post .data .title }
37- <span class = " ml-2 text-xs text-[var(--color-text-secondary)] font-normal" >(Current)</span >
38- </span >
39- ) : (
40- <a
41- href = { ` /blog/${post .slug } ` }
42- class = " text-sm text-[var(--color-text)] hover:text-[var(--color-accent)] transition-colors"
43- >
44- { post .data .title }
45- </a >
46- )}
47- </li >
48- );
49- })}
50- </ul >
51- </nav >
52- )
53- }
22+ { seriesPosts .length > 0 && (
23+ <details
24+ id = " series-nav"
25+ data-series = { series }
26+ open
27+ class = " mb-8 rounded-lg border border-[var(--color-border)] bg-[var(--color-bg-secondary)] overflow-hidden"
28+ >
29+ <summary class = " series-summary flex items-center justify-between gap-4 px-4 py-3 cursor-pointer select-none hover:bg-[var(--color-border)]/20 transition-colors" >
30+ <span class = " text-sm font-bold uppercase tracking-wider text-[var(--color-text-secondary)]" >
31+ 시리즈: { series }
32+ <span class = " ml-1.5 font-normal normal-case tracking-normal" >({ seriesPosts .length } 편)</span >
33+ </span >
34+ <svg
35+ class = " series-chevron w-4 h-4 text-[var(--color-text-secondary)] transition-transform duration-200 flex-shrink-0"
36+ viewBox = " 0 0 24 24"
37+ fill = " none"
38+ stroke = " currentColor"
39+ stroke-width = " 2"
40+ stroke-linecap = " round"
41+ stroke-linejoin = " round"
42+ aria-hidden = " true"
43+ >
44+ <polyline points = " 6 9 12 15 18 9" />
45+ </svg >
46+ </summary >
47+ <ol class = " space-y-2 px-4 pb-4 pt-1" type = " 1" >
48+ { seriesPosts .map ((post ) => {
49+ const isCurrent = post .slug === currentSlug ;
50+ return (
51+ <li class = " flex items-start gap-2" >
52+ <span class = " mt-1.5 w-1.5 h-1.5 rounded-full bg-[var(--color-text-secondary)] flex-shrink-0 opacity-50" />
53+ { isCurrent ? (
54+ <span class = " text-sm font-medium text-[var(--color-accent)]" >
55+ { post .data .title }
56+ <span class = " ml-2 text-xs text-[var(--color-text-secondary)] font-normal" >(현재)</span >
57+ </span >
58+ ) : (
59+ <a
60+ href = { ` /blog/${post .slug } ` }
61+ class = " text-sm text-[var(--color-text)] hover:text-[var(--color-accent)] transition-colors"
62+ >
63+ { post .data .title }
64+ </a >
65+ )}
66+ </li >
67+ );
68+ })}
69+ </ol >
70+ </details >
71+ )}
72+
73+ <style >
74+ .series-summary {
75+ list-style: none;
76+ }
77+ .series-summary::-webkit-details-marker {
78+ display: none;
79+ }
80+ </style >
81+
82+ <script >
83+ const el = document.getElementById("series-nav") as HTMLDetailsElement | null;
84+ if (el) {
85+ const key = `series-open:${el.dataset.series ?? ""}`;
86+ const chevron = el.querySelector(".series-chevron") as SVGElement | null;
87+
88+ function syncChevron(open: boolean) {
89+ if (chevron) chevron.style.transform = open ? "rotate(180deg)" : "";
90+ }
91+
92+ // sessionStorage는 탭 세션 내 뒤로가기/앞으로가기 전체에서 유지됨
93+ const saved = sessionStorage.getItem(key);
94+ if (saved !== null) {
95+ el.open = saved === "true";
96+ }
97+ syncChevron(el.open);
98+
99+ el.addEventListener("toggle", () => {
100+ sessionStorage.setItem(key, String(el.open));
101+ syncChevron(el.open);
102+ });
103+ }
104+ </script >
0 commit comments