Compare commits

...

12 Commits

Author SHA1 Message Date
f0c4df1cc5 12.62.2 2020-12-06 22:52:18 +09:00
839784bc8c Fix #6926 2020-12-06 22:49:31 +09:00
b758ec96ef Fix #6929 2020-12-06 22:47:51 +09:00
2f8ceb9d22 Better physics 2020-12-06 17:35:21 +09:00
e05ae5ebc2 12.62.1 2020-12-06 13:02:36 +09:00
ebc43be4b3 Merge branch 'develop' of https://github.com/syuilo/misskey into develop 2020-12-06 13:02:26 +09:00
8543278ce3 Update about-misskey.vue 2020-12-06 13:02:01 +09:00
9a98de7bd8 Fix #6924 2020-12-06 13:00:17 +09:00
e1d69fb4ad Update about-misskey.vue 2020-12-06 12:57:36 +09:00
946f9b4a2b New Crowdin updates (#6920)
* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Ukrainian)
2020-12-06 12:52:27 +09:00
9a270e59a4 ㊙️ 2020-12-06 12:51:00 +09:00
2112fb3896 Add slideshow widget 2020-12-05 22:29:55 +09:00
15 changed files with 467 additions and 53 deletions

View File

@ -974,6 +974,7 @@ _widgets:
digitalClock: "Digitaluhr"
federation: "Föderation"
postForm: "Neue Notiz anfertigen"
slideshow: "Diashow"
_cw:
hide: "Ausblenden"
show: "Mehr anzeigen"

View File

@ -974,6 +974,7 @@ _widgets:
digitalClock: "Digital clock"
federation: "Federation"
postForm: "Compose a note"
slideshow: "Slideshow"
_cw:
hide: "Hide"
show: "Load more"

View File

@ -995,6 +995,7 @@ _widgets:
digitalClock: "デジタル時計"
federation: "連合"
postForm: "投稿フォーム"
slideshow: "スライドショー"
_cw:
hide: "隠す"

View File

@ -95,6 +95,7 @@ sensitive: "Содержимое не для всех"
add: "Добавить"
reaction: "Реакции"
reactionSettingDescription: "Подберите, что будет у вас в палитре реакций"
reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»."
rememberNoteVisibility: "Запоминать видимость заметок"
attachCancel: "Удалить вложение"
markAsSensitive: "Отметить как «не для всех»"
@ -319,6 +320,7 @@ pinnedUsers: "Прикреплённый пользователь"
pinnedUsersDescription: "Перечислите по одному имени пользователя в строке. Пользователи, перечисленные здесь, будут привязаны к закладке \"Изучение\"."
pinnedPages: "Закрепленные страницы"
pinnedPagesDescription: "Если хотите закрепить страницы на главной сайта, сюда можно добавить пути к ним, каждый в отдельной строке."
pinnedClipId: "Идентификатор закреплённой памятки"
pinnedNotes: "Закреплённая заметка"
hcaptcha: "hCaptcha"
enableHcaptcha: "Включить hCaptcha"
@ -972,6 +974,7 @@ _widgets:
digitalClock: "Цифровые часы"
federation: "Федерация"
postForm: "Форма отправки"
slideshow: "Показ слайдов"
_cw:
hide: "Спрятать"
show: "Показать еще"

View File

@ -819,32 +819,62 @@ _pages:
arg2: "Списки"
_pick:
arg1: "Списки"
arg2: "Позиція"
listLen: "Отримати довжину списку"
_listLen:
arg1: "Списки"
number: "Число"
stringToNumber: "Текст на число"
_stringToNumber:
arg1: "Текст"
numberToString: "Число на текст"
_numberToString:
arg1: "Число"
splitStrByLine: "Розбиття тексту на рядки"
_splitStrByLine:
arg1: "Текст"
ref: "Змінні"
aiScriptVar: "Змінна AiScript"
fn: "Функції"
_fn:
arg1: "Вихід"
arg1: "Вивід"
for: "Повторення"
_for:
arg1: "Кількість повторень"
arg2: "Дія"
types:
string: "Текст"
number: "Число"
boolean: "Прапорець"
array: "Списки"
_relayStatus:
requesting: "Очікує затвердження"
accepted: "Затверджено"
rejected: "Відхилено"
_notification:
fileUploaded: "Файл успішно завантажено"
youGotMention: "{name} згадує вас"
youGotReply: "{name} відповідає"
youGotQuote: "{name} цитує вас"
youRenoted: "{name} поширює"
youGotPoll: "{name} бере участь в опитуванні"
youGotMessagingMessageFromUser: "Повідомлення від {name}"
youGotMessagingMessageFromGroup: "Нове повідомлення в групі {name}"
youWereFollowed: "Новий підписник"
youReceivedFollowRequest: "Ви отримали запит на підписку"
yourFollowRequestAccepted: "Запит на підписку прийнято"
youWereInvitedToGroup: "Запрошення до групи"
_types:
all: "Все"
follow: "Підписки"
mention: "Згадка"
renote: "Поширити"
quote: "Цитата"
reply: "Відповіді"
renote: "Поширення"
quote: "Цитування"
reaction: "Реакції"
pollVote: "Опитування"
receiveFollowRequest: "Запит на підписку"
followRequestAccepted: "Прийнята підписка"
receiveFollowRequest: "Запити на підписку"
followRequestAccepted: "Прийняті підписки"
groupInvited: "Запрошення до груп"
app: "Сповіщення від додатків"
_deck:

View File

@ -974,6 +974,7 @@ _widgets:
digitalClock: "数字时钟"
federation: "联邦宇宙"
postForm: "投稿窗口"
slideshow: "幻灯片展示"
_cw:
hide: "隐藏"
show: "查看更多"

View File

@ -1,7 +1,7 @@
{
"name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>",
"version": "12.62.0",
"version": "12.62.2",
"codename": "indigo",
"repository": {
"type": "git",
@ -74,6 +74,7 @@
"@types/koa__multer": "2.0.2",
"@types/koa__router": "8.0.2",
"@types/markdown-it": "10.0.3",
"@types/matter-js": "0.14.7",
"@types/mocha": "7.0.2",
"@types/node": "14.0.22",
"@types/node-fetch": "2.5.7",
@ -175,6 +176,7 @@
"lookup-dns-cache": "2.1.0",
"markdown-it": "11.0.1",
"markdown-it-anchor": "6.0.1",
"matter-js": "0.14.2",
"mocha": "8.2.1",
"moji": "0.5.1",
"ms": "2.1.2",

View File

@ -1,50 +1,54 @@
<template>
<FormBase class="znqjceqz">
<section class="_formItem">
<div class="_formPanel" style="text-align: center; padding: 16px;">
<img src="/assets/icons/512.png" alt="" style="display: block; width: 100px; margin: 0 auto; border-radius: 16px;" ref="icon"/>
<div style="margin-top: 0.75em;">Misskey</div>
<div style="opacity: 0.5;">v{{ version }}</div>
</div>
</section>
<section class="_formItem" style="text-align: center; padding: 0 16px;">
{{ $t('_aboutMisskey.about') }}
</section>
<FormGroup>
<FormLink to="https://github.com/syuilo/misskey" external>
<template #icon><Fa :icon="faCode"/></template>
{{ $t('_aboutMisskey.source') }}
<template #suffix>GitHub</template>
</FormLink>
<FormLink to="https://crowdin.com/project/misskey" external>
<template #icon><Fa :icon="faLanguage"/></template>
{{ $t('_aboutMisskey.translation') }}
<template #suffix>Crowdin</template>
</FormLink>
<FormLink to="https://www.patreon.com/syuilo" external>
<template #icon><Fa :icon="faHandHoldingMedical"/></template>
{{ $t('_aboutMisskey.donate') }}
<template #suffix>Patreon</template>
</FormLink>
</FormGroup>
<FormGroup>
<template #label>{{ $t('_aboutMisskey.contributors') }}</template>
<FormLink to="https://github.com/syuilo" external>@syuilo</FormLink>
<FormLink to="https://github.com/AyaMorisawa" external>@AyaMorisawa</FormLink>
<FormLink to="https://github.com/mei23" external>@mei23</FormLink>
<FormLink to="https://github.com/acid-chicken" external>@acid-chicken</FormLink>
<FormLink to="https://github.com/tamaina" external>@tamaina</FormLink>
<FormLink to="https://github.com/rinsuki" external>@rinsuki</FormLink>
<FormLink to="https://github.com/Xeltica" external>@Xeltica</FormLink>
<FormLink to="https://github.com/u1-liquid" external>@u1-liquid</FormLink>
<template #caption><MkLink url="https://github.com/syuilo/misskey/graphs/contributors">{{ $t('_aboutMisskey.allContributors') }}</MkLink></template>
</FormGroup>
<FormGroup>
<template #label><Mfm text="[jelly ❤]"/> {{ $t('_aboutMisskey.patrons') }}</template>
<FormKeyValueView v-for="patron in patrons" :key="patron"><template #key>{{ patron }}</template></FormKeyValueView>
<template #caption>{{ $t('_aboutMisskey.morePatrons') }}</template>
</FormGroup>
</FormBase>
<div style="overflow: hidden;">
<FormBase class="znqjceqz">
<div id="debug"></div>
<section class="_formItem">
<div class="_formPanel" style="text-align: center; padding: 16px;" ref="about">
<img src="/assets/icons/512.png" alt="" style="display: block; width: 100px; margin: 0 auto; border-radius: 16px;" ref="icon" @load="iconLoaded" draggable="false"/>
<div style="margin: 0.75em auto 0 auto; width: max-content;">Misskey</div>
<div style="margin: 0 auto; opacity: 0.5; width: max-content;">v{{ version }}</div>
<span v-for="emoji in easterEggEmojis" :key="emoji.emoji" :class="{ _physics_circle_: !emoji.emoji.startsWith(':') }" :style="{ position: 'absolute', top: emoji.top, left: emoji.left, userSelect: 'none' }"><MkEmoji style="pointer-events: none; font-size: 24px; width: 24px;" :emoji="emoji.emoji" :custom-emojis="$store.state.instance.meta.emojis" :is-reaction="false" :normal="true" :no-style="true"/></span>
</div>
</section>
<section class="_formItem" style="text-align: center; padding: 0 16px;" @click="gravity">
{{ $t('_aboutMisskey.about') }}
</section>
<FormGroup>
<FormLink to="https://github.com/syuilo/misskey" external>
<template #icon><Fa :icon="faCode"/></template>
{{ $t('_aboutMisskey.source') }}
<template #suffix>GitHub</template>
</FormLink>
<FormLink to="https://crowdin.com/project/misskey" external>
<template #icon><Fa :icon="faLanguage"/></template>
{{ $t('_aboutMisskey.translation') }}
<template #suffix>Crowdin</template>
</FormLink>
<FormLink to="https://www.patreon.com/syuilo" external>
<template #icon><Fa :icon="faHandHoldingMedical"/></template>
{{ $t('_aboutMisskey.donate') }}
<template #suffix>Patreon</template>
</FormLink>
</FormGroup>
<FormGroup>
<template #label>{{ $t('_aboutMisskey.contributors') }}</template>
<FormLink to="https://github.com/syuilo" external>@syuilo</FormLink>
<FormLink to="https://github.com/AyaMorisawa" external>@AyaMorisawa</FormLink>
<FormLink to="https://github.com/mei23" external>@mei23</FormLink>
<FormLink to="https://github.com/acid-chicken" external>@acid-chicken</FormLink>
<FormLink to="https://github.com/tamaina" external>@tamaina</FormLink>
<FormLink to="https://github.com/rinsuki" external>@rinsuki</FormLink>
<FormLink to="https://github.com/Xeltica" external>@Xeltica</FormLink>
<FormLink to="https://github.com/u1-liquid" external>@u1-liquid</FormLink>
<template #caption><MkLink url="https://github.com/syuilo/misskey/graphs/contributors">{{ $t('_aboutMisskey.allContributors') }}</MkLink></template>
</FormGroup>
<FormGroup>
<template #label><Mfm text="[jelly ❤]"/> {{ $t('_aboutMisskey.patrons') }}</template>
<FormKeyValueView v-for="patron in patrons" :key="patron"><template #key>{{ patron }}</template></FormKeyValueView>
<template #caption>{{ $t('_aboutMisskey.morePatrons') }}</template>
</FormGroup>
</FormBase>
</div>
</template>
<script lang="ts">
@ -57,6 +61,7 @@ import FormBase from '@/components/form/base.vue';
import FormGroup from '@/components/form/group.vue';
import FormKeyValueView from '@/components/form/key-value-view.vue';
import MkLink from '@/components/link.vue';
import { physics } from '@/scripts/physics.ts';
import * as os from '@/os';
const patrons = [
@ -115,10 +120,24 @@ export default defineComponent({
},
version,
patrons,
easterEggReady: false,
easterEggEmojis: [],
easterEggEngine: null,
faInfoCircle, faCode, faLanguage, faHandHoldingMedical,
}
},
created() {
const emojis = this.$store.state.settings.reactions;
for (let i = 0; i < 32; i++) {
this.easterEggEmojis.push({
top: -(32 + (Math.random() * 256)) + 'px',
left: (Math.random() * 99) + '%',
emoji: emojis[Math.floor(Math.random() * emojis.length)],
});
}
},
mounted() {
VanillaTilt.init(this.$refs.icon, {
max: 30,
@ -127,6 +146,27 @@ export default defineComponent({
speed: 1000,
});
},
beforeUnmount() {
if (this.easterEggEngine) {
this.easterEggEngine.stop();
}
},
methods: {
iconLoaded() {
this.$nextTick(() => {
this.easterEggReady = true;
});
},
gravity() {
if (!this.easterEggReady) return;
this.easterEggReady = false;
this.$refs.icon.vanillaTilt.destroy();
this.easterEggEngine = physics(this.$refs.about);
}
}
});
</script>

View File

@ -24,7 +24,7 @@
</div>
<div class="_section">
<div class="_content">
<MkSwitch v-if="user.host == null && $store.state.i.isAdmin && (this.moderator || !user.isAdmin)" @update:value="toggleModerator" v-model:value="moderator">{{ $t('moderator') }}</MkSwitch>
<MkSwitch v-if="user.host == null && $store.state.i.isAdmin && (moderator || !user.isAdmin)" @update:value="toggleModerator" v-model:value="moderator">{{ $t('moderator') }}</MkSwitch>
<MkSwitch @update:value="toggleSilence" v-model:value="silenced">{{ $t('silence') }}</MkSwitch>
<MkSwitch @update:value="toggleSuspend" v-model:value="suspended">{{ $t('suspend') }}</MkSwitch>
</div>

View File

@ -0,0 +1,148 @@
import * as Matter from 'matter-js';
export function physics(container: HTMLElement) {
const containerWidth = container.offsetWidth;
const containerHeight = container.offsetHeight;
const containerCenterX = containerWidth / 2;
// サイズ固定化(要らないかも?)
container.style.position = 'relative';
container.style.boxSizing = 'border-box';
container.style.width = `${containerWidth}px`;
container.style.height = `${containerHeight}px`;
// create engine
const engine = Matter.Engine.create({
constraintIterations: 4,
positionIterations: 8,
velocityIterations: 8,
});
const world = engine.world;
// create renderer
const render = Matter.Render.create({
engine: engine,
//element: document.getElementById('debug'),
options: {
width: containerWidth,
height: containerHeight,
background: 'transparent', // transparent to hide
wireframeBackground: 'transparent', // transparent to hide
}
});
// Disable to hide debug
Matter.Render.run(render);
// create runner
const runner = Matter.Runner.create();
Matter.Runner.run(runner, engine);
const groundThickness = 1024;
const ground = Matter.Bodies.rectangle(containerCenterX, containerHeight + (groundThickness / 2), containerWidth, groundThickness, {
isStatic: true,
restitution: 0.1,
friction: 2
});
//const wallRight = Matter.Bodies.rectangle(window.innerWidth+50, window.innerHeight/2, 100, window.innerHeight, wallopts);
//const wallLeft = Matter.Bodies.rectangle(-50, window.innerHeight/2, 100, window.innerHeight, wallopts);
Matter.World.add(world, [
ground,
//wallRight,
//wallLeft,
]);
const objEls = Array.from(container.children);
const objs = [];
for (const objEl of objEls) {
let obj;
if (objEl.classList.contains('_physics_circle_')) {
obj = Matter.Bodies.circle(
objEl.offsetLeft + (objEl.offsetWidth / 2),
objEl.offsetTop + (objEl.offsetHeight / 2),
Math.max(objEl.offsetWidth, objEl.offsetHeight) / 2,
);
} else {
const style = window.getComputedStyle(objEl);
obj = Matter.Bodies.rectangle(
objEl.offsetLeft + (objEl.offsetWidth / 2),
objEl.offsetTop + (objEl.offsetHeight / 2),
objEl.offsetWidth,
objEl.offsetHeight,
{
chamfer: { radius: parseInt(style.borderRadius, 10) },
}
);
}
objEl.id = obj.id;
objs.push(obj);
}
Matter.World.add(engine.world, objs);
// Add mouse control
const mouse = Matter.Mouse.create(container);
const mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.05,
render: {
visible: false
}
}
});
Matter.World.add(engine.world, mouseConstraint);
// keep the mouse in sync with rendering
render.mouse = mouse;
for (const objEl of objEls) {
objEl.style.position = `absolute`;
objEl.style.top = 0;
objEl.style.left = 0;
objEl.style.margin = 0;
objEl.style.userSelect = 'none';
objEl.style.willChange = 'transform';
}
window.requestAnimationFrame(update);
let stop = false;
function update() {
for (const objEl of objEls) {
const obj = objs.find(obj => obj.id.toString() === objEl.id.toString());
if (obj == null) continue;
const x = (obj.position.x - objEl.offsetWidth / 2);
const y = (obj.position.y - objEl.offsetHeight / 2);
const angle = obj.angle;
objEl.style.transform = `translate(${x}px, ${y}px) rotate(${angle}rad)`;
}
if (!stop) {
window.requestAnimationFrame(update);
}
}
// 奈落に落ちたオブジェクトは消す
const intervalId = setInterval(() => {
for (const obj of objs) {
if (obj.position.y > (containerHeight + 1024)) Matter.World.remove(world, obj);
}
}, 1000 * 10);
return {
stop: () => {
stop = true;
Matter.Runner.stop(runner);
clearInterval(intervalId);
}
};
}

View File

@ -228,6 +228,12 @@ export default defineComponent({
> .title {
font-weight: bold;
}
> .content {
> img {
max-width: 100%;
}
}
}
}
}

View File

@ -13,6 +13,7 @@ export default function(app: App) {
app.component('MkwDigitalClock', defineAsyncComponent(() => import('./digital-clock.vue')));
app.component('MkwFederation', defineAsyncComponent(() => import('./federation.vue')));
app.component('MkwPostForm', defineAsyncComponent(() => import('./post-form.vue')));
app.component('MkwSlideshow', defineAsyncComponent(() => import('./slideshow.vue')));
}
export const widgets = [
@ -28,4 +29,5 @@ export const widgets = [
'digitalClock',
'federation',
'postForm',
'slideshow',
];

View File

@ -0,0 +1,168 @@
<template>
<div class="kvausudm _panel">
<div @click="choose">
<p v-if="props.folderId == null">
<template v-if="isCustomizeMode">{{ $t('folder-customize-mode') }}</template>
<template v-else>{{ $t('folder') }}</template>
</p>
<p v-if="props.folderId != null && images.length === 0 && !fetching">{{ $t('no-image') }}</p>
<div ref="slideA" class="slide a"></div>
<div ref="slideB" class="slide b"></div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { } from '@fortawesome/free-solid-svg-icons';
import define from './define';
import * as os from '@/os';
const widget = define({
name: 'slideshow',
props: () => ({
height: {
type: 'number',
default: 300,
},
folderId: {
type: 'string',
default: null,
hidden: true,
},
})
});
export default defineComponent({
extends: widget,
data() {
return {
images: [],
fetching: true,
clock: null
};
},
mounted() {
this.$nextTick(() => {
this.applySize();
});
if (this.props.folderId != null) {
this.fetch();
}
this.clock = setInterval(this.change, 10000);
},
beforeUnmount() {
clearInterval(this.clock);
},
methods: {
applySize() {
let h;
if (this.props.size == 1) {
h = 250;
} else {
h = 170;
}
this.$el.style.height = `${h}px`;
},
resize() {
if (this.props.size == 1) {
this.props.size = 0;
} else {
this.props.size++;
}
this.save();
this.applySize();
},
change() {
if (this.images.length == 0) return;
const index = Math.floor(Math.random() * this.images.length);
const img = `url(${ this.images[index].url })`;
(this.$refs.slideB as any).style.backgroundImage = img;
this.$refs.slideB.classList.add('anime');
setTimeout(() => {
// 既にこのウィジェットがunmountされていたら要素がない
if ((this.$refs.slideA as any) == null) return;
(this.$refs.slideA as any).style.backgroundImage = img;
this.$refs.slideB.classList.remove('anime');
}, 1000);
},
fetch() {
this.fetching = true;
os.api('drive/files', {
folderId: this.props.folderId,
type: 'image/*',
limit: 100
}).then(images => {
this.images = images;
this.fetching = false;
(this.$refs.slideA as any).style.backgroundImage = '';
(this.$refs.slideB as any).style.backgroundImage = '';
this.change();
});
},
choose() {
os.selectDriveFolder(false).then(folder => {
if (folder == null) {
return;
}
this.props.folderId = folder.id;
this.save();
this.fetch();
});
}
}
});
</script>
<style lang="scss" scoped>
.kvausudm {
position: relative;
> div {
width: 100%;
height: 100%;
cursor: pointer;
> p {
display: block;
margin: 1em;
text-align: center;
color: #888;
}
> * {
pointer-events: none;
}
> .slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
background-position: center;
&.b {
opacity: 0;
}
&.anime {
transition: opacity 1s;
opacity: 1;
}
}
}
}
</style>

View File

@ -142,6 +142,7 @@ export default define(meta, async (ps, me) => {
enableServiceWorker: instance.enableServiceWorker,
...(ps.detail ? {
pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles,
proxyRemoteFiles: instance.proxyRemoteFiles,

View File

@ -661,6 +661,11 @@
"@types/mdurl" "*"
highlight.js "^9.7.0"
"@types/matter-js@0.14.7":
version "0.14.7"
resolved "https://registry.yarnpkg.com/@types/matter-js/-/matter-js-0.14.7.tgz#b816f1e7b441ee7499027f9566e4fb5baea637b3"
integrity sha512-HLUhVTUoKsibpPZ2tCzoCC/f/UYRWPP9WCOUh5F61BlrUESFV5fE7eKq/CmdoEGkNrLW9v407zYlfrTc9hnGIw==
"@types/mdurl@*":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9"
@ -6116,6 +6121,11 @@ material-colors@^1.0.0:
resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
matter-js@0.14.2:
version "0.14.2"
resolved "https://registry.yarnpkg.com/matter-js/-/matter-js-0.14.2.tgz#8169af9e06fdc356ba9e72b49624eb329839883b"
integrity sha512-3ttVT8cJlQnGRjBa8MyVrGyvGmnmOkZ3YsyemIw+KwEEdVi70mo32FH1Eta2b3GfdDJFbMDRqyMQt4heNKBUEA==
mdn-data@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"