Skip to content

Commit 90f4e8d

Browse files
committed
fix: width 속성 처리
1 parent 4b62a88 commit 90f4e8d

File tree

1 file changed

+41
-7
lines changed

1 file changed

+41
-7
lines changed

.vitepress/plugins/markdown-picture.ts

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,36 @@ function convertImgToPicture(
5252
additionalAttrs: string = "",
5353
): string {
5454
const safeAlt = alt || "";
55-
const safeAttrs = additionalAttrs && additionalAttrs.trim() ? " " + additionalAttrs.trim() : "";
55+
let safeAttrs = additionalAttrs && additionalAttrs.trim() ? " " + additionalAttrs.trim() : "";
56+
let pictureStyle = "";
57+
58+
// width 속성 처리: 퍼센트나 단위가 있는 경우 picture의 스타일로 이동하여 중첩 계산 방지
59+
const widthMatch = /width=["']([^"']+)["']/i.exec(safeAttrs);
60+
if (widthMatch) {
61+
const widthVal = widthMatch[1];
62+
if (widthVal.includes("%") || widthVal.includes("px")) {
63+
pictureStyle = `width: ${widthVal}; display: inline-block;`;
64+
// img 태그에서는 원본 width 속성을 제거하고 내부적으로 100%를 가지도록 함
65+
safeAttrs = safeAttrs.replace(/width=["'][^"']*["']/gi, "").trim();
66+
67+
if (safeAttrs.includes("style=\"")) {
68+
safeAttrs = safeAttrs.replace(/style=["']([^"']*)["']/i, (m, s) => {
69+
const baseStyle = s.trim();
70+
const separator = baseStyle && !baseStyle.endsWith(";") ? ";" : "";
71+
return `style="${baseStyle}${separator} width: 100%;"`;
72+
});
73+
} else {
74+
safeAttrs += " style=\"width: 100%;\"";
75+
}
76+
} else {
77+
// 숫자만 있는 경우(HTML5 표준) px 제거 로직 유지
78+
safeAttrs = safeAttrs.replace(/width="(\d+)(px)?"/gi, "width=\"$1\"");
79+
}
80+
}
5681

5782
// 외부 URL이거나 svg, gif는 picture 태그로 변환하지 않음
5883
if (src.startsWith("http") || src.endsWith(".svg") || src.endsWith(".gif")) {
59-
return `<img src="${src}" alt="${safeAlt}"${safeAttrs} loading="lazy" />`;
84+
return `<img src="${src}" alt="${safeAlt}"${safeAttrs ? " " + safeAttrs : ""} loading="lazy" />`;
6085
}
6186

6287
// 이미지 포맷별 경로 생성
@@ -82,13 +107,14 @@ function convertImgToPicture(
82107

83108
// 변환된 이미지가 없으면 원본만 사용
84109
if (sources.length === 0) {
85-
return `<img src="${src}" alt="${safeAlt}"${safeAttrs} loading="lazy" />`;
110+
return `<img src="${src}" alt="${safeAlt}"${safeAttrs ? " " + safeAttrs : ""} loading="lazy" />`;
86111
}
87112

88113
// picture 태그 생성 (원본을 최종 fallback으로 사용)
89-
return `<picture>
114+
const pictureAttr = pictureStyle ? ` style="${pictureStyle}"` : "";
115+
return `<picture${pictureAttr}>
90116
${sources.join("\n ")}
91-
<img src="${src}" alt="${safeAlt}"${safeAttrs} loading="lazy" />
117+
<img src="${src}" alt="${safeAlt}"${safeAttrs ? " " + safeAttrs : ""} loading="lazy" />
92118
</picture>`;
93119
}
94120

@@ -117,6 +143,7 @@ function processHtmlImages(html: string, markdownPath: string): string {
117143
.replace(/src=["'][^"']*["']/gi, "")
118144
.replace(/alt=["'][^"']*["']/gi, "")
119145
.replace(/loading=["'][^"']*["']/gi, "") // loading은 우리가 추가할 것이므로 제거
146+
.replace(/\s+/g, " ") // 중복 공백 제거
120147
.trim();
121148

122149
// 속성이 비어있거나 공백만 있으면 빈 문자열로
@@ -142,16 +169,23 @@ export function markdownPicturePlugin(md: MarkdownIt) {
142169
md.renderer.rules.image = (tokens, idx, options, env, self) => {
143170
const token = tokens[idx];
144171
const srcIndex = token.attrIndex("src");
172+
const altIndex = token.attrIndex("alt");
145173

146174
if (srcIndex < 0) {
147175
return defaultRender(tokens, idx, options, env, self);
148176
}
149177

150178
const src = token.attrs![srcIndex][1];
151-
const alt = token.content;
179+
const alt = altIndex >= 0 ? token.attrs![altIndex][1] : token.content || "";
152180
const markdownPath = env.path || "";
153181

154-
return convertImgToPicture(src, alt, markdownPath);
182+
// src, alt를 제외한 나머지 속성들 추출 (width, height 등)
183+
const additionalAttrs = token.attrs!
184+
.filter(([name]) => name !== "src" && name !== "alt")
185+
.map(([name, value]) => `${name}="${value}"`)
186+
.join(" ");
187+
188+
return convertImgToPicture(src, alt, markdownPath, additionalAttrs);
155189
};
156190

157191
// 2. HTML inline 이미지 (<img>) 처리

0 commit comments

Comments
 (0)