Hi, unfairest,
이 포스트를 우연히 발견해서 한번 시도해 보기로 했어요!
첫 번째 버전입니다. 코드가 너무 엉망이 아니기를 바랍니다. ![]()
모든 엣지 케이스를 광범위하게 테스트하지는 않았습니다. 시작점일 뿐입니다.
- 예상되는 래핑 형식:
[wrap=character avatar="<URL>" name="<이름>"][/wrap] [wrap]아래에 빈 줄이 있는지 확인하세요- CSS를 사용하여 캐릭터 이름을 커스터마이징할 수 있습니다 (
character및character-extra클래스 참고)
문제가 있으면 알려주세요 ![]()
Head
<script type="text/discourse-plugin" version="0.8.13">
let characters = new Map();
function searchTag(obj, tag) {
if (!obj || !obj.firstObject) return;
const firstObj = obj.firstObject;
return firstObj.tagName === tag ? firstObj : searchTag(firstObj.children, tag);
}
api.addPostTransformCallback(post =>
{
if (post.post_number <= 1 || post.post_type !== 1) {
return;
}
const matches = post.cooked.match(/data-wrap="character"\s+data-avatar="(?<avatar>[^"]+)"\s+data-name="(?<name>[^"]+)"/i);
if (!matches) {
characters.delete(post.id);
return;
}
// TODO: avatar/name sanity check
const {name, avatar} = matches.groups;
characters.set(post.id, {name, avatar});
});
api.reopenWidget("post-avatar", {
html(attrs) {
const html = this._super(attrs);
if (attrs.id && characters.has(attrs.id)) {
const imageHtml = searchTag(html, 'IMG');
if (imageHtml) {
imageHtml.properties.attributes.src = characters.get(attrs.id).avatar;
}
}
return html;
}
});
api.reopenWidget("poster-name", {
html(attrs) {
let html = this._super(attrs);
if (attrs.id && characters.has(attrs.id)) {
const h = require("virtual-dom").h;
html = [
h('span.character', this.userLink(attrs, characters.get(attrs.id).name)),
h('span.character-extra', 'played by'), // optional
...html
];
}
return html;
}
});
</script>
CSS
.names {
.character a {
font-weight: bold;
color: var(--tertiary-high);
}
.character-extra {
}
}
.cooked, .d-editor-preview {
p:has(> [data-wrap="character"]) {
display: none;
}
p:has(> [data-wrap="character"]) + * {
margin-top: 0;
}
}
이것이 어떻게 보였는지 보여주는 작은 데모입니다: