This commit is contained in:
syuilo 2020-12-06 12:51:00 +09:00
parent 2112fb3896
commit 9a270e59a4
4 changed files with 266 additions and 46 deletions

View file

@ -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_" :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

@ -0,0 +1,168 @@
import 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();
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
hasBounds: false,
enabled: true,
wireframes: false,
showSleeping: true,
showDebug: false,
showBroadphase: false,
showBounds: false,
showVelocity: false,
showCollisions: false,
showAxes: false,
showPositions: false,
showAngleIndicator: false,
showIds: false,
showShadows: false
}
});
// Disable to hide debug
Matter.Render.run(render);
// create runner
const runner = Matter.Runner.create();
Matter.Runner.run(runner, engine);
// add walls
const wallopts = {
isStatic: true,
restitution: 0.2,
friction: 1
};
const groundopts = {
isStatic: true,
restitution: 0.1,
friction: 2
};
const groundThickness = 100;
const ground = Matter.Bodies.rectangle(containerCenterX, containerHeight + (groundThickness / 2), containerWidth, groundThickness, groundopts);
//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,
{
restitution: 0.1,
friction: 4,
frictionAir: 0,
frictionStatic: 50,
density: 100,
}
);
} else {
const style = window.getComputedStyle(objEl);
obj = Matter.Bodies.rectangle(
objEl.offsetLeft + (objEl.offsetWidth / 2),
objEl.offsetTop + (objEl.offsetHeight / 2),
objEl.offsetWidth,
objEl.offsetHeight,
{
restitution: 0.1,
friction: 4,
frictionAir: 0,
frictionStatic: 50,
density: 100,
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: 1,
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);
}
}
return {
stop: () => {
stop = true;
Matter.Runner.stop(runner);
}
};
}

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"