Files
sori.studio/components/content/ProseToggle.vue
zenn 3fb8a40031 v1.2.9: 라이브 에디터·홈 피드·메인 커버 개선
라이브 모드 코드/콜아웃/토글 편집, 슬래시 명령, 홈 Latest List·Compact·Cards 보기,
사이트 설정 메인 화면 커버(720px) 및 HomeHero 반영.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-18 16:57:30 +09:00

113 lines
2.8 KiB
Vue

<script setup>
const props = defineProps({
/** 접힌 상태 제목 */
title: {
type: String,
default: ''
},
/** 초기 펼침 여부 */
defaultOpen: {
type: Boolean,
default: false
},
/** 본문 열림·닫힘 애니메이션 */
animated: {
type: Boolean,
default: true
}
})
const isOpen = ref(props.defaultOpen)
watch(() => props.defaultOpen, (value) => {
isOpen.value = value
})
/**
* 토글 펼침 상태를 전환한다.
* @returns {void}
*/
const toggleOpen = () => {
isOpen.value = !isOpen.value
}
</script>
<template>
<div
class="prose-toggle my-6 rounded-[10px] border border-[var(--site-line)] bg-[var(--site-panel)] p-5"
:class="{ 'prose-toggle--open': isOpen }"
>
<div class="prose-toggle__header flex items-start gap-2">
<button
class="prose-toggle__trigger mt-0.5 inline-flex size-7 shrink-0 items-center justify-center rounded-md text-[var(--site-muted)] transition-colors hover:bg-black/5 hover:text-[var(--site-text)]"
type="button"
:aria-expanded="isOpen"
aria-label="토글 펼치기·접기"
@click="toggleOpen"
>
<svg
class="prose-toggle__chevron size-4 transition-transform duration-300 ease-out"
:class="{ 'prose-toggle__chevron--open': isOpen }"
viewBox="0 0 16 16"
fill="none"
aria-hidden="true"
>
<path
d="M6 4l4 4-4 4"
stroke="currentColor"
stroke-width="1.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</button>
<div class="prose-toggle__title min-w-0 flex-1 text-[15px] font-semibold leading-7 text-[var(--site-text)]">
<slot name="title">
{{ title || '더 보기' }}
</slot>
</div>
</div>
<div
class="prose-toggle__body-shell"
:class="[
animated ? 'prose-toggle__body-shell--animated' : '',
isOpen ? 'prose-toggle__body-shell--open' : ''
]"
>
<div class="prose-toggle__body-inner min-h-0 overflow-hidden">
<div
class="prose-toggle__body mt-4 whitespace-pre-line text-[15px] leading-8 text-[var(--site-muted)]"
>
<slot />
</div>
</div>
</div>
</div>
</template>
<style scoped>
.prose-toggle__chevron--open {
transform: rotate(90deg);
}
.prose-toggle__body-shell--animated {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows 0.32s ease;
}
.prose-toggle__body-shell--animated.prose-toggle__body-shell--open {
grid-template-rows: 1fr;
}
.prose-toggle__body-shell:not(.prose-toggle__body-shell--animated) .prose-toggle__body-inner {
display: none;
}
.prose-toggle__body-shell:not(.prose-toggle__body-shell--animated).prose-toggle__body-shell--open .prose-toggle__body-inner {
display: block;
}
</style>