summaryrefslogtreecommitdiff
path: root/src/client/components/global
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2021-11-12 02:02:25 +0900
commit0e4a111f81cceed275d9bec2695f6e401fb654d8 (patch)
tree40874799472fa07416f17b50a398ac33b7771905 /src/client/components/global
parentupdate deps (diff)
downloadmisskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.gz
misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.tar.bz2
misskey-0e4a111f81cceed275d9bec2695f6e401fb654d8.zip
refactoring
Resolve #7779
Diffstat (limited to 'src/client/components/global')
-rw-r--r--src/client/components/global/a.vue138
-rw-r--r--src/client/components/global/acct.vue38
-rw-r--r--src/client/components/global/ad.vue200
-rw-r--r--src/client/components/global/avatar.vue163
-rw-r--r--src/client/components/global/ellipsis.vue34
-rw-r--r--src/client/components/global/emoji.vue125
-rw-r--r--src/client/components/global/error.vue46
-rw-r--r--src/client/components/global/header.vue360
-rw-r--r--src/client/components/global/i18n.ts42
-rw-r--r--src/client/components/global/loading.vue92
-rw-r--r--src/client/components/global/misskey-flavored-markdown.vue157
-rw-r--r--src/client/components/global/spacer.vue76
-rw-r--r--src/client/components/global/sticky-container.vue74
-rw-r--r--src/client/components/global/time.vue73
-rw-r--r--src/client/components/global/url.vue142
-rw-r--r--src/client/components/global/user-name.vue20
16 files changed, 0 insertions, 1780 deletions
diff --git a/src/client/components/global/a.vue b/src/client/components/global/a.vue
deleted file mode 100644
index 952dfb1841..0000000000
--- a/src/client/components/global/a.vue
+++ /dev/null
@@ -1,138 +0,0 @@
-<template>
-<a :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
- <slot></slot>
-</a>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import * as os from '@client/os';
-import copyToClipboard from '@client/scripts/copy-to-clipboard';
-import { router } from '@client/router';
-import { url } from '@client/config';
-import { popout } from '@client/scripts/popout';
-import { ColdDeviceStorage } from '@client/store';
-
-export default defineComponent({
- inject: {
- navHook: {
- default: null
- },
- sideViewHook: {
- default: null
- }
- },
-
- props: {
- to: {
- type: String,
- required: true,
- },
- activeClass: {
- type: String,
- required: false,
- },
- behavior: {
- type: String,
- required: false,
- },
- },
-
- computed: {
- active() {
- if (this.activeClass == null) return false;
- const resolved = router.resolve(this.to);
- if (resolved.path == this.$route.path) return true;
- if (resolved.name == null) return false;
- if (this.$route.name == null) return false;
- return resolved.name == this.$route.name;
- }
- },
-
- methods: {
- onContextmenu(e) {
- if (window.getSelection().toString() !== '') return;
- os.contextMenu([{
- type: 'label',
- text: this.to,
- }, {
- icon: 'fas fa-window-maximize',
- text: this.$ts.openInWindow,
- action: () => {
- os.pageWindow(this.to);
- }
- }, this.sideViewHook ? {
- icon: 'fas fa-columns',
- text: this.$ts.openInSideView,
- action: () => {
- this.sideViewHook(this.to);
- }
- } : undefined, {
- icon: 'fas fa-expand-alt',
- text: this.$ts.showInPage,
- action: () => {
- this.$router.push(this.to);
- }
- }, null, {
- icon: 'fas fa-external-link-alt',
- text: this.$ts.openInNewTab,
- action: () => {
- window.open(this.to, '_blank');
- }
- }, {
- icon: 'fas fa-link',
- text: this.$ts.copyLink,
- action: () => {
- copyToClipboard(`${url}${this.to}`);
- }
- }], e);
- },
-
- window() {
- os.pageWindow(this.to);
- },
-
- modalWindow() {
- os.modalPageWindow(this.to);
- },
-
- popout() {
- popout(this.to);
- },
-
- nav() {
- if (this.behavior === 'browser') {
- location.href = this.to;
- 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();
- } else if (this.behavior === 'modalWindow') {
- return this.modalWindow();
- }
- }
-
- if (this.navHook) {
- this.navHook(this.to);
- } else {
- if (this.$store.state.defaultSideView && this.sideViewHook && this.to !== '/') {
- return this.sideViewHook(this.to);
- }
-
- if (this.$router.currentRoute.value.path === this.to) {
- window.scroll({ top: 0, behavior: 'smooth' });
- } else {
- this.$router.push(this.to);
- }
- }
- }
- }
-});
-</script>
diff --git a/src/client/components/global/acct.vue b/src/client/components/global/acct.vue
deleted file mode 100644
index 70f2954cb0..0000000000
--- a/src/client/components/global/acct.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-<template>
-<span class="mk-acct">
- <span class="name">@{{ user.username }}</span>
- <span class="host" v-if="user.host || detail || $store.state.showFullAcct">@{{ user.host || host }}</span>
-</span>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { toUnicode } from 'punycode/';
-import { host } from '@client/config';
-
-export default defineComponent({
- props: {
- user: {
- type: Object,
- required: true
- },
- detail: {
- type: Boolean,
- default: false
- },
- },
- data() {
- return {
- host: toUnicode(host),
- };
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.mk-acct {
- > .host {
- opacity: 0.5;
- }
-}
-</style>
diff --git a/src/client/components/global/ad.vue b/src/client/components/global/ad.vue
deleted file mode 100644
index 8397b2229e..0000000000
--- a/src/client/components/global/ad.vue
+++ /dev/null
@@ -1,200 +0,0 @@
-<template>
-<div class="qiivuoyo" v-if="ad">
- <div class="main" :class="ad.place" v-if="!showMenu">
- <a :href="ad.url" target="_blank">
- <img :src="ad.imageUrl">
- <button class="_button menu" @click.prevent.stop="toggleMenu"><span class="fas fa-info-circle"></span></button>
- </a>
- </div>
- <div class="menu" v-else>
- <div class="body">
- <div>Ads by {{ host }}</div>
- <!--<MkButton class="button" primary>{{ $ts._ad.like }}</MkButton>-->
- <MkButton v-if="ad.ratio !== 0" class="button" @click="reduceFrequency">{{ $ts._ad.reduceFrequencyOfThisAd }}</MkButton>
- <button class="_textButton" @click="toggleMenu">{{ $ts._ad.back }}</button>
- </div>
- </div>
-</div>
-<div v-else></div>
-</template>
-
-<script lang="ts">
-import { defineComponent, ref } from 'vue';
-import { Instance, instance } from '@client/instance';
-import { host } from '@client/config';
-import MkButton from '@client/components/ui/button.vue';
-import { defaultStore } from '@client/store';
-import * as os from '@client/os';
-
-export default defineComponent({
- components: {
- MkButton
- },
-
- props: {
- prefer: {
- type: Array,
- required: true
- },
- specify: {
- type: Object,
- required: false
- },
- },
-
- setup(props) {
- const showMenu = ref(false);
- const toggleMenu = () => {
- showMenu.value = !showMenu.value;
- };
-
- const choseAd = (): Instance['ads'][number] | null => {
- if (props.specify) {
- return props.specify as Instance['ads'][number];
- }
-
- const allAds = instance.ads.map(ad => defaultStore.state.mutedAds.includes(ad.id) ? {
- ...ad,
- ratio: 0
- } : ad);
-
- let ads = allAds.filter(ad => props.prefer.includes(ad.place));
-
- if (ads.length === 0) {
- ads = allAds.filter(ad => ad.place === 'square');
- }
-
- const lowPriorityAds = ads.filter(ad => ad.ratio === 0);
- ads = ads.filter(ad => ad.ratio !== 0);
-
- if (ads.length === 0) {
- if (lowPriorityAds.length !== 0) {
- return lowPriorityAds[Math.floor(Math.random() * lowPriorityAds.length)];
- } else {
- return null;
- }
- }
-
- const totalFactor = ads.reduce((a, b) => a + b.ratio, 0);
- const r = Math.random() * totalFactor;
-
- let stackedFactor = 0;
- for (const ad of ads) {
- if (r >= stackedFactor && r <= stackedFactor + ad.ratio) {
- return ad;
- } else {
- stackedFactor += ad.ratio;
- }
- }
-
- return null;
- };
-
- const chosen = ref(choseAd());
-
- const reduceFrequency = () => {
- if (chosen.value == null) return;
- if (defaultStore.state.mutedAds.includes(chosen.value.id)) return;
- defaultStore.push('mutedAds', chosen.value.id);
- os.success();
- chosen.value = choseAd();
- showMenu.value = false;
- };
-
- return {
- ad: chosen,
- showMenu,
- toggleMenu,
- host,
- reduceFrequency,
- };
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.qiivuoyo {
- background-size: auto auto;
- background-image: repeating-linear-gradient(45deg, transparent, transparent 8px, var(--ad) 8px, var(--ad) 14px );
-
- > .main {
- text-align: center;
-
- > a {
- display: inline-block;
- position: relative;
- vertical-align: bottom;
-
- &:hover {
- > img {
- filter: contrast(120%);
- }
- }
-
- > img {
- display: block;
- object-fit: contain;
- margin: auto;
- }
-
- > .menu {
- position: absolute;
- top: 0;
- right: 0;
- background: var(--panel);
- }
- }
-
- &.square {
- > a ,
- > a > img {
- max-width: min(300px, 100%);
- max-height: 300px;
- }
- }
-
- &.horizontal {
- padding: 8px;
-
- > a ,
- > a > img {
- max-width: min(600px, 100%);
- max-height: 80px;
- }
- }
-
- &.horizontal-big {
- padding: 8px;
-
- > a ,
- > a > img {
- max-width: min(600px, 100%);
- max-height: 250px;
- }
- }
-
- &.vertical {
- > a ,
- > a > img {
- max-width: min(100px, 100%);
- }
- }
- }
-
- > .menu {
- padding: 8px;
- text-align: center;
-
- > .body {
- padding: 8px;
- margin: 0 auto;
- max-width: 400px;
- border: solid 1px var(--divider);
-
- > .button {
- margin: 8px auto;
- }
- }
- }
-}
-</style>
diff --git a/src/client/components/global/avatar.vue b/src/client/components/global/avatar.vue
deleted file mode 100644
index 395ed5d8ce..0000000000
--- a/src/client/components/global/avatar.vue
+++ /dev/null
@@ -1,163 +0,0 @@
-<template>
-<span class="eiwwqkts _noSelect" :class="{ cat, square: $store.state.squareAvatars }" :title="acct(user)" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
- <img class="inner" :src="url" decoding="async"/>
- <MkUserOnlineIndicator v-if="showIndicator" class="indicator" :user="user"/>
-</span>
-<MkA class="eiwwqkts _noSelect" :class="{ cat, square: $store.state.squareAvatars }" :to="userPage(user)" :title="acct(user)" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
- <img class="inner" :src="url" decoding="async"/>
- <MkUserOnlineIndicator v-if="showIndicator" class="indicator" :user="user"/>
-</MkA>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
-import { extractAvgColorFromBlurhash } from '@client/scripts/extract-avg-color-from-blurhash';
-import { acct, userPage } from '@client/filters/user';
-import MkUserOnlineIndicator from '@client/components/user-online-indicator.vue';
-
-export default defineComponent({
- components: {
- MkUserOnlineIndicator
- },
- props: {
- user: {
- type: Object,
- required: true
- },
- target: {
- required: false,
- default: null
- },
- disableLink: {
- required: false,
- default: false
- },
- disablePreview: {
- required: false,
- default: false
- },
- showIndicator: {
- required: false,
- default: false
- }
- },
- emits: ['click'],
- computed: {
- cat(): boolean {
- return this.user.isCat;
- },
- url(): string {
- return this.$store.state.disableShowingAnimatedImages
- ? getStaticImageUrl(this.user.avatarUrl)
- : this.user.avatarUrl;
- },
- },
- watch: {
- 'user.avatarBlurhash'() {
- if (this.$el == null) return;
- this.$el.style.color = extractAvgColorFromBlurhash(this.user.avatarBlurhash);
- }
- },
- mounted() {
- this.$el.style.color = extractAvgColorFromBlurhash(this.user.avatarBlurhash);
- },
- methods: {
- onClick(e) {
- this.$emit('click', e);
- },
- acct,
- userPage
- }
-});
-</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;
- vertical-align: bottom;
- flex-shrink: 0;
- border-radius: 100%;
- line-height: 16px;
-
- > .inner {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- top: 0;
- border-radius: 100%;
- z-index: 1;
- overflow: hidden;
- object-fit: cover;
- width: 100%;
- height: 100%;
- }
-
- > .indicator {
- position: absolute;
- z-index: 1;
- bottom: 0;
- left: 0;
- width: 20%;
- height: 20%;
- }
-
- &.square {
- border-radius: 20%;
-
- > .inner {
- border-radius: 20%;
- }
- }
-
- &.cat {
- &:before, &:after {
- background: #df548f;
- border: solid 4px currentColor;
- box-sizing: border-box;
- content: '';
- display: inline-block;
- height: 50%;
- width: 50%;
- }
-
- &:before {
- border-radius: 0 75% 75%;
- transform: rotate(37.5deg) skew(30deg);
- }
-
- &:after {
- 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/global/ellipsis.vue b/src/client/components/global/ellipsis.vue
deleted file mode 100644
index 0a46f486d6..0000000000
--- a/src/client/components/global/ellipsis.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-<template>
- <span class="mk-ellipsis">
- <span>.</span><span>.</span><span>.</span>
- </span>
-</template>
-
-<style lang="scss" scoped>
-.mk-ellipsis {
- > span {
- animation: ellipsis 1.4s infinite ease-in-out both;
-
- &:nth-child(1) {
- animation-delay: 0s;
- }
-
- &:nth-child(2) {
- animation-delay: 0.16s;
- }
-
- &:nth-child(3) {
- animation-delay: 0.32s;
- }
- }
-}
-
-@keyframes ellipsis {
- 0%, 80%, 100% {
- opacity: 1;
- }
- 40% {
- opacity: 0;
- }
-}
-</style>
diff --git a/src/client/components/global/emoji.vue b/src/client/components/global/emoji.vue
deleted file mode 100644
index f92e35c38f..0000000000
--- a/src/client/components/global/emoji.vue
+++ /dev/null
@@ -1,125 +0,0 @@
-<template>
-<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/>
-<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt" decoding="async"/>
-<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
-<span v-else>{{ emoji }}</span>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
-import { twemojiSvgBase } from '@client/../misc/twemoji-base';
-
-export default defineComponent({
- props: {
- emoji: {
- type: String,
- required: true
- },
- normal: {
- type: Boolean,
- required: false,
- default: false
- },
- noStyle: {
- type: Boolean,
- required: false,
- default: false
- },
- customEmojis: {
- required: false
- },
- isReaction: {
- type: Boolean,
- default: false
- },
- },
-
- data() {
- return {
- url: null,
- char: null,
- customEmoji: null
- }
- },
-
- computed: {
- isCustom(): boolean {
- return this.emoji.startsWith(':');
- },
-
- alt(): string {
- return this.customEmoji ? `:${this.customEmoji.name}:` : this.char;
- },
-
- useOsNativeEmojis(): boolean {
- return this.$store.state.useOsNativeEmojis && !this.isReaction;
- },
-
- ce() {
- return this.customEmojis || this.$instance?.emojis || [];
- }
- },
-
- watch: {
- ce: {
- handler() {
- if (this.isCustom) {
- const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2));
- if (customEmoji) {
- this.customEmoji = customEmoji;
- this.url = this.$store.state.disableShowingAnimatedImages
- ? getStaticImageUrl(customEmoji.url)
- : customEmoji.url;
- }
- }
- },
- immediate: true
- },
- },
-
- created() {
- if (!this.isCustom) {
- this.char = this.emoji;
- }
-
- if (this.char) {
- let codes = Array.from(this.char).map(x => x.codePointAt(0).toString(16));
- if (!codes.includes('200d')) codes = codes.filter(x => x != 'fe0f');
- codes = codes.filter(x => x && x.length);
-
- this.url = `${twemojiSvgBase}/${codes.join('-')}.svg`;
- }
- },
-});
-</script>
-
-<style lang="scss" scoped>
-.mk-emoji {
- height: 1.25em;
- vertical-align: -0.25em;
-
- &.custom {
- height: 2.5em;
- vertical-align: middle;
- transition: transform 0.2s ease;
-
- &:hover {
- transform: scale(1.2);
- }
-
- &.normal {
- height: 1.25em;
- vertical-align: -0.25em;
-
- &:hover {
- transform: none;
- }
- }
- }
-
- &.noStyle {
- height: auto !important;
- }
-}
-</style>
diff --git a/src/client/components/global/error.vue b/src/client/components/global/error.vue
deleted file mode 100644
index 05a508a653..0000000000
--- a/src/client/components/global/error.vue
+++ /dev/null
@@ -1,46 +0,0 @@
-<template>
-<transition :name="$store.state.animation ? 'zoom' : ''" appear>
- <div class="mjndxjcg">
- <img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
- <p><i class="fas fa-exclamation-triangle"></i> {{ $ts.somethingHappened }}</p>
- <MkButton @click="() => $emit('retry')" class="button">{{ $ts.retry }}</MkButton>
- </div>
-</transition>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MkButton from '@client/components/ui/button.vue';
-
-export default defineComponent({
- components: {
- MkButton,
- },
- data() {
- return {
- };
- },
-});
-</script>
-
-<style lang="scss" scoped>
-.mjndxjcg {
- padding: 32px;
- text-align: center;
-
- > p {
- margin: 0 0 8px 0;
- }
-
- > .button {
- margin: 0 auto;
- }
-
- > img {
- vertical-align: bottom;
- height: 128px;
- margin-bottom: 16px;
- border-radius: 16px;
- }
-}
-</style>
diff --git a/src/client/components/global/header.vue b/src/client/components/global/header.vue
deleted file mode 100644
index 526db07fd3..0000000000
--- a/src/client/components/global/header.vue
+++ /dev/null
@@ -1,360 +0,0 @@
-<template>
-<div class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick" ref="el">
- <template v-if="info">
- <div class="titleContainer" @click="showTabsPopup" v-if="!hideTitle">
- <MkAvatar v-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
- <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"/>
- <div v-else-if="info.title" class="title">{{ info.title }}</div>
- <div class="subtitle" v-if="!narrow && info.subtitle">
- {{ info.subtitle }}
- </div>
- <div class="subtitle activeTab" v-if="narrow && hasTabs">
- {{ info.tabs.find(tab => tab.active)?.title }}
- <i class="chevron fas fa-chevron-down"></i>
- </div>
- </div>
- </div>
- <div class="tabs" v-if="!narrow || hideTitle">
- <button class="tab _button" v-for="tab in info.tabs" :class="{ active: tab.active }" @click="tab.onClick" v-tooltip="tab.title">
- <i v-if="tab.icon" class="icon" :class="tab.icon"></i>
- <span v-if="!tab.iconOnly" class="title">{{ tab.title }}</span>
- </button>
- </div>
- </template>
- <div class="buttons right">
- <template v-if="info && info.actions && !narrow">
- <template v-for="action in info.actions">
- <MkButton class="fullButton" v-if="action.asFullButton" @click.stop="action.handler" primary><i :class="action.icon" style="margin-right: 6px;"></i>{{ action.text }}</MkButton>
- <button v-else class="_button button" :class="{ highlighted: action.highlighted }" @click.stop="action.handler" @touchstart="preventDrag" v-tooltip="action.text"><i :class="action.icon"></i></button>
- </template>
- </template>
- <button v-if="shouldShowMenu" class="_button button" @click.stop="showMenu" @touchstart="preventDrag" v-tooltip="$ts.menu"><i class="fas fa-ellipsis-h"></i></button>
- </div>
-</div>
-</template>
-
-<script lang="ts">
-import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, inject } from 'vue';
-import * as tinycolor from 'tinycolor2';
-import { popupMenu } from '@client/os';
-import { url } from '@client/config';
-import { scrollToTop } from '@client/scripts/scroll';
-import MkButton from '@client/components/ui/button.vue';
-import { i18n } from '@client/i18n';
-import { globalEvents } from '@client/events';
-
-export default defineComponent({
- components: {
- MkButton
- },
-
- props: {
- info: {
- type: Object as PropType<{
- actions?: {}[];
- tabs?: {}[];
- }>,
- required: true
- },
- menu: {
- required: false
- },
- thin: {
- required: false,
- default: false
- },
- },
-
- setup(props) {
- const el = ref<HTMLElement>(null);
- const bg = ref(null);
- const narrow = ref(false);
- const height = ref(0);
- const hasTabs = computed(() => {
- return props.info.tabs && props.info.tabs.length > 0;
- });
- const shouldShowMenu = computed(() => {
- if (props.info == null) return false;
- if (props.info.actions != null && narrow.value) return true;
- if (props.info.menu != null) return true;
- if (props.info.share != null) return true;
- if (props.menu != null) return true;
- return false;
- });
-
- const share = () => {
- navigator.share({
- url: url + props.info.path,
- ...props.info.share,
- });
- };
-
- const showMenu = (ev: MouseEvent) => {
- let menu = props.info.menu ? props.info.menu() : [];
- if (narrow.value && props.info.actions) {
- menu = [...props.info.actions.map(x => ({
- text: x.text,
- icon: x.icon,
- action: x.handler
- })), menu.length > 0 ? null : undefined, ...menu];
- }
- if (props.info.share) {
- if (menu.length > 0) menu.push(null);
- menu.push({
- text: i18n.locale.share,
- icon: 'fas fa-share-alt',
- action: share
- });
- }
- if (props.menu) {
- if (menu.length > 0) menu.push(null);
- menu = menu.concat(props.menu);
- }
- popupMenu(menu, ev.currentTarget || ev.target);
- };
-
- const showTabsPopup = (ev: MouseEvent) => {
- if (!hasTabs.value) return;
- if (!narrow.value) return;
- ev.preventDefault();
- ev.stopPropagation();
- const menu = props.info.tabs.map(tab => ({
- text: tab.title,
- icon: tab.icon,
- action: tab.onClick,
- }));
- popupMenu(menu, ev.currentTarget || ev.target);
- };
-
- const preventDrag = (ev: TouchEvent) => {
- ev.stopPropagation();
- };
-
- const onClick = () => {
- scrollToTop(el.value, { behavior: 'smooth' });
- };
-
- const calcBg = () => {
- const rawBg = props.info?.bg || 'var(--bg)';
- const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg);
- tinyBg.setAlpha(0.85);
- bg.value = tinyBg.toRgbString();
- };
-
- onMounted(() => {
- calcBg();
- globalEvents.on('themeChanged', calcBg);
- onUnmounted(() => {
- globalEvents.off('themeChanged', calcBg);
- });
-
- if (el.value.parentElement) {
- narrow.value = el.value.parentElement.offsetWidth < 500;
- const ro = new ResizeObserver((entries, observer) => {
- if (el.value) {
- narrow.value = el.value.parentElement.offsetWidth < 500;
- }
- });
- ro.observe(el.value.parentElement);
- onUnmounted(() => {
- ro.disconnect();
- });
- }
- });
-
- return {
- el,
- bg,
- narrow,
- height,
- hasTabs,
- shouldShowMenu,
- share,
- showMenu,
- showTabsPopup,
- preventDrag,
- onClick,
- hideTitle: inject('shouldOmitHeaderTitle', false),
- thin_: props.thin || inject('shouldHeaderThin', false)
- };
- },
-});
-</script>
-
-<style lang="scss" scoped>
-.fdidabkb {
- --height: 60px;
- display: flex;
- position: sticky;
- top: var(--stickyTop, 0);
- z-index: 1000;
- width: 100%;
- -webkit-backdrop-filter: var(--blur, blur(15px));
- backdrop-filter: var(--blur, blur(15px));
- border-bottom: solid 0.5px var(--divider);
-
- &.thin {
- --height: 50px;
-
- > .buttons {
- > .button {
- font-size: 0.9em;
- }
- }
- }
-
- &.slim {
- text-align: center;
-
- > .titleContainer {
- flex: 1;
- margin: 0 auto;
- margin-left: var(--height);
-
- > *:first-child {
- margin-left: auto;
- }
-
- > *:last-child {
- margin-right: auto;
- }
- }
- }
-
- > .buttons {
- --margin: 8px;
- display: flex;
- align-items: center;
- height: var(--height);
- margin: 0 var(--margin);
-
- &.right {
- margin-left: auto;
- }
-
- &:empty {
- width: var(--height);
- }
-
- > .button {
- display: flex;
- align-items: center;
- justify-content: center;
- height: calc(var(--height) - (var(--margin) * 2));
- width: calc(var(--height) - (var(--margin) * 2));
- box-sizing: border-box;
- position: relative;
- border-radius: 5px;
-
- &:hover {
- background: rgba(0, 0, 0, 0.05);
- }
-
- &.highlighted {
- color: var(--accent);
- }
- }
-
- > .fullButton {
- & + .fullButton {
- margin-left: 12px;
- }
- }
- }
-
- > .titleContainer {
- display: flex;
- align-items: center;
- overflow: auto;
- white-space: nowrap;
- text-align: left;
- font-weight: bold;
- flex-shrink: 0;
- margin-left: 24px;
-
- > .avatar {
- $size: 32px;
- display: inline-block;
- width: $size;
- height: $size;
- vertical-align: bottom;
- margin: 0 8px;
- pointer-events: none;
- }
-
- > .icon {
- margin-right: 8px;
- }
-
- > .title {
- min-width: 0;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- line-height: 1.1;
-
- > .subtitle {
- opacity: 0.6;
- font-size: 0.8em;
- font-weight: normal;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- &.activeTab {
- text-align: center;
-
- > .chevron {
- display: inline-block;
- margin-left: 6px;
- }
- }
- }
- }
- }
-
- > .tabs {
- margin-left: 16px;
- font-size: 0.8em;
- overflow: auto;
- white-space: nowrap;
-
- > .tab {
- display: inline-block;
- position: relative;
- padding: 0 10px;
- height: 100%;
- font-weight: normal;
- opacity: 0.7;
-
- &:hover {
- opacity: 1;
- }
-
- &.active {
- opacity: 1;
-
- &:after {
- content: "";
- display: block;
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- margin: 0 auto;
- width: 100%;
- height: 3px;
- background: var(--accent);
- }
- }
-
- > .icon + .title {
- margin-left: 8px;
- }
- }
- }
-}
-</style>
diff --git a/src/client/components/global/i18n.ts b/src/client/components/global/i18n.ts
deleted file mode 100644
index abf0c96856..0000000000
--- a/src/client/components/global/i18n.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { h, defineComponent } from 'vue';
-
-export default defineComponent({
- props: {
- src: {
- type: String,
- required: true,
- },
- tag: {
- type: String,
- required: false,
- default: 'span',
- },
- textTag: {
- type: String,
- required: false,
- default: null,
- },
- },
- render() {
- let str = this.src;
- const parsed = [] as (string | { arg: string; })[];
- while (true) {
- const nextBracketOpen = str.indexOf('{');
- const nextBracketClose = str.indexOf('}');
-
- if (nextBracketOpen === -1) {
- parsed.push(str);
- break;
- } else {
- if (nextBracketOpen > 0) parsed.push(str.substr(0, nextBracketOpen));
- parsed.push({
- arg: str.substring(nextBracketOpen + 1, nextBracketClose)
- });
- }
-
- str = str.substr(nextBracketClose + 1);
- }
-
- return h(this.tag, parsed.map(x => typeof x === 'string' ? (this.textTag ? h(this.textTag, x) : x) : this.$slots[x.arg]()));
- }
-});
diff --git a/src/client/components/global/loading.vue b/src/client/components/global/loading.vue
deleted file mode 100644
index 7bde53c12e..0000000000
--- a/src/client/components/global/loading.vue
+++ /dev/null
@@ -1,92 +0,0 @@
-<template>
-<div class="yxspomdl" :class="{ inline, colored, mini }">
- <div class="ring"></div>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-
-export default defineComponent({
- props: {
- inline: {
- type: Boolean,
- required: false,
- default: false
- },
- colored: {
- type: Boolean,
- required: false,
- default: true
- },
- mini: {
- type: Boolean,
- required: false,
- default: false
- },
- }
-});
-</script>
-
-<style lang="scss" scoped>
-@keyframes ring {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(360deg);
- }
-}
-
-.yxspomdl {
- padding: 32px;
- text-align: center;
- cursor: wait;
-
- --size: 48px;
-
- &.colored {
- color: var(--accent);
- }
-
- &.inline {
- display: inline;
- padding: 0;
- --size: 32px;
- }
-
- &.mini {
- padding: 16px;
- --size: 32px;
- }
-
- > .ring {
- position: relative;
- display: inline-block;
- vertical-align: middle;
-
- &:before,
- &:after {
- content: " ";
- display: block;
- box-sizing: border-box;
- width: var(--size);
- height: var(--size);
- border-radius: 50%;
- border: solid 4px;
- }
-
- &:before {
- border-color: currentColor;
- opacity: 0.3;
- }
-
- &:after {
- position: absolute;
- top: 0;
- border-color: currentColor transparent transparent transparent;
- animation: ring 0.5s linear infinite;
- }
- }
-}
-</style>
diff --git a/src/client/components/global/misskey-flavored-markdown.vue b/src/client/components/global/misskey-flavored-markdown.vue
deleted file mode 100644
index c4f75bee93..0000000000
--- a/src/client/components/global/misskey-flavored-markdown.vue
+++ /dev/null
@@ -1,157 +0,0 @@
-<template>
-<mfm-core v-bind="$attrs" class="havbbuyv" :class="{ nowrap: $attrs['nowrap'] }"/>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import MfmCore from '@client/components/mfm';
-
-export default defineComponent({
- components: {
- MfmCore
- }
-});
-</script>
-
-<style lang="scss">
-._mfm_blur_ {
- filter: blur(6px);
- transition: filter 0.3s;
-
- &:hover {
- filter: blur(0px);
- }
-}
-
-@keyframes mfm-spin {
- 0% { transform: rotate(0deg); }
- 100% { transform: rotate(360deg); }
-}
-
-@keyframes mfm-spinX {
- 0% { transform: perspective(128px) rotateX(0deg); }
- 100% { transform: perspective(128px) rotateX(360deg); }
-}
-
-@keyframes mfm-spinY {
- 0% { transform: perspective(128px) rotateY(0deg); }
- 100% { transform: perspective(128px) rotateY(360deg); }
-}
-
-@keyframes mfm-jump {
- 0% { transform: translateY(0); }
- 25% { transform: translateY(-16px); }
- 50% { transform: translateY(0); }
- 75% { transform: translateY(-8px); }
- 100% { transform: translateY(0); }
-}
-
-@keyframes mfm-bounce {
- 0% { transform: translateY(0) scale(1, 1); }
- 25% { transform: translateY(-16px) scale(1, 1); }
- 50% { transform: translateY(0) scale(1, 1); }
- 75% { transform: translateY(0) scale(1.5, 0.75); }
- 100% { transform: translateY(0) scale(1, 1); }
-}
-
-// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`;
-// let css = '';
-// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
-@keyframes mfm-twitch {
- 0% { transform: translate(7px, -2px) }
- 5% { transform: translate(-3px, 1px) }
- 10% { transform: translate(-7px, -1px) }
- 15% { transform: translate(0px, -1px) }
- 20% { transform: translate(-8px, 6px) }
- 25% { transform: translate(-4px, -3px) }
- 30% { transform: translate(-4px, -6px) }
- 35% { transform: translate(-8px, -8px) }
- 40% { transform: translate(4px, 6px) }
- 45% { transform: translate(-3px, 1px) }
- 50% { transform: translate(2px, -10px) }
- 55% { transform: translate(-7px, 0px) }
- 60% { transform: translate(-2px, 4px) }
- 65% { transform: translate(3px, -8px) }
- 70% { transform: translate(6px, 7px) }
- 75% { transform: translate(-7px, -2px) }
- 80% { transform: translate(-7px, -8px) }
- 85% { transform: translate(9px, 3px) }
- 90% { transform: translate(-3px, -2px) }
- 95% { transform: translate(-10px, 2px) }
- 100% { transform: translate(-2px, -6px) }
-}
-
-// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`;
-// let css = '';
-// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
-@keyframes mfm-shake {
- 0% { transform: translate(-3px, -1px) rotate(-8deg) }
- 5% { transform: translate(0px, -1px) rotate(-10deg) }
- 10% { transform: translate(1px, -3px) rotate(0deg) }
- 15% { transform: translate(1px, 1px) rotate(11deg) }
- 20% { transform: translate(-2px, 1px) rotate(1deg) }
- 25% { transform: translate(-1px, -2px) rotate(-2deg) }
- 30% { transform: translate(-1px, 2px) rotate(-3deg) }
- 35% { transform: translate(2px, 1px) rotate(6deg) }
- 40% { transform: translate(-2px, -3px) rotate(-9deg) }
- 45% { transform: translate(0px, -1px) rotate(-12deg) }
- 50% { transform: translate(1px, 2px) rotate(10deg) }
- 55% { transform: translate(0px, -3px) rotate(8deg) }
- 60% { transform: translate(1px, -1px) rotate(8deg) }
- 65% { transform: translate(0px, -1px) rotate(-7deg) }
- 70% { transform: translate(-1px, -3px) rotate(6deg) }
- 75% { transform: translate(0px, -2px) rotate(4deg) }
- 80% { transform: translate(-2px, -1px) rotate(3deg) }
- 85% { transform: translate(1px, -3px) rotate(-10deg) }
- 90% { transform: translate(1px, 0px) rotate(3deg) }
- 95% { transform: translate(-2px, 0px) rotate(-3deg) }
- 100% { transform: translate(2px, 1px) rotate(2deg) }
-}
-
-@keyframes mfm-rubberBand {
- from { transform: scale3d(1, 1, 1); }
- 30% { transform: scale3d(1.25, 0.75, 1); }
- 40% { transform: scale3d(0.75, 1.25, 1); }
- 50% { transform: scale3d(1.15, 0.85, 1); }
- 65% { transform: scale3d(0.95, 1.05, 1); }
- 75% { transform: scale3d(1.05, 0.95, 1); }
- to { transform: scale3d(1, 1, 1); }
-}
-
-@keyframes mfm-rainbow {
- 0% { filter: hue-rotate(0deg) contrast(150%) saturate(150%); }
- 100% { filter: hue-rotate(360deg) contrast(150%) saturate(150%); }
-}
-</style>
-
-<style lang="scss" scoped>
-.havbbuyv {
- white-space: pre-wrap;
-
- &.nowrap {
- white-space: pre;
- word-wrap: normal; // https://codeday.me/jp/qa/20190424/690106.html
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- ::v-deep(.quote) {
- display: block;
- margin: 8px;
- padding: 6px 0 6px 12px;
- color: var(--fg);
- border-left: solid 3px var(--fg);
- opacity: 0.7;
- }
-
- ::v-deep(pre) {
- font-size: 0.8em;
- }
-
- > ::v-deep(code) {
- font-size: 0.8em;
- word-break: break-all;
- padding: 4px 6px;
- }
-}
-</style>
diff --git a/src/client/components/global/spacer.vue b/src/client/components/global/spacer.vue
deleted file mode 100644
index 1129d54c71..0000000000
--- a/src/client/components/global/spacer.vue
+++ /dev/null
@@ -1,76 +0,0 @@
-<template>
-<div ref="root" :class="$style.root" :style="{ padding: margin + 'px' }">
- <div ref="content" :class="$style.content">
- <slot></slot>
- </div>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
-
-export default defineComponent({
- props: {
- contentMax: {
- type: Number,
- required: false,
- default: null,
- }
- },
-
- setup(props, context) {
- let ro: ResizeObserver;
- const root = ref<HTMLElement>(null);
- const content = ref<HTMLElement>(null);
- const margin = ref(0);
- const adjust = (rect: { width: number; height: number; }) => {
- if (rect.width > (props.contentMax || 500)) {
- margin.value = 32;
- } else {
- margin.value = 12;
- }
- };
-
- onMounted(() => {
- ro = new ResizeObserver((entries) => {
- /* iOSが対応していない
- adjust({
- width: entries[0].borderBoxSize[0].inlineSize,
- height: entries[0].borderBoxSize[0].blockSize,
- });
- */
- adjust({
- width: root.value.offsetWidth,
- height: root.value.offsetHeight,
- });
- });
- ro.observe(root.value);
-
- if (props.contentMax) {
- content.value.style.maxWidth = `${props.contentMax}px`;
- }
- });
-
- onUnmounted(() => {
- ro.disconnect();
- });
-
- return {
- root,
- content,
- margin,
- };
- },
-});
-</script>
-
-<style lang="scss" module>
-.root {
- box-sizing: border-box;
- width: 100%;
-}
-
-.content {
- margin: 0 auto;
-}
-</style>
diff --git a/src/client/components/global/sticky-container.vue b/src/client/components/global/sticky-container.vue
deleted file mode 100644
index 859b2c1d73..0000000000
--- a/src/client/components/global/sticky-container.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<template>
-<div ref="rootEl">
- <slot name="header"></slot>
- <div ref="bodyEl">
- <slot></slot>
- </div>
-</div>
-</template>
-
-<script lang="ts">
-import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
-
-export default defineComponent({
- props: {
- autoSticky: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
-
- setup(props, context) {
- const rootEl = ref<HTMLElement>(null);
- const bodyEl = ref<HTMLElement>(null);
-
- const calc = () => {
- const currentStickyTop = getComputedStyle(rootEl.value).getPropertyValue('--stickyTop') || '0px';
-
- const header = rootEl.value.children[0];
- if (header === bodyEl.value) {
- bodyEl.value.style.setProperty('--stickyTop', currentStickyTop);
- } else {
- bodyEl.value.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`);
-
- if (props.autoSticky) {
- header.style.setProperty('--stickyTop', currentStickyTop);
- header.style.position = 'sticky';
- header.style.top = 'var(--stickyTop)';
- header.style.zIndex = '1';
- }
- }
- };
-
- onMounted(() => {
- calc();
-
- const observer = new MutationObserver(() => {
- setTimeout(() => {
- calc();
- }, 100);
- });
-
- observer.observe(rootEl.value, {
- attributes: false,
- childList: true,
- subtree: false,
- });
-
- onUnmounted(() => {
- observer.disconnect();
- });
- });
-
- return {
- rootEl,
- bodyEl,
- };
- },
-});
-</script>
-
-<style lang="scss" module>
-
-</style>
diff --git a/src/client/components/global/time.vue b/src/client/components/global/time.vue
deleted file mode 100644
index 6a330a2307..0000000000
--- a/src/client/components/global/time.vue
+++ /dev/null
@@ -1,73 +0,0 @@
-<template>
-<time :title="absolute">
- <template v-if="mode == 'relative'">{{ relative }}</template>
- <template v-else-if="mode == 'absolute'">{{ absolute }}</template>
- <template v-else-if="mode == 'detail'">{{ absolute }} ({{ relative }})</template>
-</time>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-
-export default defineComponent({
- props: {
- time: {
- type: [Date, String],
- required: true
- },
- mode: {
- type: String,
- default: 'relative'
- }
- },
- data() {
- return {
- tickId: null,
- now: new Date()
- };
- },
- computed: {
- _time(): Date {
- return typeof this.time == 'string' ? new Date(this.time) : this.time;
- },
- absolute(): string {
- return this._time.toLocaleString();
- },
- relative(): string {
- const time = this._time;
- const ago = (this.now.getTime() - time.getTime()) / 1000/*ms*/;
- return (
- ago >= 31536000 ? this.$t('_ago.yearsAgo', { n: (~~(ago / 31536000)).toString() }) :
- ago >= 2592000 ? this.$t('_ago.monthsAgo', { n: (~~(ago / 2592000)).toString() }) :
- ago >= 604800 ? this.$t('_ago.weeksAgo', { n: (~~(ago / 604800)).toString() }) :
- ago >= 86400 ? this.$t('_ago.daysAgo', { n: (~~(ago / 86400)).toString() }) :
- ago >= 3600 ? this.$t('_ago.hoursAgo', { n: (~~(ago / 3600)).toString() }) :
- ago >= 60 ? this.$t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) :
- ago >= 10 ? this.$t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) :
- ago >= -1 ? this.$ts._ago.justNow :
- ago < -1 ? this.$ts._ago.future :
- this.$ts._ago.unknown);
- }
- },
- created() {
- if (this.mode == 'relative' || this.mode == 'detail') {
- this.tickId = window.requestAnimationFrame(this.tick);
- }
- },
- unmounted() {
- if (this.mode === 'relative' || this.mode === 'detail') {
- window.clearTimeout(this.tickId);
- }
- },
- methods: {
- tick() {
- // TODO: パフォーマンス向上のため、このコンポーネントが画面内に表示されている場合のみ更新する
- this.now = new Date();
-
- this.tickId = setTimeout(() => {
- window.requestAnimationFrame(this.tick);
- }, 10000);
- }
- }
-});
-</script>
diff --git a/src/client/components/global/url.vue b/src/client/components/global/url.vue
deleted file mode 100644
index 218729882d..0000000000
--- a/src/client/components/global/url.vue
+++ /dev/null
@@ -1,142 +0,0 @@
-<template>
-<component :is="self ? 'MkA' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
- @mouseover="onMouseover"
- @mouseleave="onMouseleave"
- @contextmenu.stop="() => {}"
->
- <template v-if="!self">
- <span class="schema">{{ schema }}//</span>
- <span class="hostname">{{ hostname }}</span>
- <span class="port" v-if="port != ''">:{{ port }}</span>
- </template>
- <template v-if="pathname === '/' && self">
- <span class="self">{{ hostname }}</span>
- </template>
- <span class="pathname" v-if="pathname != ''">{{ self ? pathname.substr(1) : pathname }}</span>
- <span class="query">{{ query }}</span>
- <span class="hash">{{ hash }}</span>
- <i v-if="target === '_blank'" class="fas fa-external-link-square-alt icon"></i>
-</component>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-import { toUnicode as decodePunycode } from 'punycode/';
-import { url as local } from '@client/config';
-import { isDeviceTouch } from '@client/scripts/is-device-touch';
-import * as os from '@client/os';
-
-export default defineComponent({
- props: {
- url: {
- type: String,
- required: true,
- },
- rel: {
- type: String,
- required: false,
- }
- },
- data() {
- const self = this.url.startsWith(local);
- 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,
- self: self,
- attr: self ? 'to' : 'href',
- target: self ? null : '_blank',
- showTimer: null,
- hideTimer: null,
- checkTimer: null,
- close: null,
- };
- },
- 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('@client/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 (isDeviceTouch) return;
- clearTimeout(this.showTimer);
- clearTimeout(this.hideTimer);
- this.showTimer = setTimeout(this.showPreview, 500);
- },
- onMouseleave() {
- if (isDeviceTouch) return;
- clearTimeout(this.showTimer);
- clearTimeout(this.hideTimer);
- this.hideTimer = setTimeout(this.closePreview, 500);
- }
- }
-});
-</script>
-
-<style lang="scss" scoped>
-.ieqqeuvs {
- word-break: break-all;
-
- > .icon {
- padding-left: 2px;
- font-size: .9em;
- }
-
- > .self {
- font-weight: bold;
- }
-
- > .schema {
- opacity: 0.5;
- }
-
- > .hostname {
- font-weight: bold;
- }
-
- > .pathname {
- opacity: 0.8;
- }
-
- > .query {
- opacity: 0.5;
- }
-
- > .hash {
- font-style: italic;
- }
-}
-</style>
diff --git a/src/client/components/global/user-name.vue b/src/client/components/global/user-name.vue
deleted file mode 100644
index bc93a8ea30..0000000000
--- a/src/client/components/global/user-name.vue
+++ /dev/null
@@ -1,20 +0,0 @@
-<template>
-<Mfm :text="user.name || user.username" :plain="true" :nowrap="nowrap" :custom-emojis="user.emojis"/>
-</template>
-
-<script lang="ts">
-import { defineComponent } from 'vue';
-
-export default defineComponent({
- props: {
- user: {
- type: Object,
- required: true
- },
- nowrap: {
- type: Boolean,
- default: true
- },
- }
-});
-</script>