㊙️
This commit is contained in:
parent
2112fb3896
commit
9a270e59a4
4 changed files with 266 additions and 46 deletions
|
@ -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",
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
<template>
|
||||
<div style="overflow: hidden;">
|
||||
<FormBase class="znqjceqz">
|
||||
<div id="debug"></div>
|
||||
<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 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;">
|
||||
<section class="_formItem" style="text-align: center; padding: 0 16px;" @click="gravity">
|
||||
{{ $t('_aboutMisskey.about') }}
|
||||
</section>
|
||||
<FormGroup>
|
||||
|
@ -45,6 +48,7 @@
|
|||
<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>
|
||||
|
||||
|
|
168
src/client/scripts/physics.ts
Normal file
168
src/client/scripts/physics.ts
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
10
yarn.lock
10
yarn.lock
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue