v1.2.9: 라이브 에디터·홈 피드·메인 커버 개선
라이브 모드 코드/콜아웃/토글 편집, 슬래시 명령, 홈 Latest List·Compact·Cards 보기, 사이트 설정 메인 화면 커버(720px) 및 HomeHero 반영. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
122
components/content/ProseCodeBlock.vue
Normal file
122
components/content/ProseCodeBlock.vue
Normal file
@@ -0,0 +1,122 @@
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
/** 언어 라벨(공개 화면 표시) */
|
||||
language: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 줄 번호 표시 */
|
||||
showLineNumbers: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 복사 버튼 표시(공개 화면) */
|
||||
showCopy: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 복사할 코드 본문 */
|
||||
copyText: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 줄 번호 목록 */
|
||||
lineNumbers: {
|
||||
type: Array,
|
||||
default: () => [1]
|
||||
}
|
||||
})
|
||||
|
||||
const copyDone = ref(false)
|
||||
let copyDoneTimer = null
|
||||
|
||||
/**
|
||||
* 코드 본문을 클립보드에 복사한다.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const copyToClipboard = async () => {
|
||||
const text = String(props.copyText ?? '')
|
||||
|
||||
if (!import.meta.client || !text) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(text)
|
||||
copyDone.value = true
|
||||
window.clearTimeout(copyDoneTimer)
|
||||
copyDoneTimer = window.setTimeout(() => {
|
||||
copyDone.value = false
|
||||
}, 1600)
|
||||
} catch {
|
||||
copyDone.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
window.clearTimeout(copyDoneTimer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="prose-code-block group relative mb-2.5 overflow-x-auto rounded bg-[#15171a] text-sm leading-6 text-white"
|
||||
>
|
||||
<div
|
||||
v-if="$slots['header-tools'] || showCopy || language"
|
||||
class="prose-code-block__header absolute right-3 top-2 z-10 flex items-center gap-2"
|
||||
>
|
||||
<slot name="header-tools" />
|
||||
<span
|
||||
v-if="language && !$slots['header-tools']"
|
||||
class="prose-code-block__language text-xs text-white/50"
|
||||
>{{ language }}</span>
|
||||
<button
|
||||
v-if="showCopy"
|
||||
class="prose-code-block__copy rounded px-2 py-0.5 text-xs font-medium text-white/70 transition-colors hover:bg-white/10 hover:text-white"
|
||||
type="button"
|
||||
@click="copyToClipboard"
|
||||
>
|
||||
{{ copyDone ? '복사됨' : '복사' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="prose-code-block__body flex">
|
||||
<div
|
||||
v-if="showLineNumbers"
|
||||
class="prose-code-block__gutter shrink-0 select-none border-r border-white/10 py-3 pl-3 pr-2 font-mono text-xs leading-6 text-white/40 tabular-nums"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div
|
||||
v-for="lineNumber in lineNumbers"
|
||||
:key="`prose-code-gutter-${lineNumber}`"
|
||||
class="prose-code-block__gutter-line"
|
||||
>
|
||||
{{ lineNumber }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="prose-code-block__content min-w-0 flex-1 px-4 py-3 font-mono text-sm leading-6">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.prose-code-block:focus-within {
|
||||
outline: 2px solid rgb(255 255 255 / 0.22);
|
||||
outline-offset: 0;
|
||||
}
|
||||
|
||||
.prose-code-block__content :deep(code) {
|
||||
display: block;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user