107 lines
3.2 KiB
Vue
107 lines
3.2 KiB
Vue
<script setup>
|
|
import { parseInlineSegments } from '../../lib/markdown-inline.js'
|
|
|
|
const props = defineProps({
|
|
/** 렌더링할 인라인 마크다운 텍스트 */
|
|
text: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
/** 링크에 적용할 클래스 */
|
|
linkClass: {
|
|
type: String,
|
|
default: 'text-[var(--site-accent)] underline underline-offset-4'
|
|
},
|
|
/** 줄바꿈을 br로 렌더링할지 여부 */
|
|
multiline: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
})
|
|
|
|
const segmentLines = computed(() => {
|
|
const source = String(props.text || '')
|
|
const normalizedSource = props.multiline
|
|
? source.replace(/<br\s*\/?>/gi, '\n')
|
|
: source
|
|
const lines = props.multiline ? normalizedSource.split('\n') : [normalizedSource]
|
|
return lines.map(parseInlineSegments)
|
|
})
|
|
|
|
/**
|
|
* 인라인 색상 클래스명을 반환한다.
|
|
* @param {string} color - 색상 이름
|
|
* @returns {string} 클래스명
|
|
*/
|
|
const getInlineColorClass = (color) => `content-markdown-inline-segments__color--${String(color || '').trim().toLowerCase()}`
|
|
</script>
|
|
|
|
<template>
|
|
<template v-for="(lineSegments, lineIndex) in segmentLines" :key="`inline-line-${lineIndex}`">
|
|
<br v-if="lineIndex > 0">
|
|
<template v-for="(segment, segmentIndex) in lineSegments" :key="`inline-segment-${lineIndex}-${segmentIndex}`">
|
|
<strong v-if="segment.type === 'strong'">{{ segment.text }}</strong>
|
|
<em v-else-if="segment.type === 'em'">{{ segment.text }}</em>
|
|
<sub v-else-if="segment.type === 'subscript'">{{ segment.text }}</sub>
|
|
<sup v-else-if="segment.type === 'superscript'">{{ segment.text }}</sup>
|
|
<code v-else-if="segment.type === 'code'" class="content-markdown-inline-segments__inline-code rounded bg-[#252525] px-1.5 py-0.5 text-[0.9em] text-white">{{ segment.text }}</code>
|
|
<a v-else-if="segment.type === 'link'" :class="linkClass" :href="segment.href" target="_blank" rel="noreferrer">{{ segment.text }}</a>
|
|
<span
|
|
v-else-if="segment.type === 'color'"
|
|
class="content-markdown-inline-segments__color"
|
|
:class="getInlineColorClass(segment.color)"
|
|
:data-inline-color="segment.color"
|
|
>
|
|
<ContentMarkdownInlineSegments :text="segment.text" :link-class="linkClass" />
|
|
</span>
|
|
<template v-else>{{ segment.text }}</template>
|
|
</template>
|
|
</template>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.content-markdown-inline-segments__color--gray {
|
|
color: var(--site-muted);
|
|
}
|
|
|
|
.content-markdown-inline-segments__color--blue {
|
|
color: #0055ff;
|
|
}
|
|
|
|
.content-markdown-inline-segments__color--green {
|
|
color: #16ae68;
|
|
}
|
|
|
|
.content-markdown-inline-segments__color--yellow {
|
|
color: #a16207;
|
|
}
|
|
|
|
.content-markdown-inline-segments__color--red {
|
|
color: #e60000;
|
|
}
|
|
|
|
.content-markdown-inline-segments__color--purple {
|
|
color: #8800ff;
|
|
}
|
|
|
|
:global(html[data-theme='dark']) .content-markdown-inline-segments__color--blue {
|
|
color: #7aa2ff;
|
|
}
|
|
|
|
:global(html[data-theme='dark']) .content-markdown-inline-segments__color--green {
|
|
color: #5ee0a0;
|
|
}
|
|
|
|
:global(html[data-theme='dark']) .content-markdown-inline-segments__color--yellow {
|
|
color: #facc15;
|
|
}
|
|
|
|
:global(html[data-theme='dark']) .content-markdown-inline-segments__color--red {
|
|
color: #ff6b6b;
|
|
}
|
|
|
|
:global(html[data-theme='dark']) .content-markdown-inline-segments__color--purple {
|
|
color: #c084fc;
|
|
}
|
|
</style>
|