summaryrefslogtreecommitdiff
path: root/packages/client/src/components
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-12-29 13:42:15 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-12-29 13:42:15 +0900
commit621fc5a715e372064bb178a24f07c8aa960f7f50 (patch)
tree4efab3afa32c533fc36bdb72c622619614125f5a /packages/client/src/components
parentMerge branch 'develop' (diff)
parent12.101.0 (diff)
downloadmisskey-621fc5a715e372064bb178a24f07c8aa960f7f50.tar.gz
misskey-621fc5a715e372064bb178a24f07c8aa960f7f50.tar.bz2
misskey-621fc5a715e372064bb178a24f07c8aa960f7f50.zip
Merge branch 'develop'
Diffstat (limited to 'packages/client/src/components')
-rw-r--r--packages/client/src/components/emoji-picker.vue8
-rw-r--r--packages/client/src/components/form/input.vue9
-rw-r--r--packages/client/src/components/form/select.vue9
-rw-r--r--packages/client/src/components/form/switch.vue110
-rw-r--r--packages/client/src/components/form/textarea.vue9
-rw-r--r--packages/client/src/components/global/a.vue5
-rw-r--r--packages/client/src/components/global/header.vue3
-rw-r--r--packages/client/src/components/global/url.vue88
-rw-r--r--packages/client/src/components/media-list.vue9
-rw-r--r--packages/client/src/components/mfm.ts9
-rw-r--r--packages/client/src/components/note-preview.vue4
-rw-r--r--packages/client/src/components/page-window.vue26
-rw-r--r--packages/client/src/components/reactions-viewer.reaction.vue2
-rw-r--r--packages/client/src/components/ripple.vue (renamed from packages/client/src/components/particle.vue)53
-rw-r--r--packages/client/src/components/signup.vue11
-rw-r--r--packages/client/src/components/sparkle.vue250
-rw-r--r--packages/client/src/components/ui/menu.vue2
-rw-r--r--packages/client/src/components/ui/modal.vue3
-rw-r--r--packages/client/src/components/ui/pagination.vue7
-rw-r--r--packages/client/src/components/ui/window.vue5
-rw-r--r--packages/client/src/components/updated.vue30
21 files changed, 300 insertions, 352 deletions
diff --git a/packages/client/src/components/emoji-picker.vue b/packages/client/src/components/emoji-picker.vue
index ff450246f9..a8eed1ca21 100644
--- a/packages/client/src/components/emoji-picker.vue
+++ b/packages/client/src/components/emoji-picker.vue
@@ -77,7 +77,7 @@
import { defineComponent, markRaw } from 'vue';
import { emojilist } from '@/scripts/emojilist';
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
-import Particle from '@/components/particle.vue';
+import Ripple from '@/components/ripple.vue';
import * as os from '@/os';
import { isTouchUsing } from '@/scripts/touch';
import { isMobile } from '@/scripts/is-mobile';
@@ -296,9 +296,9 @@ export default defineComponent({
if (ev) {
const el = ev.currentTarget || ev.target;
const rect = el.getBoundingClientRect();
- const x = rect.left + (el.clientWidth / 2);
- const y = rect.top + (el.clientHeight / 2);
- os.popup(Particle, { x, y }, {}, 'end');
+ const x = rect.left + (el.offsetWidth / 2);
+ const y = rect.top + (el.offsetHeight / 2);
+ os.popup(Ripple, { x, y }, {}, 'end');
}
const key = this.getKey(emoji);
diff --git a/packages/client/src/components/form/input.vue b/packages/client/src/components/form/input.vue
index c990b693f1..3533f4f27b 100644
--- a/packages/client/src/components/form/input.vue
+++ b/packages/client/src/components/form/input.vue
@@ -5,7 +5,7 @@
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
<input ref="inputEl"
v-model="v"
- v-panel
+ v-adaptive-border
:type="type"
:disabled="disabled"
:required="required"
@@ -243,7 +243,8 @@ export default defineComponent({
font-weight: normal;
font-size: 1em;
color: var(--fg);
- border: solid 0.5px var(--panel);
+ background: var(--panel);
+ border: solid 1px var(--panel);
border-radius: 6px;
outline: none;
box-shadow: none;
@@ -251,7 +252,7 @@ export default defineComponent({
transition: border-color 0.1s ease-out;
&:hover {
- border-color: var(--inputBorderHover);
+ border-color: var(--inputBorderHover) !important;
}
}
@@ -298,7 +299,7 @@ export default defineComponent({
&.focused {
> input {
- border-color: var(--accent);
+ border-color: var(--accent) !important;
//box-shadow: 0 0 0 4px var(--focus);
}
}
diff --git a/packages/client/src/components/form/select.vue b/packages/client/src/components/form/select.vue
index 9ecff1aa6f..afc53ca9c8 100644
--- a/packages/client/src/components/form/select.vue
+++ b/packages/client/src/components/form/select.vue
@@ -3,7 +3,9 @@
<div class="label" @click="focus"><slot name="label"></slot></div>
<div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick">
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
- <select ref="inputEl" v-model="v" v-panel
+ <select ref="inputEl"
+ v-model="v"
+ v-adaptive-border
class="select"
:disabled="disabled"
:required="required"
@@ -226,7 +228,7 @@ export default defineComponent({
&:hover {
> .select {
- border-color: var(--inputBorderHover);
+ border-color: var(--inputBorderHover) !important;
}
}
@@ -242,6 +244,7 @@ export default defineComponent({
font-weight: normal;
font-size: 1em;
color: var(--fg);
+ background: var(--panel);
border: solid 1px var(--panel);
border-radius: 6px;
outline: none;
@@ -295,7 +298,7 @@ export default defineComponent({
&.focused {
> select {
- border-color: var(--accent);
+ border-color: var(--accent) !important;
}
}
diff --git a/packages/client/src/components/form/switch.vue b/packages/client/src/components/form/switch.vue
index 239303a55a..aa9b09215e 100644
--- a/packages/client/src/components/form/switch.vue
+++ b/packages/client/src/components/form/switch.vue
@@ -2,10 +2,6 @@
<div
class="ziffeoms"
:class="{ disabled, checked }"
- role="switch"
- :aria-checked="checked"
- :aria-disabled="disabled"
- @click.prevent="toggle"
>
<input
ref="input"
@@ -13,18 +9,20 @@
:disabled="disabled"
@keydown.enter="toggle"
>
- <span v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button">
- <span class="handle"></span>
+ <span ref="button" v-adaptive-border v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle">
+ <i class="check fas fa-check"></i>
</span>
<span class="label">
- <span><slot></slot></span>
+ <span @click="toggle"><slot></slot></span>
<p class="caption"><slot name="caption"></slot></p>
</span>
</div>
</template>
<script lang="ts">
-import { defineComponent } from 'vue';
+import { defineComponent, ref, toRefs } from 'vue';
+import * as os from '@/os';
+import Ripple from '@/components/ripple.vue';
export default defineComponent({
props: {
@@ -37,17 +35,28 @@ export default defineComponent({
default: false
}
},
- computed: {
- checked(): boolean {
- return this.modelValue;
- }
+
+ setup(props, context) {
+ const button = ref<HTMLElement>();
+ const checked = toRefs(props).modelValue;
+ const toggle = () => {
+ if (props.disabled) return;
+ context.emit('update:modelValue', !checked.value);
+
+ if (!checked.value) {
+ const rect = button.value.getBoundingClientRect();
+ const x = rect.left + (button.value.offsetWidth / 2);
+ const y = rect.top + (button.value.offsetHeight / 2);
+ os.popup(Ripple, { x, y, particle: false }, {}, 'end');
+ }
+ };
+
+ return {
+ button,
+ checked,
+ toggle,
+ };
},
- methods: {
- toggle() {
- if (this.disabled) return;
- this.$emit('update:modelValue', !this.checked);
- }
- }
});
</script>
@@ -55,16 +64,7 @@ export default defineComponent({
.ziffeoms {
position: relative;
display: flex;
- cursor: pointer;
- transition: all 0.3s;
-
- &:first-child {
- margin-top: 0;
- }
-
- &:last-child {
- margin-bottom: 0;
- }
+ transition: all 0.2s ease;
> * {
user-select: none;
@@ -80,27 +80,32 @@ export default defineComponent({
> .button {
position: relative;
- display: inline-block;
+ display: inline-flex;
flex-shrink: 0;
margin: 0;
- width: 36px;
- height: 26px;
- background: var(--switchBg);
+ box-sizing: border-box;
+ width: 23px;
+ height: 23px;
outline: none;
- border-radius: 999px;
+ background: var(--panel);
+ border: solid 1px var(--panel);
+ border-radius: 4px;
+ cursor: pointer;
transition: inherit;
- > .handle {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 5px;
- margin: auto 0;
- border-radius: 100%;
- transition: background-color 0.3s, transform 0.3s;
- width: 16px;
- height: 16px;
- background-color: #fff;
+ > .check {
+ margin: auto;
+ opacity: 0;
+ color: var(--fgOnAccent);
+ font-size: 13px;
+ transform: scale(0.5);
+ transition: all 0.2s ease;
+ }
+ }
+
+ &:hover {
+ > .button {
+ border-color: var(--inputBorderHover) !important;
}
}
@@ -108,13 +113,13 @@ export default defineComponent({
margin-left: 16px;
margin-top: 2px;
display: block;
- cursor: pointer;
transition: inherit;
color: var(--fg);
> span {
display: block;
line-height: 20px;
+ cursor: pointer;
transition: inherit;
}
@@ -129,12 +134,6 @@ export default defineComponent({
}
}
- &:hover {
- > .button {
- background-color: var(--accentedBg);
- }
- }
-
&.disabled {
opacity: 0.6;
cursor: not-allowed;
@@ -142,11 +141,12 @@ export default defineComponent({
&.checked {
> .button {
- background-color: var(--accent);
- border-color: var(--accent);
+ background-color: var(--accent) !important;
+ border-color: var(--accent) !important;
- > .handle {
- transform: translateX(10px);
+ > .check {
+ opacity: 1;
+ transform: scale(1);
}
}
}
diff --git a/packages/client/src/components/form/textarea.vue b/packages/client/src/components/form/textarea.vue
index 98fd0da94b..c9ba9b97a2 100644
--- a/packages/client/src/components/form/textarea.vue
+++ b/packages/client/src/components/form/textarea.vue
@@ -4,7 +4,7 @@
<div class="input" :class="{ disabled, focused, tall, pre }">
<textarea ref="inputEl"
v-model="v"
- v-panel
+ v-adaptive-border
:class="{ code, _monospace: code }"
:disabled="disabled"
:required="required"
@@ -210,7 +210,8 @@ export default defineComponent({
font-weight: normal;
font-size: 1em;
color: var(--fg);
- border: solid 0.5px var(--panel);
+ background: var(--panel);
+ border: solid 1px var(--panel);
border-radius: 6px;
outline: none;
box-shadow: none;
@@ -218,13 +219,13 @@ export default defineComponent({
transition: border-color 0.1s ease-out;
&:hover {
- border-color: var(--inputBorderHover);
+ border-color: var(--inputBorderHover) !important;
}
}
&.focused {
> textarea {
- border-color: var(--accent);
+ border-color: var(--accent) !important;
}
}
diff --git a/packages/client/src/components/global/a.vue b/packages/client/src/components/global/a.vue
index 5db61203c6..77ee7525a4 100644
--- a/packages/client/src/components/global/a.vue
+++ b/packages/client/src/components/global/a.vue
@@ -106,11 +106,6 @@ export default defineComponent({
return;
}
- if (this.to.startsWith('/my/messaging')) {
- if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window();
- if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout();
- }
-
if (this.behavior) {
if (this.behavior === 'window') {
return this.window();
diff --git a/packages/client/src/components/global/header.vue b/packages/client/src/components/global/header.vue
index 2e03d783af..a241ece407 100644
--- a/packages/client/src/components/global/header.vue
+++ b/packages/client/src/components/global/header.vue
@@ -6,7 +6,7 @@
<i v-else-if="info.icon" class="icon" :class="info.icon"></i>
<div class="title">
- <MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/>
+ <MkUserName v-if="info.userName" :user="info.userName" :nowrap="true" class="title"/>
<div v-else-if="info.title" class="title">{{ info.title }}</div>
<div v-if="!narrow && info.subtitle" class="subtitle">
{{ info.subtitle }}
@@ -268,6 +268,7 @@ export default defineComponent({
> .titleContainer {
display: flex;
align-items: center;
+ max-width: 400px;
overflow: auto;
white-space: nowrap;
text-align: left;
diff --git a/packages/client/src/components/global/url.vue b/packages/client/src/components/global/url.vue
index 097fcddef6..56a8c3453a 100644
--- a/packages/client/src/components/global/url.vue
+++ b/packages/client/src/components/global/url.vue
@@ -1,7 +1,5 @@
<template>
-<component :is="self ? 'MkA' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
- @mouseover="onMouseover"
- @mouseleave="onMouseleave"
+<component :is="self ? 'MkA' : 'a'" ref="el" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
@contextmenu.stop="() => {}"
>
<template v-if="!self">
@@ -20,11 +18,11 @@
</template>
<script lang="ts">
-import { defineComponent } from 'vue';
+import { defineComponent, ref } from 'vue';
import { toUnicode as decodePunycode } from 'punycode/';
import { url as local } from '@/config';
-import { isTouchUsing } from '@/scripts/touch';
import * as os from '@/os';
+import { useTooltip } from '@/scripts/use-tooltip';
export default defineComponent({
props: {
@@ -35,74 +33,36 @@ export default defineComponent({
rel: {
type: String,
required: false,
+ default: null,
}
},
- data() {
- const self = this.url.startsWith(local);
+ setup(props) {
+ const self = props.url.startsWith(local);
+ const url = new URL(props.url);
+ const el = ref();
+
+ useTooltip(el, (showing) => {
+ os.popup(import('@/components/url-preview-popup.vue'), {
+ showing,
+ url: props.url,
+ source: el.value,
+ }, {}, 'closed');
+ });
+
return {
local,
- schema: null as string | null,
- hostname: null as string | null,
- port: null as string | null,
- pathname: null as string | null,
- query: null as string | null,
- hash: null as string | null,
+ schema: url.protocol,
+ hostname: decodePunycode(url.hostname),
+ port: url.port,
+ pathname: decodeURIComponent(url.pathname),
+ query: decodeURIComponent(url.search),
+ hash: decodeURIComponent(url.hash),
self: self,
attr: self ? 'to' : 'href',
target: self ? null : '_blank',
- showTimer: null,
- hideTimer: null,
- checkTimer: null,
- close: null,
+ el,
};
},
- created() {
- const url = new URL(this.url);
- this.schema = url.protocol;
- this.hostname = decodePunycode(url.hostname);
- this.port = url.port;
- this.pathname = decodeURIComponent(url.pathname);
- this.query = decodeURIComponent(url.search);
- this.hash = decodeURIComponent(url.hash);
- },
- methods: {
- async showPreview() {
- if (!document.body.contains(this.$el)) return;
- if (this.close) return;
-
- const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
- url: this.url,
- source: this.$el
- });
-
- this.close = () => {
- dispose();
- };
-
- this.checkTimer = setInterval(() => {
- if (!document.body.contains(this.$el)) this.closePreview();
- }, 1000);
- },
- closePreview() {
- if (this.close) {
- clearInterval(this.checkTimer);
- this.close();
- this.close = null;
- }
- },
- onMouseover() {
- if (isTouchUsing) return;
- clearTimeout(this.showTimer);
- clearTimeout(this.hideTimer);
- this.showTimer = setTimeout(this.showPreview, 500);
- },
- onMouseleave() {
- if (isTouchUsing) return;
- clearTimeout(this.showTimer);
- clearTimeout(this.hideTimer);
- this.hideTimer = setTimeout(this.closePreview, 500);
- }
- }
});
</script>
diff --git a/packages/client/src/components/media-list.vue b/packages/client/src/components/media-list.vue
index c987ff5ff1..2970d06c97 100644
--- a/packages/client/src/components/media-list.vue
+++ b/packages/client/src/components/media-list.vue
@@ -105,6 +105,7 @@ export default defineComponent({
return {
previewable,
gallery,
+ pswpZIndex: os.claimZIndex('middle'),
};
},
});
@@ -188,3 +189,11 @@ export default defineComponent({
}
}
</style>
+
+<style lang="scss">
+.pswp {
+ // なぜか機能しない
+ //z-index: v-bind(pswpZIndex);
+ z-index: 2000000;
+}
+</style>
diff --git a/packages/client/src/components/mfm.ts b/packages/client/src/components/mfm.ts
index d1da365d9a..2e6d26476a 100644
--- a/packages/client/src/components/mfm.ts
+++ b/packages/client/src/components/mfm.ts
@@ -175,14 +175,7 @@ export default defineComponent({
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));
+ return h(MkSparkle, {}, genEl(token.children));
}
case 'rotate': {
const degrees = parseInt(token.props.args.deg) || '90';
diff --git a/packages/client/src/components/note-preview.vue b/packages/client/src/components/note-preview.vue
index 6e3eba9306..bdcb8d5eed 100644
--- a/packages/client/src/components/note-preview.vue
+++ b/packages/client/src/components/note-preview.vue
@@ -7,7 +7,7 @@
</div>
<div class="body">
<div class="content">
- <Mfm :text="text" :author="$i" :i="$i"/>
+ <Mfm :text="text.trim()" :author="$i" :i="$i"/>
</div>
</div>
</div>
@@ -61,6 +61,7 @@ export default defineComponent({
width: 40px;
height: 40px;
border-radius: 8px;
+ pointer-events: none;
}
> .main {
@@ -69,6 +70,7 @@ export default defineComponent({
> .header {
margin-bottom: 2px;
+ font-weight: bold;
}
> .body {
diff --git a/packages/client/src/components/page-window.vue b/packages/client/src/components/page-window.vue
index 39c185b3e0..ec7451d5aa 100644
--- a/packages/client/src/components/page-window.vue
+++ b/packages/client/src/components/page-window.vue
@@ -16,7 +16,13 @@
<template #headerLeft>
<button v-if="history.length > 0" v-tooltip="$ts.goBack" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
</template>
- <div class="yrolvcoq">
+ <template #headerRight>
+ <button v-tooltip="$ts.showInPage" class="_button" @click="expand()"><i class="fas fa-expand-alt"></i></button>
+ <button v-tooltip="$ts.popout" class="_button" @click="popout()"><i class="fas fa-external-link-alt"></i></button>
+ <button class="_button" @click="menu"><i class="fas fa-ellipsis-h"></i></button>
+ </template>
+
+ <div class="yrolvcoq" :style="{ background: pageInfo?.bg }">
<MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<component :is="component" v-bind="props" :ref="changePage"/>
@@ -33,6 +39,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
import { resolve } from '@/router';
import { url } from '@/config';
import * as symbols from '@/symbols';
+import * as os from '@/os';
export default defineComponent({
components: {
@@ -139,6 +146,23 @@ export default defineComponent({
this.props = props;
},
+ menu(ev) {
+ os.popupMenu([{
+ icon: 'fas fa-external-link-alt',
+ text: this.$ts.openInNewTab,
+ action: () => {
+ window.open(this.url, '_blank');
+ this.$refs.window.close();
+ }
+ }, {
+ icon: 'fas fa-link',
+ text: this.$ts.copyLink,
+ action: () => {
+ copyToClipboard(this.url);
+ }
+ }], ev.currentTarget || ev.target);
+ },
+
back() {
this.navigate(this.history.pop(), false);
},
diff --git a/packages/client/src/components/reactions-viewer.reaction.vue b/packages/client/src/components/reactions-viewer.reaction.vue
index a1de99f018..bbf518549c 100644
--- a/packages/client/src/components/reactions-viewer.reaction.vue
+++ b/packages/client/src/components/reactions-viewer.reaction.vue
@@ -2,7 +2,7 @@
<button
v-if="count > 0"
ref="buttonRef"
- v-particle="canToggle"
+ v-ripple="canToggle"
class="hkzvhatu _button"
:class="{ reacted: note.myReaction == reaction, canToggle }"
@click="toggleReaction()"
diff --git a/packages/client/src/components/particle.vue b/packages/client/src/components/ripple.vue
index d82705c1e8..272eacbc6e 100644
--- a/packages/client/src/components/particle.vue
+++ b/packages/client/src/components/ripple.vue
@@ -1,5 +1,5 @@
<template>
-<div class="vswabwbm" :style="{ top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }">
+<div class="vswabwbm" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }">
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<circle fill="none" cx="64" cy="64">
<animate attributeName="r"
@@ -52,7 +52,8 @@
</template>
<script lang="ts">
-import { defineComponent } from 'vue';
+import { defineComponent, onMounted } from 'vue';
+import * as os from '@/os';
export default defineComponent({
props: {
@@ -63,37 +64,46 @@ export default defineComponent({
y: {
type: Number,
required: true
+ },
+ particle: {
+ type: Boolean,
+ required: false,
+ default: true,
}
},
emits: ['end'],
- data() {
+ setup(props, context) {
const particles = [];
const origin = 64;
const colors = ['#FF1493', '#00FFFF', '#FFE202'];
- for (let i = 0; i < 12; i++) {
- const angle = Math.random() * (Math.PI * 2);
- const pos = Math.random() * 16;
- const velocity = 16 + (Math.random() * 48);
- particles.push({
- size: 4 + (Math.random() * 8),
- xA: origin + (Math.sin(angle) * pos),
- yA: origin + (Math.cos(angle) * pos),
- xB: origin + (Math.sin(angle) * (pos + velocity)),
- yB: origin + (Math.cos(angle) * (pos + velocity)),
- color: colors[Math.floor(Math.random() * colors.length)]
- });
+ if (props.particle) {
+ for (let i = 0; i < 12; i++) {
+ const angle = Math.random() * (Math.PI * 2);
+ const pos = Math.random() * 16;
+ const velocity = 16 + (Math.random() * 48);
+ particles.push({
+ size: 4 + (Math.random() * 8),
+ xA: origin + (Math.sin(angle) * pos),
+ yA: origin + (Math.cos(angle) * pos),
+ xB: origin + (Math.sin(angle) * (pos + velocity)),
+ yB: origin + (Math.cos(angle) * (pos + velocity)),
+ color: colors[Math.floor(Math.random() * colors.length)]
+ });
+ }
}
+ onMounted(() => {
+ setTimeout(() => {
+ context.emit('end');
+ }, 1100);
+ });
+
return {
- particles
+ particles,
+ zIndex: os.claimZIndex('high'),
};
},
- mounted() {
- setTimeout(() => {
- this.$emit('end');
- }, 1100);
- }
});
</script>
@@ -101,7 +111,6 @@ export default defineComponent({
.vswabwbm {
pointer-events: none;
position: fixed;
- z-index: 1000000;
width: 128px;
height: 128px;
diff --git a/packages/client/src/components/signup.vue b/packages/client/src/components/signup.vue
index 8668d1d076..38a9fd55f1 100644
--- a/packages/client/src/components/signup.vue
+++ b/packages/client/src/components/signup.vue
@@ -51,14 +51,13 @@
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</span>
</template>
</MkInput>
- <label v-if="meta.tosUrl" class="_formBlock tou">
- <input v-model="ToSAgreement" type="checkbox">
+ <MkSwitch v-if="meta.tosUrl" v-model="ToSAgreement" class="_formBlock tou">
<I18n :src="$ts.agreeTo">
<template #0>
<a :href="meta.tosUrl" class="_link" target="_blank">{{ $ts.tos }}</a>
</template>
</I18n>
- </label>
+ </MkSwitch>
<captcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
<captcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
<MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ $ts.start }}</MkButton>
@@ -258,11 +257,5 @@ export default defineComponent({
.captcha {
margin: 16px 0;
}
-
- > .tou {
- display: block;
- margin: 16px 0;
- cursor: pointer;
- }
}
</style>
diff --git a/packages/client/src/components/sparkle.vue b/packages/client/src/components/sparkle.vue
index 21b57f1580..f52e5a3f9b 100644
--- a/packages/client/src/components/sparkle.vue
+++ b/packages/client/src/components/sparkle.vue
@@ -1,161 +1,121 @@
<template>
<span class="mk-sparkle">
- <span ref="content">
+ <span ref="el">
<slot></slot>
</span>
- <canvas ref="canvas"></canvas>
+ <!-- なぜか path に対する key が機能しないため
+ <svg :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg">
+ <path v-for="particle in particles" :key="particle.id" style="transform-origin: center; transform-box: fill-box;"
+ :transform="`translate(${particle.x} ${particle.y})`"
+ :fill="particle.color"
+ d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
+ >
+ <animateTransform
+ attributeName="transform"
+ attributeType="XML"
+ type="rotate"
+ from="0 0 0"
+ to="360 0 0"
+ :dur="`${particle.dur}ms`"
+ repeatCount="indefinite"
+ additive="sum"
+ />
+ <animateTransform
+ attributeName="transform"
+ attributeType="XML"
+ type="scale"
+ :values="`0; ${particle.size}; 0`"
+ :dur="`${particle.dur}ms`"
+ repeatCount="indefinite"
+ additive="sum"
+ />
+ </path>
+ </svg>
+ -->
+ <svg v-for="particle in particles" :key="particle.id" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg">
+ <path style="transform-origin: center; transform-box: fill-box;"
+ :transform="`translate(${particle.x} ${particle.y})`"
+ :fill="particle.color"
+ d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
+ >
+ <animateTransform
+ attributeName="transform"
+ attributeType="XML"
+ type="rotate"
+ from="0 0 0"
+ to="360 0 0"
+ :dur="`${particle.dur}ms`"
+ repeatCount="1"
+ additive="sum"
+ />
+ <animateTransform
+ attributeName="transform"
+ attributeType="XML"
+ type="scale"
+ :values="`0; ${particle.size}; 0`"
+ :dur="`${particle.dur}ms`"
+ repeatCount="1"
+ additive="sum"
+ />
+ </path>
+ </svg>
</span>
</template>
<script lang="ts">
-import { defineComponent } from 'vue';
+import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
import * as os from '@/os';
-const sprite = new Image();
-sprite.src = '/client-assets/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,
- };
- },
- unmounted() {
- window.cancelAnimationFrame(this.anim);
- },
- mounted() {
- this.ctx = this.$refs.canvas.getContext('2d');
-
- new ResizeObserver(this.resize).observe(this.$refs.content);
-
- this.resize();
- this.tick();
- },
- updated() {
- this.resize();
- },
- methods: {
- createSparkles(w, h, count) {
- const holder = [];
-
- for (let 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();
+ setup() {
+ const particles = ref([]);
+ const el = ref<HTMLElement>();
+ const width = ref(0);
+ const height = ref(0);
+ const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];
- 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();
+ onMounted(() => {
+ const ro = new ResizeObserver((entries, observer) => {
+ width.value = el.value?.offsetWidth + 64;
+ height.value = el.value?.offsetHeight + 64;
});
- 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);
+ ro.observe(el.value);
+ let stop = false;
+ const add = () => {
+ if (stop) return;
+ const x = (Math.random() * (width.value - 64));
+ const y = (Math.random() * (height.value - 64));
+ const sizeFactor = Math.random();
+ const particle = {
+ id: Math.random().toString(),
+ x,
+ y,
+ size: 0.2 + ((sizeFactor / 10) * 3),
+ dur: 1000 + (sizeFactor * 1000),
+ color: colors[Math.floor(Math.random() * colors.length)],
+ };
+ particles.value.push(particle);
+ window.setTimeout(() => {
+ particles.value = particles.value.filter(x => x.id !== particle.id);
+ }, particle.dur - 100);
- this.tick();
+ window.setTimeout(() => {
+ add();
+ }, 500 + (Math.random() * 500));
+ };
+ add();
+ onUnmounted(() => {
+ ro.disconnect();
+ stop = true;
});
- },
- 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);
- }
- },
+ return {
+ el,
+ width,
+ height,
+ particles,
+ };
},
});
</script>
@@ -169,10 +129,10 @@ export default defineComponent({
display: inline-block;
}
- > canvas {
+ > svg {
position: absolute;
- top: -0.1em;
- left: -0.1em;
+ top: -32px;
+ left: -32px;
pointer-events: none;
}
}
diff --git a/packages/client/src/components/ui/menu.vue b/packages/client/src/components/ui/menu.vue
index 869709cf21..6f3f277b11 100644
--- a/packages/client/src/components/ui/menu.vue
+++ b/packages/client/src/components/ui/menu.vue
@@ -284,7 +284,7 @@ export default defineComponent({
}
&.asDrawer {
- padding: 12px 0;
+ padding: 12px 0 calc(env(safe-area-inset-bottom, 0px) + 12px) 0;
width: 100%;
> .item {
diff --git a/packages/client/src/components/ui/modal.vue b/packages/client/src/components/ui/modal.vue
index b09d04c450..3e2e59b27c 100644
--- a/packages/client/src/components/ui/modal.vue
+++ b/packages/client/src/components/ui/modal.vue
@@ -13,6 +13,7 @@
import { defineComponent, nextTick, onMounted, computed, PropType, ref, watch } from 'vue';
import * as os from '@/os';
import { isTouchUsing } from '@/scripts/touch';
+import { defaultStore } from '@/store';
function getFixedContainer(el: Element | null): Element | null {
if (el == null || el.tagName === 'BODY') return null;
@@ -77,7 +78,7 @@ export default defineComponent({
const zIndex = os.claimZIndex(props.zPriority);
const type = computed(() => {
if (props.preferType === 'auto') {
- if (isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
+ if (!defaultStore.state.disableDrawer && isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
return 'drawer';
} else {
return props.src != null ? 'popup' : 'dialog';
diff --git a/packages/client/src/components/ui/pagination.vue b/packages/client/src/components/ui/pagination.vue
index 00200efd3c..64af4a54f7 100644
--- a/packages/client/src/components/ui/pagination.vue
+++ b/packages/client/src/components/ui/pagination.vue
@@ -5,7 +5,12 @@
<MkError v-else-if="error" @retry="init()"/>
<div v-else-if="empty" key="_empty_" class="empty">
- <slot name="empty"></slot>
+ <slot name="empty">
+ <div class="_fullinfo">
+ <img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
+ <div>{{ $ts.nothing }}</div>
+ </div>
+ </slot>
</div>
<div v-else class="cxiknjgy">
diff --git a/packages/client/src/components/ui/window.vue b/packages/client/src/components/ui/window.vue
index d01498d8df..bd33289ccc 100644
--- a/packages/client/src/components/ui/window.vue
+++ b/packages/client/src/components/ui/window.vue
@@ -414,6 +414,10 @@ export default defineComponent({
}
}
+ > .left {
+ min-width: 16px;
+ }
+
> .title {
flex: 1;
position: relative;
@@ -421,7 +425,6 @@ export default defineComponent({
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
- text-align: center;
cursor: move;
}
}
diff --git a/packages/client/src/components/updated.vue b/packages/client/src/components/updated.vue
index 74f54524be..375ac0dbbb 100644
--- a/packages/client/src/components/updated.vue
+++ b/packages/client/src/components/updated.vue
@@ -1,7 +1,7 @@
<template>
<MkModal ref="modal" :z-priority="'middle'" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="ewlycnyt">
- <div class="title">{{ $ts.misskeyUpdated }}</div>
+ <div class="title"><MkSparkle>{{ $ts.misskeyUpdated }}</MkSparkle></div>
<div class="version">✨{{ version }}🚀</div>
<MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton>
<MkButton class="gotIt" primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton>
@@ -9,31 +9,19 @@
</MkModal>
</template>
-<script lang="ts">
-import { defineComponent } from 'vue';
+<script lang="ts" setup>
+import { ref } from 'vue';
import MkModal from '@/components/ui/modal.vue';
import MkButton from '@/components/ui/button.vue';
+import MkSparkle from '@/components/sparkle.vue';
import { version } from '@/config';
-export default defineComponent({
- components: {
- MkModal,
- MkButton,
- },
+const modal = ref();
- data() {
- return {
- version: version,
- };
- },
-
- methods: {
- whatIsNew() {
- this.$refs.modal.close();
- window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank');
- }
- }
-});
+const whatIsNew = () => {
+ modal.value.close();
+ window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank');
+};
</script>
<style lang="scss" scoped>