153 lines
4.1 KiB
JavaScript
153 lines
4.1 KiB
JavaScript
/** @type {string[]} */
|
|
export const CALLOUT_BACKGROUND_OPTIONS = ['gray', 'blue', 'green', 'yellow', 'red', 'purple']
|
|
|
|
/** @type {string[]} */
|
|
export const QUOTE_BACKGROUND_OPTIONS = ['gray', 'blue', 'green', 'yellow', 'red', 'purple']
|
|
|
|
/** @type {Record<string, string>} */
|
|
export const QUOTE_BACKGROUND_LABELS = {
|
|
gray: '회색',
|
|
blue: '파랑',
|
|
green: '초록',
|
|
yellow: '노랑',
|
|
red: '빨강',
|
|
purple: '보라'
|
|
}
|
|
|
|
/** @type {Record<string, string>} */
|
|
export const QUOTE_BACKGROUND_SWATCHES = {
|
|
gray: '#050505',
|
|
blue: '#0055ff',
|
|
green: '#16ae68',
|
|
yellow: '#ffff00',
|
|
red: '#ff0000',
|
|
purple: '#8800ff'
|
|
}
|
|
|
|
/** @type {Record<string, string>} */
|
|
export const CALLOUT_BACKGROUND_SWATCHES = {
|
|
gray: 'color-mix(in srgb, #050505 10%, #ffffff)',
|
|
blue: 'color-mix(in srgb, #0055ff 10%, #ffffff)',
|
|
green: 'color-mix(in srgb, #16ae68 10%, #ffffff)',
|
|
yellow: 'color-mix(in srgb, #ffff00 10%, #ffffff)',
|
|
red: 'color-mix(in srgb, #ff0000 10%, #ffffff)',
|
|
purple: 'color-mix(in srgb, #8800ff 10%, #ffffff)'
|
|
}
|
|
|
|
/** @type {string[]} */
|
|
export const CALLOUT_EMOJI_OPTIONS = ['💡', '⚠️', '❗', '✅', '📌', '🔥', '💬']
|
|
|
|
/**
|
|
* 옵션 선언부를 key=value 토큰 목록으로 분리한다.
|
|
* @param {string} input - 옵션 문자열
|
|
* @returns {string[]} 토큰 목록
|
|
*/
|
|
const tokenizeOptionString = (input) => {
|
|
const tokens = []
|
|
const pattern = /[^\s"']+(?:"[^"]*"|'[^']*')?/g
|
|
const matches = String(input ?? '').match(pattern)
|
|
|
|
return matches ? tokens.concat(matches) : tokens
|
|
}
|
|
|
|
/**
|
|
* 선언부 옵션 값을 정리한다.
|
|
* @param {string} value - 원본 값
|
|
* @returns {string} 정리된 값
|
|
*/
|
|
const normalizeOptionValue = (value) => {
|
|
const normalized = String(value ?? '').trim()
|
|
|
|
if ((normalized.startsWith('"') && normalized.endsWith('"'))
|
|
|| (normalized.startsWith("'") && normalized.endsWith("'"))) {
|
|
return normalized.slice(1, -1)
|
|
}
|
|
|
|
return normalized
|
|
}
|
|
|
|
/**
|
|
* 선언부 옵션 값을 직렬화한다.
|
|
* @param {string} value - 옵션 값
|
|
* @returns {string} 직렬화 값
|
|
*/
|
|
const serializeOptionValue = (value) => {
|
|
const normalized = String(value ?? '').trim()
|
|
|
|
if (!normalized) {
|
|
return ''
|
|
}
|
|
|
|
if (/[\s"']/.test(normalized)) {
|
|
return `"${normalized.replace(/"/g, '\\"')}"`
|
|
}
|
|
|
|
return normalized
|
|
}
|
|
|
|
/**
|
|
* 콜아웃 선언부 옵션을 파싱한다.
|
|
* @param {string} line - 콜아웃 선언 라인
|
|
* @returns {{ calloutEmojiEnabled: boolean, calloutEmoji: string, calloutBackground: string, title: string }}
|
|
*/
|
|
export const parseCalloutOptions = (line) => {
|
|
const options = {
|
|
calloutEmojiEnabled: false,
|
|
calloutEmoji: '💡',
|
|
calloutBackground: 'blue',
|
|
title: ''
|
|
}
|
|
const tokens = tokenizeOptionString(String(line ?? '').trim()).slice(1)
|
|
|
|
tokens.forEach((token) => {
|
|
const [rawKey, ...rawValueParts] = token.split('=')
|
|
|
|
if (!rawKey || !rawValueParts.length) {
|
|
return
|
|
}
|
|
|
|
const key = rawKey.toLowerCase()
|
|
const value = normalizeOptionValue(rawValueParts.join('='))
|
|
|
|
if (key === 'emoji') {
|
|
if (!value || value === 'none') {
|
|
options.calloutEmojiEnabled = false
|
|
options.calloutEmoji = '💡'
|
|
} else {
|
|
options.calloutEmojiEnabled = true
|
|
options.calloutEmoji = value
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if (key === 'bg' && CALLOUT_BACKGROUND_OPTIONS.includes(value)) {
|
|
options.calloutBackground = value
|
|
return
|
|
}
|
|
|
|
if (key === 'title') {
|
|
options.title = value
|
|
}
|
|
})
|
|
|
|
return options
|
|
}
|
|
|
|
/**
|
|
* 콜아웃 선언 줄을 만든다.
|
|
* @param {{ calloutEmojiEnabled?: boolean, calloutEmoji?: string, calloutBackground?: string, title?: string }} options - 옵션
|
|
* @returns {string} 선언 줄
|
|
*/
|
|
export const buildCalloutOpenerLine = (options = {}) => {
|
|
const emojiEnabled = options.calloutEmojiEnabled === true
|
|
const emoji = emojiEnabled ? (options.calloutEmoji || '💡') : 'none'
|
|
const background = CALLOUT_BACKGROUND_OPTIONS.includes(options.calloutBackground)
|
|
? options.calloutBackground
|
|
: 'blue'
|
|
const title = serializeOptionValue(options.title)
|
|
const titleOption = title ? ` title=${title}` : ''
|
|
|
|
return `:::callout emoji=${emoji} bg=${background}${titleOption}`
|
|
}
|