게시물 상세 사이드바 목차·광고 재배치와 세션 확인 개선
게시물 상세에서는 오른쪽 사이드에 목차와 광고를 배치하고, 비로그인 세션 확인 시 콘솔 401 로그가 나지 않도록 정리했다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -15,6 +15,8 @@ const { data: siteSettings } = await useFetch('/api/site-settings', {
|
||||
logoText: '井',
|
||||
logoUrl: '',
|
||||
socialLinks: [],
|
||||
adSidebarCode: '',
|
||||
adPostSidebarCode: '',
|
||||
copyrightText: '©2026 sori.studio'
|
||||
})
|
||||
})
|
||||
@@ -39,7 +41,7 @@ const recommendedSites = computed(() => {
|
||||
return list.filter((x) => x?.isVisible !== false)
|
||||
})
|
||||
const isPostDetailRoute = computed(() => route.path.startsWith('/post/'))
|
||||
const sidebarAdCode = computed(() => isPostDetailRoute.value ? '' : siteSettings.value?.adSidebarCode)
|
||||
const sidebarAdCode = computed(() => isPostDetailRoute.value ? siteSettings.value?.adPostSidebarCode : siteSettings.value?.adSidebarCode)
|
||||
const postTocItems = computed(() => Array.isArray(postToc.value) ? postToc.value : [])
|
||||
const followLinks = computed(() => getVisibleSocialLinks(siteSettings.value?.socialLinks || []))
|
||||
|
||||
@@ -100,20 +102,23 @@ const scrollActiveTocIntoView = (id) => {
|
||||
}
|
||||
|
||||
const nav = tocNavRef.value
|
||||
const scrollContainer = nav.closest('.site-sidebar-scroll')
|
||||
const link = nav.querySelector(`[data-toc-id="${id}"]`)
|
||||
|
||||
if (!(link instanceof HTMLElement)) {
|
||||
if (!(link instanceof HTMLElement) || !(scrollContainer instanceof HTMLElement)) {
|
||||
return
|
||||
}
|
||||
|
||||
const navTop = nav.scrollTop
|
||||
const navBottom = navTop + nav.clientHeight
|
||||
const linkTop = link.offsetTop
|
||||
const containerRect = scrollContainer.getBoundingClientRect()
|
||||
const linkRect = link.getBoundingClientRect()
|
||||
const navTop = scrollContainer.scrollTop
|
||||
const navBottom = navTop + scrollContainer.clientHeight
|
||||
const linkTop = navTop + linkRect.top - containerRect.top
|
||||
const linkBottom = linkTop + link.offsetHeight
|
||||
const buffer = 24
|
||||
|
||||
if (linkTop < navTop + buffer) {
|
||||
nav.scrollTo({
|
||||
scrollContainer.scrollTo({
|
||||
top: Math.max(0, linkTop - buffer),
|
||||
behavior: 'smooth'
|
||||
})
|
||||
@@ -121,8 +126,8 @@ const scrollActiveTocIntoView = (id) => {
|
||||
}
|
||||
|
||||
if (linkBottom > navBottom - buffer) {
|
||||
nav.scrollTo({
|
||||
top: linkBottom - nav.clientHeight + buffer,
|
||||
scrollContainer.scrollTo({
|
||||
top: linkBottom - scrollContainer.clientHeight + buffer,
|
||||
behavior: 'smooth'
|
||||
})
|
||||
}
|
||||
@@ -240,7 +245,7 @@ watch([postTocItems, () => route.fullPath], async () => {
|
||||
<template>
|
||||
<aside class="right-sidebar site-sidebar flex w-full flex-col overflow-hidden border-[var(--site-line)] max-lg:border-l-0 max-lg:border-t max-lg:px-4 max-lg:pb-10 lg:sticky lg:top-[57px] lg:z-10 lg:h-[calc(100vh-57px)] lg:max-h-[calc(100vh-57px)] lg:w-[287px] lg:self-start lg:border-l lg:border-t-0 lg:px-0">
|
||||
<div class="right-sidebar__scroll site-sidebar-scroll flex min-h-0 flex-1 flex-col">
|
||||
<div class="right-sidebar__block site-sidebar-section py-5 pl-5 pr-5 sm:pr-0 max-lg:px-0">
|
||||
<div v-if="!isPostDetailRoute" class="right-sidebar__block site-sidebar-section py-5 pl-5 pr-5 sm:pr-0 max-lg:px-0">
|
||||
<div class="right-sidebar__profile flex items-center gap-3">
|
||||
<div class="right-sidebar__logo grid h-12 w-12 shrink-0 place-items-center overflow-hidden rounded-2xl text-2xl font-bold text-[var(--site-invert-text)]">
|
||||
<img
|
||||
@@ -262,7 +267,7 @@ watch([postTocItems, () => route.fullPath], async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="followLinks.length" class="right-sidebar__block site-sidebar-section py-5 sm:pl-5 pr-0">
|
||||
<div v-if="!isPostDetailRoute && followLinks.length" class="right-sidebar__block site-sidebar-section py-5 sm:pl-5 pr-0">
|
||||
<div class="right-sidebar__row flex items-center justify-between">
|
||||
<p class="right-sidebar__eyebrow text-xs font-semibold uppercase site-muted">
|
||||
Follow
|
||||
@@ -404,24 +409,29 @@ watch([postTocItems, () => route.fullPath], async () => {
|
||||
|
||||
<div
|
||||
v-if="isPostDetailRoute"
|
||||
class="right-sidebar__block right-sidebar__toc flex min-h-0 flex-1 flex-col py-5 pl-5 pr-0 max-lg:hidden"
|
||||
class="right-sidebar__block right-sidebar__toc py-5 pl-5 pr-0 max-lg:hidden"
|
||||
>
|
||||
<div class="right-sidebar__row flex shrink-0 items-center justify-between">
|
||||
<p class="right-sidebar__eyebrow text-xs font-semibold uppercase site-muted">
|
||||
TOC
|
||||
목차
|
||||
</p>
|
||||
</div>
|
||||
<nav ref="tocNavRef" class="right-sidebar__toc-nav mt-4 min-h-0 flex-1 overflow-y-auto pr-2" aria-label="게시글 목차">
|
||||
<ul v-if="postTocItems.length" class="right-sidebar__toc-list list-none space-y-2 p-0">
|
||||
<li v-for="item in postTocItems" :key="item.id">
|
||||
<nav ref="tocNavRef" class="right-sidebar__toc-nav mt-4 pr-2" aria-label="게시글 목차">
|
||||
<ul v-if="postTocItems.length" class="right-sidebar__toc-list flex list-none flex-col gap-2 border-l border-[var(--site-line)] p-0">
|
||||
<li
|
||||
v-for="item in postTocItems"
|
||||
:key="item.id"
|
||||
class="right-sidebar__toc-item relative flex h-6 items-center transition-colors"
|
||||
:class="activeTocId === item.id ? 'right-sidebar__toc-item--active' : ''"
|
||||
>
|
||||
<a
|
||||
class="right-sidebar__toc-link site-interactive block rounded-md py-1.5 pr-3 text-sm leading-snug transition-colors hover:text-[var(--site-accent)]"
|
||||
class="right-sidebar__toc-link site-interactive flex h-full items-center rounded-md pr-3 text-sm leading-snug transition-colors hover:text-[var(--site-accent)]"
|
||||
:class="{
|
||||
'border-[var(--site-accent)] bg-[var(--site-panel)] text-[var(--site-accent)] font-semibold': activeTocId === item.id,
|
||||
'border-transparent text-[var(--site-text)]': activeTocId !== item.id,
|
||||
'pl-2 font-semibold': item.level === 1,
|
||||
'pl-5': item.level === 2,
|
||||
'pl-8 text-xs': item.level === 3,
|
||||
'bg-[var(--site-panel)] text-[var(--site-accent)] font-semibold': activeTocId === item.id,
|
||||
'text-[var(--site-text)]': activeTocId !== item.id,
|
||||
'pl-4 font-semibold': item.level === 1,
|
||||
'pl-7': item.level === 2,
|
||||
'pl-10': item.level === 3,
|
||||
'site-muted': item.level === 3 && activeTocId !== item.id
|
||||
}"
|
||||
:href="`#${item.id}`"
|
||||
@@ -491,7 +501,7 @@ watch([postTocItems, () => route.fullPath], async () => {
|
||||
<SiteAdSlot
|
||||
class="right-sidebar__ad-slot py-5 pl-5 pr-0 max-lg:px-0"
|
||||
:code="sidebarAdCode"
|
||||
location="sidebar"
|
||||
:location="isPostDetailRoute ? 'post-sidebar-right' : 'sidebar'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -511,4 +521,15 @@ watch([postTocItems, () => route.fullPath], async () => {
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.right-sidebar__toc-item--active::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -2px;
|
||||
top: 50%;
|
||||
width: 3px;
|
||||
height: 24px;
|
||||
background: var(--site-accent);
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user