diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-09-22 22:53:41 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-09-22 22:53:41 +0900 |
| commit | 338793d891d1657f158cd4dc83f998e124bd7e45 (patch) | |
| tree | d47080ad4fcff61ad5eafdb8eb1e3ca997739115 /src/client/components | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.91.0 (diff) | |
| download | misskey-338793d891d1657f158cd4dc83f998e124bd7e45.tar.gz misskey-338793d891d1657f158cd4dc83f998e124bd7e45.tar.bz2 misskey-338793d891d1657f158cd4dc83f998e124bd7e45.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/client/components')
| -rw-r--r-- | src/client/components/global/avatar.vue | 26 | ||||
| -rw-r--r-- | src/client/components/mfm.ts | 14 | ||||
| -rw-r--r-- | src/client/components/note-header.vue | 12 | ||||
| -rw-r--r-- | src/client/components/page-window.vue | 2 | ||||
| -rwxr-xr-x | src/client/components/signin.vue | 41 | ||||
| -rw-r--r-- | src/client/components/sparkle.vue | 180 | ||||
| -rw-r--r-- | src/client/components/ui/folder.vue | 3 | ||||
| -rw-r--r-- | src/client/components/ui/input.vue | 2 | ||||
| -rw-r--r-- | src/client/components/ui/menu.vue | 33 | ||||
| -rw-r--r-- | src/client/components/ui/textarea.vue | 2 |
10 files changed, 280 insertions, 35 deletions
diff --git a/src/client/components/global/avatar.vue b/src/client/components/global/avatar.vue index eea970ec9a..395ed5d8ce 100644 --- a/src/client/components/global/avatar.vue +++ b/src/client/components/global/avatar.vue @@ -73,6 +73,22 @@ export default defineComponent({ </script> <style lang="scss" scoped> +@keyframes earwiggleleft { + from { transform: rotate(37.6deg) skew(30deg); } + 25% { transform: rotate(10deg) skew(30deg); } + 50% { transform: rotate(20deg) skew(30deg); } + 75% { transform: rotate(0deg) skew(30deg); } + to { transform: rotate(37.6deg) skew(30deg); } +} + +@keyframes earwiggleright { + from { transform: rotate(-37.6deg) skew(-30deg); } + 30% { transform: rotate(-10deg) skew(-30deg); } + 55% { transform: rotate(-20deg) skew(-30deg); } + 75% { transform: rotate(0deg) skew(-30deg); } + to { transform: rotate(-37.6deg) skew(-30deg); } +} + .eiwwqkts { position: relative; display: inline-block; @@ -132,6 +148,16 @@ export default defineComponent({ border-radius: 75% 0 75% 75%; transform: rotate(-37.5deg) skew(-30deg); } + + &:hover { + &:before { + animation: earwiggleleft 1s infinite; + } + + &:after { + animation: earwiggleright 1s infinite; + } + } } } </style> diff --git a/src/client/components/mfm.ts b/src/client/components/mfm.ts index c248f934df..a228ca4b8d 100644 --- a/src/client/components/mfm.ts +++ b/src/client/components/mfm.ts @@ -8,6 +8,7 @@ import { concat } from '@client/../prelude/array'; import MkFormula from '@client/components/formula.vue'; import MkCode from '@client/components/code.vue'; import MkGoogle from '@client/components/google.vue'; +import MkSparkle from '@client/components/sparkle.vue'; import MkA from '@client/components/global/a.vue'; import { host } from '@client/config'; @@ -169,6 +170,19 @@ export default defineComponent({ style = this.$store.state.animatedMfm ? 'animation: mfm-rainbow 1s linear infinite;' : ''; break; } + case 'sparkle': { + if (!this.$store.state.animatedMfm) { + return genEl(token.children); + } + let count = token.props.args.count ? parseInt(token.props.args.count) : 10; + if (count > 100) { + count = 100; + } + const speed = token.props.args.speed ? parseFloat(token.props.args.speed) : 1; + return h(MkSparkle, { + count, speed, + }, genEl(token.children)); + } } if (style == null) { return h('span', {}, ['[', token.props.name, ...genEl(token.children), ']']); diff --git a/src/client/components/note-header.vue b/src/client/components/note-header.vue index 7758dea3ae..80bfea9b07 100644 --- a/src/client/components/note-header.vue +++ b/src/client/components/note-header.vue @@ -3,10 +3,10 @@ <MkA class="name" :to="userPage(note.user)" v-user-preview="note.user.id"> <MkUserName :user="note.user"/> </MkA> - <span class="is-bot" v-if="note.user.isBot">bot</span> - <span class="username"><MkAcct :user="note.user"/></span> - <span class="admin" v-if="note.user.isAdmin"><i class="fas fa-bookmark"></i></span> - <span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><i class="far fa-bookmark"></i></span> + <div class="is-bot" v-if="note.user.isBot">bot</div> + <div class="username"><MkAcct :user="note.user"/></div> + <div class="admin" v-if="note.user.isAdmin"><i class="fas fa-bookmark"></i></div> + <div class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><i class="far fa-bookmark"></i></div> <div class="info"> <span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span> <MkA class="created-at" :to="notePage(note)"> @@ -55,6 +55,7 @@ export default defineComponent({ white-space: nowrap; > .name { + flex-shrink: 1; display: block; margin: 0 .5em 0 0; padding: 0; @@ -81,17 +82,20 @@ export default defineComponent({ > .admin, > .moderator { + flex-shrink: 0; margin-right: 0.5em; color: var(--badge); } > .username { + flex-shrink: 9999999; margin: 0 .5em 0 0; overflow: hidden; text-overflow: ellipsis; } > .info { + flex-shrink: 0; margin-left: auto; font-size: 0.9em; diff --git a/src/client/components/page-window.vue b/src/client/components/page-window.vue index c83b040dd8..fbc9f0b7fd 100644 --- a/src/client/components/page-window.vue +++ b/src/client/components/page-window.vue @@ -8,7 +8,7 @@ @closed="$emit('closed')" > <template #header> - <XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()"/> + <XHeader :info="pageInfo" :back-button="history.length > 0" @back="back()" :close-button="true" @close="close()" :title-only="true"/> </template> <div class="yrolvcoq _flat_"> <component :is="component" v-bind="props" :ref="changePage"/> diff --git a/src/client/components/signin.vue b/src/client/components/signin.vue index c051288d0a..69f527b7d6 100755 --- a/src/client/components/signin.vue +++ b/src/client/components/signin.vue @@ -54,6 +54,7 @@ import { apiUrl, host } from '@client/config'; import { byteify, hexify } from '@client/scripts/2fa'; import * as os from '@client/os'; import { login } from '@client/account'; +import { showSuspendedDialog } from '../scripts/show-suspended-dialog'; export default defineComponent({ components: { @@ -169,15 +170,7 @@ export default defineComponent({ this.signing = false; this.challengeData = res; return this.queryKey(); - }).catch(() => { - os.dialog({ - type: 'error', - text: this.$ts.signinFailed - }); - this.challengeData = null; - this.totpLogin = false; - this.signing = false; - }); + }).catch(this.loginFailed); } else { this.totpLogin = true; this.signing = false; @@ -190,14 +183,36 @@ export default defineComponent({ }).then(res => { this.$emit('login', res); this.onLogin(res); - }).catch(() => { + }).catch(this.loginFailed); + } + }, + + loginFailed(err) { + switch (err.id) { + case '6cc579cc-885d-43d8-95c2-b8c7fc963280': { os.dialog({ type: 'error', - text: this.$ts.loginFailed + title: this.$ts.loginFailed, + text: this.$ts.noSuchUser }); - this.signing = false; - }); + break; + } + case 'e03a5f46-d309-4865-9b69-56282d94e1eb': { + showSuspendedDialog(); + break; + } + default: { + os.dialog({ + type: 'error', + title: this.$ts.loginFailed, + text: JSON.stringify(err) + }); + } } + + this.challengeData = null; + this.totpLogin = false; + this.signing = false; }, resetPassword() { diff --git a/src/client/components/sparkle.vue b/src/client/components/sparkle.vue new file mode 100644 index 0000000000..942412b445 --- /dev/null +++ b/src/client/components/sparkle.vue @@ -0,0 +1,180 @@ +<template> +<span class="mk-sparkle"> + <span ref="content"> + <slot></slot> + </span> + <canvas ref="canvas"></canvas> +</span> +</template> + +<script lang="ts"> +import { defineComponent } from 'vue'; +import * as os from '@client/os'; + +const sprite = new Image(); +sprite.src = "/static-assets/client/sparkle-spritesheet.png"; + + +export default defineComponent({ + props: { + count: { + type: Number, + required: true, + }, + speed: { + type: Number, + required: true, + }, + }, + data() { + return { + sprites: [0,6,13,20], + particles: [], + anim: null, + ctx: null, + }; + }, + methods: { + createSparkles(w, h, count) { + var holder = []; + + for (var i = 0; i < count; i++) { + + const color = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6); + + holder[i] = { + position: { + x: Math.floor(Math.random() * w), + y: Math.floor(Math.random() * h) + }, + style: this.sprites[ Math.floor(Math.random() * 4) ], + delta: { + x: Math.floor(Math.random() * 1000) - 500, + y: Math.floor(Math.random() * 1000) - 500 + }, + color: color, + opacity: Math.random(), + }; + + } + + return holder; + }, + draw(time) { + this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height); + this.ctx.beginPath(); + + const particleSize = Math.floor(this.fontSize / 2); + this.particles.forEach((particle) => { + var modulus = Math.floor(Math.random()*7); + + if (Math.floor(time) % modulus === 0) { + particle.style = this.sprites[ Math.floor(Math.random()*4) ]; + } + + this.ctx.save(); + this.ctx.globalAlpha = particle.opacity; + this.ctx.drawImage(sprite, particle.style, 0, 7, 7, particle.position.x, particle.position.y, particleSize, particleSize); + + this.ctx.globalCompositeOperation = "source-atop"; + this.ctx.globalAlpha = 0.5; + this.ctx.fillStyle = particle.color; + this.ctx.fillRect(particle.position.x, particle.position.y, particleSize, particleSize); + + this.ctx.restore(); + }); + this.ctx.stroke(); + }, + tick() { + this.anim = window.requestAnimationFrame((time) => { + if (!this.$refs.canvas) { + return; + } + this.particles.forEach((particle) => { + if (!particle) { + return; + } + var randX = Math.random() > Math.random() * 2; + var randY = Math.random() > Math.random() * 3; + + if (randX) { + particle.position.x += (particle.delta.x * this.speed) / 1500; + } + + if (!randY) { + particle.position.y -= (particle.delta.y * this.speed) / 800; + } + + if( particle.position.x > this.$refs.canvas.width ) { + particle.position.x = -7; + } else if (particle.position.x < -7) { + particle.position.x = this.$refs.canvas.width; + } + + if (particle.position.y > this.$refs.canvas.height) { + particle.position.y = -7; + particle.position.x = Math.floor(Math.random() * this.$refs.canvas.width); + } else if (particle.position.y < -7) { + particle.position.y = this.$refs.canvas.height; + particle.position.x = Math.floor(Math.random() * this.$refs.canvas.width); + } + + particle.opacity -= 0.005; + + if (particle.opacity <= 0) { + particle.opacity = 1; + } + }); + + this.draw(time); + + this.tick(); + }); + }, + resize() { + if (this.$refs.content) { + const contentRect = this.$refs.content.getBoundingClientRect(); + this.fontSize = parseFloat(getComputedStyle(this.$refs.content).fontSize); + const padding = this.fontSize * 0.2; + + this.$refs.canvas.width = parseInt(contentRect.width + padding); + this.$refs.canvas.height = parseInt(contentRect.height + padding); + + this.particles = this.createSparkles(this.$refs.canvas.width, this.$refs.canvas.height, this.count); + } + }, + }, + mounted() { + this.ctx = this.$refs.canvas.getContext('2d'); + + new ResizeObserver(this.resize).observe(this.$refs.content); + + this.resize(); + this.tick(); + }, + updated() { + this.resize(); + }, + destroyed() { + window.cancelAnimationFrame(this.anim); + }, +}); +</script> + +<style lang="scss" scoped> +.mk-sparkle { + position: relative; + display: inline-block; + + > span { + display: inline-block; + } + + > canvas { + position: absolute; + top: -0.1em; + left: -0.1em; + pointer-events: none; + } +} +</style> diff --git a/src/client/components/ui/folder.vue b/src/client/components/ui/folder.vue index 1f3593a74a..eecf1d8be1 100644 --- a/src/client/components/ui/folder.vue +++ b/src/client/components/ui/folder.vue @@ -99,7 +99,8 @@ export default defineComponent({ z-index: 10; position: sticky; top: var(--stickyTop, 0px); - background: var(--panel); + padding: var(--x-padding); + background: var(--x-header, var(--panel)); /* TODO panelの半透明バージョンをプログラマティックに作りたい background: var(--X17); -webkit-backdrop-filter: var(--blur, blur(8px)); diff --git a/src/client/components/ui/input.vue b/src/client/components/ui/input.vue index 05ce5d3e15..a916a0b035 100644 --- a/src/client/components/ui/input.vue +++ b/src/client/components/ui/input.vue @@ -245,7 +245,7 @@ export default defineComponent({ font-size: 1em; color: var(--fg); background: var(--panel); - border: solid 1px var(--inputBorder); + border: solid 0.5px var(--inputBorder); border-radius: 6px; outline: none; box-shadow: none; diff --git a/src/client/components/ui/menu.vue b/src/client/components/ui/menu.vue index d652d9b84f..26b4b04b11 100644 --- a/src/client/components/ui/menu.vue +++ b/src/client/components/ui/menu.vue @@ -41,7 +41,7 @@ </template> <script lang="ts"> -import { defineComponent, ref } from 'vue'; +import { defineComponent, ref, unref } from 'vue'; import { focusPrev, focusNext } from '@client/scripts/focus'; import contains from '@client/scripts/contains'; @@ -79,21 +79,26 @@ export default defineComponent({ }; }, }, - created() { - const items = ref(this.items.filter(item => item !== undefined)); + watch: { + items: { + handler() { + const items = ref(unref(this.items).filter(item => item !== undefined)); - for (let i = 0; i < items.value.length; i++) { - const item = items.value[i]; - - if (item && item.then) { // if item is Promise - items.value[i] = { type: 'pending' }; - item.then(actualItem => { - items.value[i] = actualItem; - }); - } - } + for (let i = 0; i < items.value.length; i++) { + const item = items.value[i]; + + if (item && item.then) { // if item is Promise + items.value[i] = { type: 'pending' }; + item.then(actualItem => { + items.value[i] = actualItem; + }); + } + } - this._items = items; + this._items = items; + }, + immediate: true + } }, mounted() { if (this.viaKeyboard) { diff --git a/src/client/components/ui/textarea.vue b/src/client/components/ui/textarea.vue index 53a141f011..08ac3182a9 100644 --- a/src/client/components/ui/textarea.vue +++ b/src/client/components/ui/textarea.vue @@ -212,7 +212,7 @@ export default defineComponent({ font-size: 1em; color: var(--fg); background: var(--panel); - border: solid 1px var(--inputBorder); + border: solid 0.5px var(--inputBorder); border-radius: 6px; outline: none; box-shadow: none; |