parent
9d405b4581
commit
31aa008566
8 changed files with 193 additions and 433 deletions
|
@ -77,9 +77,57 @@ export default defineComponent({
|
||||||
}, genEl(token.children));
|
}, genEl(token.children));
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'big': {
|
case 'fn': {
|
||||||
return h('strong', {
|
// TODO: CSSを文字列で組み立てていくと token.node.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる
|
||||||
style: `display: inline-block; font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: anime-tada 1s linear infinite both;' : ''),
|
let style;
|
||||||
|
switch (token.node.props.name) {
|
||||||
|
case 'tada': {
|
||||||
|
style = `font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'jelly': {
|
||||||
|
const speed = token.node.props.args.speed || '1s';
|
||||||
|
style = (this.$store.state.device.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'twitch': {
|
||||||
|
const speed = token.node.props.args.speed || '0.5s';
|
||||||
|
style = this.$store.state.device.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'shake': {
|
||||||
|
const speed = token.node.props.args.speed || '0.5s';
|
||||||
|
style = this.$store.state.device.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'spin': {
|
||||||
|
const direction =
|
||||||
|
token.node.props.args.left ? 'reverse' :
|
||||||
|
token.node.props.args.alternate ? 'alternate' :
|
||||||
|
'normal';
|
||||||
|
const anime =
|
||||||
|
token.node.props.args.x ? 'mfm-spinX' :
|
||||||
|
token.node.props.args.y ? 'mfm-spinY' :
|
||||||
|
'mfm-spin';
|
||||||
|
const speed = token.node.props.args.speed || '1.5s';
|
||||||
|
style = this.$store.state.device.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'jump': {
|
||||||
|
style = this.$store.state.device.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'flip': {
|
||||||
|
const transform =
|
||||||
|
(token.node.props.args.h && token.node.props.args.v) ? 'scale(-1, -1)' :
|
||||||
|
token.node.props.args.v ? 'scaleY(-1)' :
|
||||||
|
'scaleX(-1)';
|
||||||
|
style = `transform: ${transform};`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h('span', {
|
||||||
|
style: 'display: inline-block;' + style,
|
||||||
}, genEl(token.children));
|
}, genEl(token.children));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,48 +143,6 @@ export default defineComponent({
|
||||||
}, genEl(token.children))];
|
}, genEl(token.children))];
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'motion': {
|
|
||||||
return h('span', {
|
|
||||||
style: 'display: inline-block;' + (this.$store.state.device.animatedMfm ? 'animation: anime-rubberBand 1s linear infinite both;' : ''),
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'spin': {
|
|
||||||
const direction =
|
|
||||||
token.node.props.attr == 'left' ? 'reverse' :
|
|
||||||
token.node.props.attr == 'alternate' ? 'alternate' :
|
|
||||||
'normal';
|
|
||||||
const style = this.$store.state.device.animatedMfm
|
|
||||||
? `animation: anime-spin 1.5s linear infinite; animation-direction: ${direction};` : '';
|
|
||||||
return h('span', {
|
|
||||||
style: 'display: inline-block;' + style
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'jump': {
|
|
||||||
return h('span', {
|
|
||||||
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-jump 0.75s linear infinite;' : 'display: inline-block;'
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'flip': {
|
|
||||||
return h('span', {
|
|
||||||
style: 'display: inline-block; transform: scaleX(-1);'
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'twitch': {
|
|
||||||
return h('span', {
|
|
||||||
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-twitch 0.5s ease infinite;' : 'display: inline-block;'
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'shake': {
|
|
||||||
return h('span', {
|
|
||||||
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-shake 0.5s ease infinite;' : 'display: inline-block;'
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'url': {
|
case 'url': {
|
||||||
return [h(MkUrl, {
|
return [h(MkUrl, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
|
@ -198,12 +204,6 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'title': {
|
|
||||||
return [h('div', {
|
|
||||||
class: 'title'
|
|
||||||
}, genEl(token.children))];
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'emoji': {
|
case 'emoji': {
|
||||||
return [h(MkEmoji, {
|
return [h(MkEmoji, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
|
|
|
@ -13,6 +13,115 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@keyframes mfm-spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-spinX {
|
||||||
|
0% { transform: perspective(128px) rotateX(0deg); }
|
||||||
|
100% { transform: perspective(128px) rotateX(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-spinY {
|
||||||
|
0% { transform: perspective(128px) rotateY(0deg); }
|
||||||
|
100% { transform: perspective(128px) rotateY(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-jump {
|
||||||
|
0% { transform: translateY(0); }
|
||||||
|
25% { transform: translateY(-16px); }
|
||||||
|
50% { transform: translateY(0); }
|
||||||
|
75% { transform: translateY(-8px); }
|
||||||
|
100% { transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`;
|
||||||
|
// let css = '';
|
||||||
|
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
|
||||||
|
@keyframes mfm-twitch {
|
||||||
|
0% { transform: translate(7px, -2px) }
|
||||||
|
5% { transform: translate(-3px, 1px) }
|
||||||
|
10% { transform: translate(-7px, -1px) }
|
||||||
|
15% { transform: translate(0px, -1px) }
|
||||||
|
20% { transform: translate(-8px, 6px) }
|
||||||
|
25% { transform: translate(-4px, -3px) }
|
||||||
|
30% { transform: translate(-4px, -6px) }
|
||||||
|
35% { transform: translate(-8px, -8px) }
|
||||||
|
40% { transform: translate(4px, 6px) }
|
||||||
|
45% { transform: translate(-3px, 1px) }
|
||||||
|
50% { transform: translate(2px, -10px) }
|
||||||
|
55% { transform: translate(-7px, 0px) }
|
||||||
|
60% { transform: translate(-2px, 4px) }
|
||||||
|
65% { transform: translate(3px, -8px) }
|
||||||
|
70% { transform: translate(6px, 7px) }
|
||||||
|
75% { transform: translate(-7px, -2px) }
|
||||||
|
80% { transform: translate(-7px, -8px) }
|
||||||
|
85% { transform: translate(9px, 3px) }
|
||||||
|
90% { transform: translate(-3px, -2px) }
|
||||||
|
95% { transform: translate(-10px, 2px) }
|
||||||
|
100% { transform: translate(-2px, -6px) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`;
|
||||||
|
// let css = '';
|
||||||
|
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
|
||||||
|
@keyframes mfm-shake {
|
||||||
|
0% { transform: translate(-3px, -1px) rotate(-8deg) }
|
||||||
|
5% { transform: translate(0px, -1px) rotate(-10deg) }
|
||||||
|
10% { transform: translate(1px, -3px) rotate(0deg) }
|
||||||
|
15% { transform: translate(1px, 1px) rotate(11deg) }
|
||||||
|
20% { transform: translate(-2px, 1px) rotate(1deg) }
|
||||||
|
25% { transform: translate(-1px, -2px) rotate(-2deg) }
|
||||||
|
30% { transform: translate(-1px, 2px) rotate(-3deg) }
|
||||||
|
35% { transform: translate(2px, 1px) rotate(6deg) }
|
||||||
|
40% { transform: translate(-2px, -3px) rotate(-9deg) }
|
||||||
|
45% { transform: translate(0px, -1px) rotate(-12deg) }
|
||||||
|
50% { transform: translate(1px, 2px) rotate(10deg) }
|
||||||
|
55% { transform: translate(0px, -3px) rotate(8deg) }
|
||||||
|
60% { transform: translate(1px, -1px) rotate(8deg) }
|
||||||
|
65% { transform: translate(0px, -1px) rotate(-7deg) }
|
||||||
|
70% { transform: translate(-1px, -3px) rotate(6deg) }
|
||||||
|
75% { transform: translate(0px, -2px) rotate(4deg) }
|
||||||
|
80% { transform: translate(-2px, -1px) rotate(3deg) }
|
||||||
|
85% { transform: translate(1px, -3px) rotate(-10deg) }
|
||||||
|
90% { transform: translate(1px, 0px) rotate(3deg) }
|
||||||
|
95% { transform: translate(-2px, 0px) rotate(-3deg) }
|
||||||
|
100% { transform: translate(2px, 1px) rotate(2deg) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-rubberBand {
|
||||||
|
from {
|
||||||
|
transform: scale3d(1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
30% {
|
||||||
|
transform: scale3d(1.25, 0.75, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
40% {
|
||||||
|
transform: scale3d(0.75, 1.25, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale3d(1.15, 0.85, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
65% {
|
||||||
|
transform: scale3d(0.95, 1.05, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
75% {
|
||||||
|
transform: scale3d(1.05, 0.95, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: scale3d(1, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.havbbuyv {
|
.havbbuyv {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
@ -42,10 +151,5 @@ export default defineComponent({
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep(.title) {
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: solid 1px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<Mfm :key="'past-turn-of:' + turnUser().name" :text="$t('_reversi.pastTurnOf', { name: turnUser().name })" :plain="true" :custom-emojis="turnUser().emojis"/>
|
<Mfm :key="'past-turn-of:' + turnUser().name" :text="$t('_reversi.pastTurnOf', { name: turnUser().name })" :plain="true" :custom-emojis="turnUser().emojis"/>
|
||||||
</p>
|
</p>
|
||||||
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn()">{{ $t('_reversi.opponentTurn') }}<MkEllipsis/></p>
|
<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn()">{{ $t('_reversi.opponentTurn') }}<MkEllipsis/></p>
|
||||||
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn()" style="animation: anime-tada 1s linear infinite both;">{{ $t('_reversi.myTurn') }}</p>
|
<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn()" style="animation: tada 1s linear infinite both;">{{ $t('_reversi.myTurn') }}</p>
|
||||||
<p class="result" v-if="game.isEnded && logPos == logs.length">
|
<p class="result" v-if="game.isEnded && logPos == logs.length">
|
||||||
<template v-if="game.winner">
|
<template v-if="game.winner">
|
||||||
<Mfm :key="'won'" :text="$t('_reversi.won', { name: game.winner.name })" :plain="true" :custom-emojis="game.winner.emojis"/>
|
<Mfm :key="'won'" :text="$t('_reversi.won', { name: game.winner.name })" :plain="true" :custom-emojis="game.winner.emojis"/>
|
||||||
|
|
|
@ -486,74 +486,7 @@ hr {
|
||||||
90% { opacity: 0; transform: scale(0.5); }
|
90% { opacity: 0; transform: scale(0.5); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes anime-spin {
|
@keyframes tada {
|
||||||
0% { transform: rotate(0deg); }
|
|
||||||
100% { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes anime-jump {
|
|
||||||
0% { transform: translateY(0); }
|
|
||||||
25% { transform: translateY(-16px); }
|
|
||||||
50% { transform: translateY(0); }
|
|
||||||
75% { transform: translateY(-8px); }
|
|
||||||
100% { transform: translateY(0); }
|
|
||||||
}
|
|
||||||
|
|
||||||
// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`;
|
|
||||||
// let css = '';
|
|
||||||
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
|
|
||||||
@keyframes anime-twitch {
|
|
||||||
0% { transform: translate(7px, -2px) }
|
|
||||||
5% { transform: translate(-3px, 1px) }
|
|
||||||
10% { transform: translate(-7px, -1px) }
|
|
||||||
15% { transform: translate(0px, -1px) }
|
|
||||||
20% { transform: translate(-8px, 6px) }
|
|
||||||
25% { transform: translate(-4px, -3px) }
|
|
||||||
30% { transform: translate(-4px, -6px) }
|
|
||||||
35% { transform: translate(-8px, -8px) }
|
|
||||||
40% { transform: translate(4px, 6px) }
|
|
||||||
45% { transform: translate(-3px, 1px) }
|
|
||||||
50% { transform: translate(2px, -10px) }
|
|
||||||
55% { transform: translate(-7px, 0px) }
|
|
||||||
60% { transform: translate(-2px, 4px) }
|
|
||||||
65% { transform: translate(3px, -8px) }
|
|
||||||
70% { transform: translate(6px, 7px) }
|
|
||||||
75% { transform: translate(-7px, -2px) }
|
|
||||||
80% { transform: translate(-7px, -8px) }
|
|
||||||
85% { transform: translate(9px, 3px) }
|
|
||||||
90% { transform: translate(-3px, -2px) }
|
|
||||||
95% { transform: translate(-10px, 2px) }
|
|
||||||
100% { transform: translate(-2px, -6px) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`;
|
|
||||||
// let css = '';
|
|
||||||
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
|
|
||||||
@keyframes anime-shake {
|
|
||||||
0% { transform: translate(-3px, -1px) rotate(-8deg) }
|
|
||||||
5% { transform: translate(0px, -1px) rotate(-10deg) }
|
|
||||||
10% { transform: translate(1px, -3px) rotate(0deg) }
|
|
||||||
15% { transform: translate(1px, 1px) rotate(11deg) }
|
|
||||||
20% { transform: translate(-2px, 1px) rotate(1deg) }
|
|
||||||
25% { transform: translate(-1px, -2px) rotate(-2deg) }
|
|
||||||
30% { transform: translate(-1px, 2px) rotate(-3deg) }
|
|
||||||
35% { transform: translate(2px, 1px) rotate(6deg) }
|
|
||||||
40% { transform: translate(-2px, -3px) rotate(-9deg) }
|
|
||||||
45% { transform: translate(0px, -1px) rotate(-12deg) }
|
|
||||||
50% { transform: translate(1px, 2px) rotate(10deg) }
|
|
||||||
55% { transform: translate(0px, -3px) rotate(8deg) }
|
|
||||||
60% { transform: translate(1px, -1px) rotate(8deg) }
|
|
||||||
65% { transform: translate(0px, -1px) rotate(-7deg) }
|
|
||||||
70% { transform: translate(-1px, -3px) rotate(6deg) }
|
|
||||||
75% { transform: translate(0px, -2px) rotate(4deg) }
|
|
||||||
80% { transform: translate(-2px, -1px) rotate(3deg) }
|
|
||||||
85% { transform: translate(1px, -3px) rotate(-10deg) }
|
|
||||||
90% { transform: translate(1px, 0px) rotate(3deg) }
|
|
||||||
95% { transform: translate(-2px, 0px) rotate(-3deg) }
|
|
||||||
100% { transform: translate(2px, 1px) rotate(2deg) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes anime-tada {
|
|
||||||
from {
|
from {
|
||||||
transform: scale3d(1, 1, 1);
|
transform: scale3d(1, 1, 1);
|
||||||
}
|
}
|
||||||
|
@ -580,33 +513,3 @@ hr {
|
||||||
transform: scale3d(1, 1, 1);
|
transform: scale3d(1, 1, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes anime-rubberBand {
|
|
||||||
from {
|
|
||||||
transform: scale3d(1, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
30% {
|
|
||||||
transform: scale3d(1.25, 0.75, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
40% {
|
|
||||||
transform: scale3d(0.75, 1.25, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
50% {
|
|
||||||
transform: scale3d(1.15, 0.85, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
65% {
|
|
||||||
transform: scale3d(0.95, 1.05, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
75% {
|
|
||||||
transform: scale3d(1.05, 0.95, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
transform: scale3d(1, 1, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ export const mfmLanguage = P.createLanguage({
|
||||||
root: r => P.alt(r.block, r.inline).atLeast(1),
|
root: r => P.alt(r.block, r.inline).atLeast(1),
|
||||||
plain: r => P.alt(r.emoji, r.text).atLeast(1),
|
plain: r => P.alt(r.emoji, r.text).atLeast(1),
|
||||||
block: r => P.alt(
|
block: r => P.alt(
|
||||||
r.title,
|
|
||||||
r.quote,
|
r.quote,
|
||||||
r.search,
|
r.search,
|
||||||
r.blockCode,
|
r.blockCode,
|
||||||
|
@ -37,14 +36,6 @@ export const mfmLanguage = P.createLanguage({
|
||||||
return P.makeFailure(i, 'not newline');
|
return P.makeFailure(i, 'not newline');
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
title: r => r.startOfLine.then(P((input, i) => {
|
|
||||||
const text = input.substr(i);
|
|
||||||
const match = text.match(/^([【\[]([^【\[】\]\n]+?)[】\]])(\n|$)/);
|
|
||||||
if (!match) return P.makeFailure(i, 'not a title');
|
|
||||||
const q = match[2].trim();
|
|
||||||
const contents = r.inline.atLeast(1).tryParse(q);
|
|
||||||
return P.makeSuccess(i + match[0].length, createTree('title', contents, {}));
|
|
||||||
})),
|
|
||||||
quote: r => r.startOfLine.then(P((input, i) => {
|
quote: r => r.startOfLine.then(P((input, i) => {
|
||||||
const text = input.substr(i);
|
const text = input.substr(i);
|
||||||
if (!text.match(/^>[\s\S]+?/)) return P.makeFailure(i, 'not a quote');
|
if (!text.match(/^>[\s\S]+?/)) return P.makeFailure(i, 'not a quote');
|
||||||
|
@ -67,17 +58,10 @@ export const mfmLanguage = P.createLanguage({
|
||||||
return P.makeSuccess(i + match[0].length, createLeaf('blockCode', { code: match[2], lang: match[1] ? match[1].trim() : null }));
|
return P.makeSuccess(i + match[0].length, createLeaf('blockCode', { code: match[2], lang: match[1] ? match[1].trim() : null }));
|
||||||
})),
|
})),
|
||||||
inline: r => P.alt(
|
inline: r => P.alt(
|
||||||
r.big,
|
|
||||||
r.bold,
|
r.bold,
|
||||||
r.small,
|
r.small,
|
||||||
r.italic,
|
r.italic,
|
||||||
r.strike,
|
r.strike,
|
||||||
r.motion,
|
|
||||||
r.spin,
|
|
||||||
r.jump,
|
|
||||||
r.flip,
|
|
||||||
r.twitch,
|
|
||||||
r.shake,
|
|
||||||
r.inlineCode,
|
r.inlineCode,
|
||||||
r.mathInline,
|
r.mathInline,
|
||||||
r.mention,
|
r.mention,
|
||||||
|
@ -85,9 +69,9 @@ export const mfmLanguage = P.createLanguage({
|
||||||
r.url,
|
r.url,
|
||||||
r.link,
|
r.link,
|
||||||
r.emoji,
|
r.emoji,
|
||||||
|
r.fn,
|
||||||
r.text
|
r.text
|
||||||
),
|
),
|
||||||
big: r => P.regexp(/^\*\*\*([\s\S]+?)\*\*\*/, 1).map(x => createTree('big', r.inline.atLeast(1).tryParse(x), {})),
|
|
||||||
bold: r => {
|
bold: r => {
|
||||||
const asterisk = P.regexp(/\*\*([\s\S]+?)\*\*/, 1);
|
const asterisk = P.regexp(/\*\*([\s\S]+?)\*\*/, 1);
|
||||||
const underscore = P.regexp(/__([a-zA-Z0-9\s]+?)__/, 1);
|
const underscore = P.regexp(/__([a-zA-Z0-9\s]+?)__/, 1);
|
||||||
|
@ -107,25 +91,6 @@ export const mfmLanguage = P.createLanguage({
|
||||||
return P.alt(xml, underscore).map(x => createTree('italic', r.inline.atLeast(1).tryParse(x), {}));
|
return P.alt(xml, underscore).map(x => createTree('italic', r.inline.atLeast(1).tryParse(x), {}));
|
||||||
},
|
},
|
||||||
strike: r => P.regexp(/~~([^\n~]+?)~~/, 1).map(x => createTree('strike', r.inline.atLeast(1).tryParse(x), {})),
|
strike: r => P.regexp(/~~([^\n~]+?)~~/, 1).map(x => createTree('strike', r.inline.atLeast(1).tryParse(x), {})),
|
||||||
motion: r => {
|
|
||||||
const paren = P.regexp(/\(\(\(([\s\S]+?)\)\)\)/, 1);
|
|
||||||
const xml = P.regexp(/<motion>(.+?)<\/motion>/, 1);
|
|
||||||
return P.alt(paren, xml).map(x => createTree('motion', r.inline.atLeast(1).tryParse(x), {}));
|
|
||||||
},
|
|
||||||
spin: r => {
|
|
||||||
return P((input, i) => {
|
|
||||||
const text = input.substr(i);
|
|
||||||
const match = text.match(/^<spin(\s[a-z]+?)?>(.+?)<\/spin>/i);
|
|
||||||
if (!match) return P.makeFailure(i, 'not a spin');
|
|
||||||
return P.makeSuccess(i + match[0].length, {
|
|
||||||
content: match[2], attr: match[1] ? match[1].trim() : null
|
|
||||||
});
|
|
||||||
}).map(x => createTree('spin', r.inline.atLeast(1).tryParse(x.content), { attr: x.attr }));
|
|
||||||
},
|
|
||||||
jump: r => P.regexp(/<jump>(.+?)<\/jump>/, 1).map(x => createTree('jump', r.inline.atLeast(1).tryParse(x), {})),
|
|
||||||
flip: r => P.regexp(/<flip>(.+?)<\/flip>/, 1).map(x => createTree('flip', r.inline.atLeast(1).tryParse(x), {})),
|
|
||||||
twitch: r => P.regexp(/<twitch>(.+?)<\/twitch>/, 1).map(x => createTree('twitch', r.inline.atLeast(1).tryParse(x), {})),
|
|
||||||
shake: r => P.regexp(/<shake>(.+?)<\/shake>/, 1).map(x => createTree('shake', r.inline.atLeast(1).tryParse(x), {})),
|
|
||||||
center: r => r.startOfLine.then(P.regexp(/<center>([\s\S]+?)<\/center>/, 1).map(x => createTree('center', r.inline.atLeast(1).tryParse(x), {}))),
|
center: r => r.startOfLine.then(P.regexp(/<center>([\s\S]+?)<\/center>/, 1).map(x => createTree('center', r.inline.atLeast(1).tryParse(x), {}))),
|
||||||
inlineCode: () => P.regexp(/`([^´\n]+?)`/, 1).map(x => createLeaf('inlineCode', { code: x })),
|
inlineCode: () => P.regexp(/`([^´\n]+?)`/, 1).map(x => createLeaf('inlineCode', { code: x })),
|
||||||
mathBlock: r => r.startOfLine.then(P.regexp(/\\\[([\s\S]+?)\\\]/, 1).map(x => createLeaf('mathBlock', { formula: x.trim() }))),
|
mathBlock: r => r.startOfLine.then(P.regexp(/\\\[([\s\S]+?)\\\]/, 1).map(x => createLeaf('mathBlock', { formula: x.trim() }))),
|
||||||
|
@ -192,5 +157,29 @@ export const mfmLanguage = P.createLanguage({
|
||||||
const code = P.regexp(emojiRegex).map(x => createLeaf('emoji', { emoji: x }));
|
const code = P.regexp(emojiRegex).map(x => createLeaf('emoji', { emoji: x }));
|
||||||
return P.alt(name, code);
|
return P.alt(name, code);
|
||||||
},
|
},
|
||||||
|
fn: r => {
|
||||||
|
return P.seqObj(
|
||||||
|
P.string('['), ['fn', P.regexp(/[^\s\n\[\]]+/)] as any, P.string(' '), P.optWhitespace, ['text', P.regexp(/[^\n\[\]]+/)] as any, P.string(']'),
|
||||||
|
).map((x: any) => {
|
||||||
|
let name = x.fn;
|
||||||
|
const args = {};
|
||||||
|
const separator = x.fn.indexOf('.');
|
||||||
|
if (separator > -1) {
|
||||||
|
name = x.fn.substr(0, separator);
|
||||||
|
for (const arg of x.fn.substr(separator + 1).split(',')) {
|
||||||
|
const kv = arg.split('=');
|
||||||
|
if (kv.length === 1) {
|
||||||
|
args[kv[0]] = true;
|
||||||
|
} else {
|
||||||
|
args[kv[0]] = kv[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return createTree('fn', r.inline.atLeast(1).tryParse(x.text), {
|
||||||
|
name,
|
||||||
|
args
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
text: () => P.any.map(x => createLeaf('text', { text: x }))
|
text: () => P.any.map(x => createLeaf('text', { text: x }))
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,12 +25,6 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
|
||||||
big(token) {
|
|
||||||
const el = doc.createElement('strong');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
small(token) {
|
small(token) {
|
||||||
const el = doc.createElement('small');
|
const el = doc.createElement('small');
|
||||||
appendChildren(token.children, el);
|
appendChildren(token.children, el);
|
||||||
|
@ -49,42 +43,12 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
|
||||||
motion(token) {
|
fn(token) {
|
||||||
const el = doc.createElement('i');
|
const el = doc.createElement('i');
|
||||||
appendChildren(token.children, el);
|
appendChildren(token.children, el);
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
|
||||||
spin(token) {
|
|
||||||
const el = doc.createElement('i');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
jump(token) {
|
|
||||||
const el = doc.createElement('i');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
twitch(token) {
|
|
||||||
const el = doc.createElement('i');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
shake(token) {
|
|
||||||
const el = doc.createElement('i');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
flip(token) {
|
|
||||||
const el = doc.createElement('span');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
blockCode(token) {
|
blockCode(token) {
|
||||||
const pre = doc.createElement('pre');
|
const pre = doc.createElement('pre');
|
||||||
const inner = doc.createElement('code');
|
const inner = doc.createElement('code');
|
||||||
|
@ -157,12 +121,6 @@ export function toHtml(tokens: MfmForest | null, mentionedRemoteUsers: IMentione
|
||||||
return el;
|
return el;
|
||||||
},
|
},
|
||||||
|
|
||||||
title(token) {
|
|
||||||
const el = doc.createElement('h1');
|
|
||||||
appendChildren(token.children, el);
|
|
||||||
return el;
|
|
||||||
},
|
|
||||||
|
|
||||||
text(token) {
|
text(token) {
|
||||||
const el = doc.createElement('span');
|
const el = doc.createElement('span');
|
||||||
const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x) as Node);
|
const nodes = (token.node.props.text as string).split(/\r\n|\r|\n/).map(x => doc.createTextNode(x) as Node);
|
||||||
|
|
|
@ -18,10 +18,6 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin
|
||||||
return `**${appendChildren(token.children, opts)}**`;
|
return `**${appendChildren(token.children, opts)}**`;
|
||||||
},
|
},
|
||||||
|
|
||||||
big(token, opts) {
|
|
||||||
return `***${appendChildren(token.children, opts)}***`;
|
|
||||||
},
|
|
||||||
|
|
||||||
small(token, opts) {
|
small(token, opts) {
|
||||||
return `<small>${appendChildren(token.children, opts)}</small>`;
|
return `<small>${appendChildren(token.children, opts)}</small>`;
|
||||||
},
|
},
|
||||||
|
@ -34,30 +30,11 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin
|
||||||
return `<i>${appendChildren(token.children, opts)}</i>`;
|
return `<i>${appendChildren(token.children, opts)}</i>`;
|
||||||
},
|
},
|
||||||
|
|
||||||
motion(token, opts) {
|
fn(token, opts) {
|
||||||
return `<motion>${appendChildren(token.children, opts)}</motion>`;
|
const name = token.node.props?.name;
|
||||||
},
|
const args = token.node.props?.args || {};
|
||||||
|
const argsStr = Object.entries(args).map(([k, v]) => v === true ? k : `${k}=${v}`).join(',');
|
||||||
spin(token, opts) {
|
return `[${name}${argsStr !== '' ? '.' + argsStr : ''} ${appendChildren(token.children, opts)}]`;
|
||||||
const attr = token.node.props?.attr;
|
|
||||||
const post = attr ? ` ${attr}` : '';
|
|
||||||
return `<spin${post}>${appendChildren(token.children, opts)}</spin>`;
|
|
||||||
},
|
|
||||||
|
|
||||||
jump(token, opts) {
|
|
||||||
return `<jump>${appendChildren(token.children, opts)}</jump>`;
|
|
||||||
},
|
|
||||||
|
|
||||||
twitch(token, opts) {
|
|
||||||
return `<twitch>${appendChildren(token.children, opts)}</twitch>`;
|
|
||||||
},
|
|
||||||
|
|
||||||
shake(token, opts) {
|
|
||||||
return `<shake>${appendChildren(token.children, opts)}</shake>`;
|
|
||||||
},
|
|
||||||
|
|
||||||
flip(token, opts) {
|
|
||||||
return `<flip>${appendChildren(token.children, opts)}</flip>`;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
blockCode(token) {
|
blockCode(token) {
|
||||||
|
@ -104,10 +81,6 @@ export function toString(tokens: MfmForest | null, opts?: RestoreOptions): strin
|
||||||
return `${appendChildren(token.children, {doNyaize: false}).replace(/^/gm,'>').trim()}\n`;
|
return `${appendChildren(token.children, {doNyaize: false}).replace(/^/gm,'>').trim()}\n`;
|
||||||
},
|
},
|
||||||
|
|
||||||
title(token, opts) {
|
|
||||||
return `[${appendChildren(token.children, opts)}]\n`;
|
|
||||||
},
|
|
||||||
|
|
||||||
text(token, opts) {
|
text(token, opts) {
|
||||||
return (opts && opts.doNyaize) ? nyaize(token.node.props.text) : token.node.props.text;
|
return (opts && opts.doNyaize) ? nyaize(token.node.props.text) : token.node.props.text;
|
||||||
},
|
},
|
||||||
|
|
167
test/mfm.ts
167
test/mfm.ts
|
@ -227,16 +227,6 @@ describe('MFM', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('big', () => {
|
|
||||||
const tokens = parse('***Strawberry*** Pasta');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('big', [
|
|
||||||
text('Strawberry')
|
|
||||||
], {}),
|
|
||||||
text(' Pasta'),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('small', () => {
|
it('small', () => {
|
||||||
const tokens = parse('<small>smaller</small>');
|
const tokens = parse('<small>smaller</small>');
|
||||||
assert.deepStrictEqual(tokens, [
|
assert.deepStrictEqual(tokens, [
|
||||||
|
@ -246,133 +236,6 @@ describe('MFM', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('flip', () => {
|
|
||||||
const tokens = parse('<flip>foo</flip>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('flip', [
|
|
||||||
text('foo')
|
|
||||||
], {}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('spin', () => {
|
|
||||||
it('text', () => {
|
|
||||||
const tokens = parse('<spin>foo</spin>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('spin', [
|
|
||||||
text('foo')
|
|
||||||
], {
|
|
||||||
attr: null
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('emoji', () => {
|
|
||||||
const tokens = parse('<spin>:foo:</spin>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('spin', [
|
|
||||||
leaf('emoji', { name: 'foo' })
|
|
||||||
], {
|
|
||||||
attr: null
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('with attr', () => {
|
|
||||||
const tokens = parse('<spin left>:foo:</spin>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('spin', [
|
|
||||||
leaf('emoji', { name: 'foo' })
|
|
||||||
], {
|
|
||||||
attr: 'left'
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
/*
|
|
||||||
it('multi', () => {
|
|
||||||
const tokens = parse('<spin>:foo:</spin><spin>:foo:</spin>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('spin', [
|
|
||||||
leaf('emoji', { name: 'foo' })
|
|
||||||
], {
|
|
||||||
attr: null
|
|
||||||
}),
|
|
||||||
tree('spin', [
|
|
||||||
leaf('emoji', { name: 'foo' })
|
|
||||||
], {
|
|
||||||
attr: null
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('nested', () => {
|
|
||||||
const tokens = parse('<spin><spin>:foo:</spin></spin>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('spin', [
|
|
||||||
tree('spin', [
|
|
||||||
leaf('emoji', { name: 'foo' })
|
|
||||||
], {
|
|
||||||
attr: null
|
|
||||||
}),
|
|
||||||
], {
|
|
||||||
attr: null
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
});
|
|
||||||
|
|
||||||
it('jump', () => {
|
|
||||||
const tokens = parse('<jump>:foo:</jump>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('jump', [
|
|
||||||
leaf('emoji', { name: 'foo' })
|
|
||||||
], {}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('motion', () => {
|
|
||||||
it('by triple brackets', () => {
|
|
||||||
const tokens = parse('(((foo)))');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('motion', [
|
|
||||||
text('foo')
|
|
||||||
], {}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('by triple brackets (with other texts)', () => {
|
|
||||||
const tokens = parse('bar(((foo)))bar');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
text('bar'),
|
|
||||||
tree('motion', [
|
|
||||||
text('foo')
|
|
||||||
], {}),
|
|
||||||
text('bar'),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('by <motion> tag', () => {
|
|
||||||
const tokens = parse('<motion>foo</motion>');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
tree('motion', [
|
|
||||||
text('foo')
|
|
||||||
], {}),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('by <motion> tag (with other texts)', () => {
|
|
||||||
const tokens = parse('bar<motion>foo</motion>bar');
|
|
||||||
assert.deepStrictEqual(tokens, [
|
|
||||||
text('bar'),
|
|
||||||
tree('motion', [
|
|
||||||
text('foo')
|
|
||||||
], {}),
|
|
||||||
text('bar'),
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('mention', () => {
|
describe('mention', () => {
|
||||||
it('local', () => {
|
it('local', () => {
|
||||||
const tokens = parse('@himawari foo');
|
const tokens = parse('@himawari foo');
|
||||||
|
@ -1310,30 +1173,6 @@ describe('MFM', () => {
|
||||||
it('小さい字', () => {
|
it('小さい字', () => {
|
||||||
assert.deepStrictEqual(toString(parse('<small>小さい字</small>')), '<small>小さい字</small>');
|
assert.deepStrictEqual(toString(parse('<small>小さい字</small>')), '<small>小さい字</small>');
|
||||||
});
|
});
|
||||||
it('モーション', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('<motion>モーション</motion>')), '<motion>モーション</motion>');
|
|
||||||
});
|
|
||||||
it('モーション2', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('(((モーション)))')), '<motion>モーション</motion>');
|
|
||||||
});
|
|
||||||
it('ビッグ+', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('*** ビッグ+ ***')), '*** ビッグ+ ***');
|
|
||||||
});
|
|
||||||
it('回転', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('<spin>回転</spin>')), '<spin>回転</spin>');
|
|
||||||
});
|
|
||||||
it('右回転', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('<spin right>右回転</spin>')), '<spin right>右回転</spin>');
|
|
||||||
});
|
|
||||||
it('左回転', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('<spin left>左回転</spin>')), '<spin left>左回転</spin>');
|
|
||||||
});
|
|
||||||
it('往復回転', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('<spin alternate>往復回転</spin>')), '<spin alternate>往復回転</spin>');
|
|
||||||
});
|
|
||||||
it('ジャンプ', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('<jump>ジャンプ</jump>')), '<jump>ジャンプ</jump>');
|
|
||||||
});
|
|
||||||
it('コードブロック', () => {
|
it('コードブロック', () => {
|
||||||
assert.deepStrictEqual(toString(parse('```\nコードブロック\n```')), '```\nコードブロック\n```');
|
assert.deepStrictEqual(toString(parse('```\nコードブロック\n```')), '```\nコードブロック\n```');
|
||||||
});
|
});
|
||||||
|
@ -1352,12 +1191,6 @@ describe('MFM', () => {
|
||||||
it('詳細なしリンク', () => {
|
it('詳細なしリンク', () => {
|
||||||
assert.deepStrictEqual(toString(parse('?[詳細なしリンク](http://example.com)')), '?[詳細なしリンク](http://example.com)');
|
assert.deepStrictEqual(toString(parse('?[詳細なしリンク](http://example.com)')), '?[詳細なしリンク](http://example.com)');
|
||||||
});
|
});
|
||||||
it('【タイトル】', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('【タイトル】')), '[タイトル]');
|
|
||||||
});
|
|
||||||
it('[タイトル]', () => {
|
|
||||||
assert.deepStrictEqual(toString(parse('[タイトル]')), '[タイトル]');
|
|
||||||
});
|
|
||||||
it('インライン数式', () => {
|
it('インライン数式', () => {
|
||||||
assert.deepStrictEqual(toString(parse('\\(インライン数式\\)')), '\\(インライン数式\\)');
|
assert.deepStrictEqual(toString(parse('\\(インライン数式\\)')), '\\(インライン数式\\)');
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue