v13のMFMに対応

This commit is contained in:
2023-01-25 16:19:38 +09:00
committed by sim1222
parent 6965cae734
commit 58f9c9055a

View File

@ -5,7 +5,6 @@ import MkLink from '@/components/MkLink.vue';
import MkMention from '@/components/MkMention.vue';
import MkEmoji from '@/components/global/MkEmoji.vue';
import { concat } from '@/scripts/array';
import MkFormula from '@/components/MkFormula.vue';
import MkCode from '@/components/MkCode.vue';
import MkGoogle from '@/components/MkGoogle.vue';
import MkSparkle from '@/components/MkSparkle.vue';
@ -13,6 +12,15 @@ import MkA from '@/components/global/MkA.vue';
import { host } from '@/config';
import { MFM_TAGS } from '@/scripts/mfm-tags';
const QUOTE_STYLE = `
display: block;
margin: 8px;
padding: 6px 0 6px 12px;
color: var(--fg);
border-left: solid 3px var(--fg);
opacity: 0.7;
`.split('\n').join(' ');
export default defineComponent({
props: {
text: {
@ -35,9 +43,6 @@ export default defineComponent({
type: Object,
default: null,
},
customEmojis: {
required: false,
},
isNote: {
type: Boolean,
default: true,
@ -47,20 +52,20 @@ export default defineComponent({
render() {
if (this.text == null || this.text === '') return;
const ast = (this.plain ? mfm.parseSimple : mfm.parse)(this.text, { fnNameList: MFM_TAGS });
const ast = (this.plain ? mfm.parseSimple : mfm.parse)(this.text);
const validTime = (t: string | null | undefined) => {
if (t == null) return null;
return t.match(/^[0-9.]+s$/) ? t : null;
};
const genEl = (ast: mfm.MfmNode[]) => concat(ast.map((token): VNode[] => {
const genEl = (ast: mfm.MfmNode[]) => ast.map((token): VNode | string | (VNode | string)[] => {
switch (token.type) {
case 'text': {
const text = token.props.text.replace(/(\r\n|\n|\r)/g, '\n');
if (!this.plain) {
const res = [];
const res: (VNode | string)[] = [];
for (const t of text.split('\n')) {
res.push(h('br'));
res.push(t);
@ -91,22 +96,22 @@ export default defineComponent({
let style;
switch (token.props.name) {
case 'tada': {
const speed = validTime(token.props.args.speed) || '1s';
const speed = validTime(token.props.args.speed) ?? '1s';
style = 'font-size: 150%;' + (this.$store.state.animatedMfm ? `animation: tada ${speed} linear infinite both;` : '');
break;
}
case 'jelly': {
const speed = validTime(token.props.args.speed) || '1s';
const speed = validTime(token.props.args.speed) ?? '1s';
style = (this.$store.state.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
break;
}
case 'twitch': {
const speed = validTime(token.props.args.speed) || '0.5s';
const speed = validTime(token.props.args.speed) ?? '0.5s';
style = this.$store.state.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
break;
}
case 'shake': {
const speed = validTime(token.props.args.speed) || '0.5s';
const speed = validTime(token.props.args.speed) ?? '0.5s';
style = this.$store.state.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
break;
}
@ -119,17 +124,17 @@ export default defineComponent({
token.props.args.x ? 'mfm-spinX' :
token.props.args.y ? 'mfm-spinY' :
'mfm-spin';
const speed = validTime(token.props.args.speed) || '1.5s';
const speed = validTime(token.props.args.speed) ?? '1.5s';
style = this.$store.state.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
break;
}
case 'jump': {
const speed = validTime(token.props.args.speed) || '0.75s';
const speed = validTime(token.props.args.speed) ?? '0.75s';
style = this.$store.state.animatedMfm ? `animation: mfm-jump ${speed} linear infinite;` : '';
break;
}
case 'bounce': {
const speed = validTime(token.props.args.speed) || '0.75s';
const speed = validTime(token.props.args.speed) ?? '0.75s';
style = this.$store.state.animatedMfm ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : '';
break;
}
@ -174,7 +179,7 @@ export default defineComponent({
}, genEl(token.children));
}
case 'rainbow': {
const speed = validTime(token.props.args.speed) || '1s';
const speed = validTime(token.props.args.speed) ?? '1s';
style = this.$store.state.animatedMfm ? `animation: mfm-rainbow ${speed} linear infinite;` : '';
break;
}
@ -185,16 +190,40 @@ export default defineComponent({
return h(MkSparkle, {}, genEl(token.children));
}
case 'rotate': {
const degrees = parseInt(token.props.args.deg) || '90';
const degrees = parseFloat(token.props.args.deg) ?? '90';
style = `transform: rotate(${degrees}deg); transform-origin: center center;`;
break;
}
case 'position': {
const x = parseFloat(token.props.args.x ?? '0');
const y = parseFloat(token.props.args.y ?? '0');
style = `transform: translateX(${x}em) translateY(${y}em);`;
break;
}
case 'scale': {
const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5);
const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5);
style = `transform: scale(${x}, ${y});`;
break;
}
case 'fg': {
let color = token.props.args.color;
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';
style = `color: #${color};`;
break;
}
case 'bg': {
let color = token.props.args.color;
if (!/^[0-9a-f]{3,6}$/i.test(color)) color = 'f00';
style = `background-color: #${color};`;
break;
}
}
if (style == null) {
return h('span', {}, ['$[', token.props.name, ' ', ...genEl(token.children), ']']);
} else {
return h('span', {
style: 'display: inline-block;' + style,
style: 'display: inline-block; ' + style,
}, genEl(token.children));
}
}
@ -270,11 +299,11 @@ export default defineComponent({
case 'quote': {
if (!this.nowrap) {
return [h('div', {
class: 'quote',
style: QUOTE_STYLE,
}, genEl(token.children))];
} else {
return [h('span', {
class: 'quote',
style: QUOTE_STYLE,
}, genEl(token.children))];
}
}
@ -283,8 +312,9 @@ export default defineComponent({
return [h(MkEmoji, {
key: Math.random(),
emoji: `:${token.props.name}:`,
customEmojis: this.customEmojis,
normal: this.plain,
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
host: this.author?.host,
})];
}
@ -292,25 +322,16 @@ export default defineComponent({
return [h(MkEmoji, {
key: Math.random(),
emoji: token.props.emoji,
customEmojis: this.customEmojis,
normal: this.plain,
})];
}
case 'mathInline': {
return [h(MkFormula, {
key: Math.random(),
formula: token.props.formula,
block: false,
})];
return [h('code', token.props.formula)];
}
case 'mathBlock': {
return [h(MkFormula, {
key: Math.random(),
formula: token.props.formula,
block: true,
})];
return [h('code', token.props.formula)];
}
case 'search': {
@ -325,12 +346,13 @@ export default defineComponent({
}
default: {
console.error('unrecognized ast type:', token.type);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
console.error('unrecognized ast type:', (token as any).type);
return [];
}
}
}));
}).flat(Infinity) as (VNode | string)[];
// Parse ast to DOM
return h('span', genEl(ast));