From cc441258dbf8c60786c6eb6c70f9b8a45622037f Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 23 Dec 2021 16:10:13 +0900 Subject: [PATCH 1/9] enhance(client): tweak channel pages --- .../client/src/components/ui/pagination.vue | 7 +- packages/client/src/pages/channel-editor.vue | 34 ++++----- packages/client/src/pages/channel.vue | 58 ++++++++------ packages/client/src/pages/channels.vue | 75 ++++++++++--------- 4 files changed, 97 insertions(+), 77 deletions(-) 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/pages/channel-editor.vue b/packages/client/src/pages/channel-editor.vue index 67b839bc3d..58c644be62 100644 --- a/packages/client/src/pages/channel-editor.vue +++ b/packages/client/src/pages/channel-editor.vue @@ -1,28 +1,26 @@ <template> -<div> - <div class="_section"> - <div class="_content"> - <MkInput v-model="name"> - <template #label>{{ $ts.name }}</template> - </MkInput> +<MkSpacer :content-max="700"> + <div class="_formRoot"> + <MkInput v-model="name" class="_formBlock"> + <template #label>{{ $ts.name }}</template> + </MkInput> - <MkTextarea v-model="description"> - <template #label>{{ $ts.description }}</template> - </MkTextarea> + <MkTextarea v-model="description" class="_formBlock"> + <template #label>{{ $ts.description }}</template> + </MkTextarea> - <div class="banner"> - <MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton> - <div v-else-if="bannerUrl"> - <img :src="bannerUrl" style="width: 100%;"/> - <MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton> - </div> + <div class="banner"> + <MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton> + <div v-else-if="bannerUrl"> + <img :src="bannerUrl" style="width: 100%;"/> + <MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton> </div> </div> - <div class="_footer"> + <div class="_formBlock"> <MkButton primary @click="save()"><i class="fas fa-save"></i> {{ channelId ? $ts.save : $ts.create }}</MkButton> </div> </div> -</div> +</MkSpacer> </template> <script lang="ts"> @@ -51,9 +49,11 @@ export default defineComponent({ [symbols.PAGE_INFO]: computed(() => this.channelId ? { title: this.$ts._channel.edit, icon: 'fas fa-satellite-dish', + bg: 'var(--bg)', } : { title: this.$ts._channel.create, icon: 'fas fa-satellite-dish', + bg: 'var(--bg)', }), channel: null, name: null, diff --git a/packages/client/src/pages/channel.vue b/packages/client/src/pages/channel.vue index a328eacb07..67ab2d8981 100644 --- a/packages/client/src/pages/channel.vue +++ b/packages/client/src/pages/channel.vue @@ -1,29 +1,31 @@ <template> -<div v-if="channel" class="_section"> - <div class="wpgynlbz _content _panel _gap" :class="{ hide: !showBanner }"> - <XChannelFollowButton :channel="channel" :full="true" class="subscribe"/> - <button class="_button toggle" @click="() => showBanner = !showBanner"> - <template v-if="showBanner"><i class="fas fa-angle-up"></i></template> - <template v-else><i class="fas fa-angle-down"></i></template> - </button> - <div v-if="!showBanner" class="hideOverlay"> - </div> - <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner"> - <div class="status"> - <div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> - <div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div> +<MkSpacer :content-max="700"> + <div v-if="channel"> + <div class="wpgynlbz _panel _gap" :class="{ hide: !showBanner }"> + <XChannelFollowButton :channel="channel" :full="true" class="subscribe"/> + <button class="_button toggle" @click="() => showBanner = !showBanner"> + <template v-if="showBanner"><i class="fas fa-angle-up"></i></template> + <template v-else><i class="fas fa-angle-down"></i></template> + </button> + <div v-if="!showBanner" class="hideOverlay"> + </div> + <div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner"> + <div class="status"> + <div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div> + <div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div> + </div> + <div class="fade"></div> + </div> + <div v-if="channel.description" class="description"> + <Mfm :text="channel.description" :is-note="false" :i="$i"/> </div> - <div class="fade"></div> - </div> - <div v-if="channel.description" class="description"> - <Mfm :text="channel.description" :is-note="false" :i="$i"/> </div> + + <XPostForm v-if="$i" :channel="channel" class="post-form _panel _gap" fixed/> + + <XTimeline :key="channelId" class="_gap" src="channel" :channel="channelId" @before="before" @after="after"/> </div> - - <XPostForm v-if="$i" :channel="channel" class="post-form _content _panel _gap" fixed/> - - <XTimeline :key="channelId" class="_content _gap" src="channel" :channel="channelId" @before="before" @after="after"/> -</div> +</MkSpacer> </template> <script lang="ts"> @@ -55,6 +57,12 @@ export default defineComponent({ [symbols.PAGE_INFO]: computed(() => this.channel ? { title: this.channel.name, icon: 'fas fa-satellite-dish', + bg: 'var(--bg)', + actions: [...(this.$i && this.$i.id === this.channel.userId ? [{ + icon: 'fas fa-cog', + text: this.$ts.edit, + handler: this.edit, + }] : [])], } : null), channel: null, showBanner: true, @@ -79,8 +87,10 @@ export default defineComponent({ } }, - created() { - + methods: { + edit() { + this.$router.push(`/channels/${this.channel.id}/edit`); + } }, }); </script> diff --git a/packages/client/src/pages/channels.vue b/packages/client/src/pages/channels.vue index a08c273279..3bc62b5b56 100644 --- a/packages/client/src/pages/channels.vue +++ b/packages/client/src/pages/channels.vue @@ -1,58 +1,63 @@ <template> -<div> - <div v-if="$i" class="_section" style="padding: 0;"> - <MkTab v-model="tab" class="_content"> - <option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._channel.featured }}</option> - <option value="following"><i class="fas fa-heart"></i> {{ $ts._channel.following }}</option> - <option value="owned"><i class="fas fa-edit"></i> {{ $ts._channel.owned }}</option> - </MkTab> +<MkSpacer :content-max="700"> + <div v-if="tab === 'featured'" class="_content grwlizim featured"> + <MkPagination v-slot="{items}" :pagination="featuredPagination"> + <MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/> + </MkPagination> </div> - - <div class="_section"> - <div v-if="tab === 'featured'" class="_content grwlizim featured"> - <MkPagination v-slot="{items}" :pagination="featuredPagination"> - <MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/> - </MkPagination> - </div> - - <div v-if="tab === 'following'" class="_content grwlizim following"> - <MkPagination v-slot="{items}" :pagination="followingPagination"> - <MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/> - </MkPagination> - </div> - - <div v-if="tab === 'owned'" class="_content grwlizim owned"> - <MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton> - <MkPagination v-slot="{items}" :pagination="ownedPagination"> - <MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/> - </MkPagination> - </div> + <div v-else-if="tab === 'following'" class="_content grwlizim following"> + <MkPagination v-slot="{items}" :pagination="followingPagination"> + <MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/> + </MkPagination> </div> -</div> + <div v-else-if="tab === 'owned'" class="_content grwlizim owned"> + <MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton> + <MkPagination v-slot="{items}" :pagination="ownedPagination"> + <MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/> + </MkPagination> + </div> +</MkSpacer> </template> <script lang="ts"> -import { defineComponent } from 'vue'; +import { computed, defineComponent } from 'vue'; import MkChannelPreview from '@/components/channel-preview.vue'; import MkPagination from '@/components/ui/pagination.vue'; import MkButton from '@/components/ui/button.vue'; -import MkTab from '@/components/tab.vue'; import * as symbols from '@/symbols'; export default defineComponent({ components: { - MkChannelPreview, MkPagination, MkButton, MkTab + MkChannelPreview, MkPagination, MkButton, }, data() { return { - [symbols.PAGE_INFO]: { + [symbols.PAGE_INFO]: computed(() => ({ title: this.$ts.channel, icon: 'fas fa-satellite-dish', - action: { + bg: 'var(--bg)', + actions: [{ icon: 'fas fa-plus', + text: this.$ts.create, handler: this.create - } - }, + }], + tabs: [{ + active: this.tab === 'featured', + title: this.$ts._channel.featured, + icon: 'fas fa-fire-alt', + onClick: () => { this.tab = 'featured'; }, + }, { + active: this.tab === 'following', + title: this.$ts._channel.following, + icon: 'fas fa-heart', + onClick: () => { this.tab = 'following'; }, + }, { + active: this.tab === 'owned', + title: this.$ts._channel.owned, + icon: 'fas fa-edit', + onClick: () => { this.tab = 'owned'; }, + },] + })), tab: 'featured', featuredPagination: { endpoint: 'channels/featured', From 3a990dce7520eb1e4fabb2dbdf0860f2c60432e4 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 23 Dec 2021 17:05:26 +0900 Subject: [PATCH 2/9] refactor(client): refactor --- packages/client/src/components/global/url.vue | 88 +++++-------------- packages/client/src/pages/channels.vue | 2 +- packages/client/src/scripts/use-tooltip.ts | 3 + 3 files changed, 28 insertions(+), 65 deletions(-) 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/pages/channels.vue b/packages/client/src/pages/channels.vue index 3bc62b5b56..48877ab3ec 100644 --- a/packages/client/src/pages/channels.vue +++ b/packages/client/src/pages/channels.vue @@ -39,7 +39,7 @@ export default defineComponent({ actions: [{ icon: 'fas fa-plus', text: this.$ts.create, - handler: this.create + handler: this.create, }], tabs: [{ active: this.tab === 'featured', diff --git a/packages/client/src/scripts/use-tooltip.ts b/packages/client/src/scripts/use-tooltip.ts index 0df4baca7b..d0c6756eb1 100644 --- a/packages/client/src/scripts/use-tooltip.ts +++ b/packages/client/src/scripts/use-tooltip.ts @@ -18,6 +18,9 @@ export function useTooltip( const open = () => { close(); if (!isHovering) return; + if (elRef.value == null) return; + const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el; + if (!document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため const showing = ref(true); onShow(showing); From 2e80f9dfba1e82b8b649c127138c2553f5cdf760 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 23 Dec 2021 17:05:50 +0900 Subject: [PATCH 3/9] clean up --- locales/ja-JP.yml | 1 - packages/client/src/components/global/a.vue | 5 ----- packages/client/src/pages/settings/general.vue | 8 -------- packages/client/src/store.ts | 1 - 4 files changed, 15 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f85e8f3e00..62aade568d 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -614,7 +614,6 @@ regenerateLoginToken: "ログイントークンを再生成" regenerateLoginTokenDescription: "ログインに使用される内部トークンを再生成します。通常この操作を行う必要はありません。再生成すると、全てのデバイスでログアウトされます。" setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。" fileIdOrUrl: "ファイルIDまたはURL" -chatOpenBehavior: "チャットを開くときの動作" behavior: "動作" sample: "サンプル" abuseReports: "通報" 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/pages/settings/general.vue b/packages/client/src/pages/settings/general.vue index 83924382d8..734bc78442 100644 --- a/packages/client/src/pages/settings/general.vue +++ b/packages/client/src/pages/settings/general.vue @@ -77,13 +77,6 @@ <FormSwitch v-model="defaultSideView">{{ $ts.openInSideView }}</FormSwitch> </FormGroup> - <FormSelect v-model="chatOpenBehavior" class="_formBlock"> - <template #label>{{ $ts.chatOpenBehavior }}</template> - <option value="page">{{ $ts.showInPage }}</option> - <option value="window">{{ $ts.openInWindow }}</option> - <option value="popout">{{ $ts.popout }}</option> - </FormSelect> - <FormLink to="/settings/deck" class="_formBlock">{{ $ts.deck }}</FormLink> <FormLink to="/settings/custom-css" class="_formBlock"><template #icon><i class="fas fa-code"></i></template>{{ $ts.customCss }}</FormLink> @@ -149,7 +142,6 @@ export default defineComponent({ disablePagesScript: defaultStore.makeGetterSetter('disablePagesScript'), showFixedPostForm: defaultStore.makeGetterSetter('showFixedPostForm'), defaultSideView: defaultStore.makeGetterSetter('defaultSideView'), - chatOpenBehavior: ColdDeviceStorage.makeGetterSetter('chatOpenBehavior'), instanceTicker: defaultStore.makeGetterSetter('instanceTicker'), enableInfiniteScroll: defaultStore.makeGetterSetter('enableInfiniteScroll'), useReactionPickerForContextMenu: defaultStore.makeGetterSetter('useReactionPickerForContextMenu'), diff --git a/packages/client/src/store.ts b/packages/client/src/store.ts index 19d46bacea..dc9c3b7b9e 100644 --- a/packages/client/src/store.ts +++ b/packages/client/src/store.ts @@ -245,7 +245,6 @@ export class ColdDeviceStorage { lightTheme: require('@/themes/l-light.json5') as Theme, darkTheme: require('@/themes/d-dark.json5') as Theme, syncDeviceDarkMode: true, - chatOpenBehavior: 'page' as 'page' | 'window' | 'popout', plugins: [] as Plugin[], mediaVolume: 0.5, sound_masterVolume: 0.3, From 99ced12ac5c7ef5d4f835cdf054abdd55f888b5a Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 24 Dec 2021 01:07:04 +0900 Subject: [PATCH 4/9] fix(client): fix zindex issue Fix #8086 --- CHANGELOG.md | 7 +++++++ packages/client/src/components/media-list.vue | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e15c6d6463..743479ae4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ --> +## 12.x.x (unreleased) + +### Improvements + +### Bugfixes +- クライアント: 一部のコンポーネントが裏に隠れるのを修正 + ## 12.100.2 (2021/12/18) ### Bugfixes 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> From 1122f7281ec9b95205f4ee8aa8462daae98ebbed Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Fri, 24 Dec 2021 01:16:58 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=E3=83=8E=E3=83=BC=E3=83=88=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=81=A7Renote=E3=81=A7=E3=81=82=E3=82=8B?= =?UTF-8?q?=E5=A0=B4=E5=90=88=E3=81=ABnoindex=E3=82=92=E4=BB=98=E5=8A=A0?= =?UTF-8?q?=20(#8074)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/server/web/views/note.pug | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/server/web/views/note.pug b/packages/backend/src/server/web/views/note.pug index 7030936975..fce91bdabe 100644 --- a/packages/backend/src/server/web/views/note.pug +++ b/packages/backend/src/server/web/views/note.pug @@ -4,6 +4,7 @@ block vars - const user = note.user; - const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`; - const url = `${config.url}/notes/${note.id}`; + - const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null; block title = `${title} | ${instanceName}` @@ -19,7 +20,7 @@ block og meta(property='og:image' content= user.avatarUrl) block meta - if user.host || profile.noCrawle + if user.host || isRenote || profile.noCrawle meta(name='robots' content='noindex') meta(name='misskey:user-username' content=user.username) From 2294e9ffdce9091a412cb3a4e1b04e5056c013e6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 24 Dec 2021 01:31:37 +0900 Subject: [PATCH 6/9] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fe3df853b7..633995c947 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,7 @@ Configuration files are located in [`/.github/workflows`](/.github/workflows). ## Vue Misskey uses Vue(v3) as its front-end framework. -**When creating a new component, please use the Composition API instead of the Options API.** +**When creating a new component, please use the Composition API (and [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html)) instead of the Options API.** Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome. ## Adding MisskeyRoom items From b4636631751449da34e2bad7e7276546c6fd3967 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 24 Dec 2021 12:34:24 +0900 Subject: [PATCH 7/9] enhance(client): tweak ui --- .../client/src/components/page-window.vue | 26 ++++++++++++++++++- packages/client/src/components/ui/window.vue | 5 +++- packages/client/src/scripts/use-tooltip.ts | 7 ++++- 3 files changed, 35 insertions(+), 3 deletions(-) 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/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/scripts/use-tooltip.ts b/packages/client/src/scripts/use-tooltip.ts index d0c6756eb1..bc8f27a038 100644 --- a/packages/client/src/scripts/use-tooltip.ts +++ b/packages/client/src/scripts/use-tooltip.ts @@ -1,4 +1,4 @@ -import { Ref, ref, watch } from 'vue'; +import { Ref, ref, watch, onUnmounted } from 'vue'; export function useTooltip( elRef: Ref<HTMLElement | { $el: HTMLElement } | null | undefined>, @@ -72,9 +72,14 @@ export function useTooltip( el.addEventListener('mouseleave', onMouseleave, { passive: true }); el.addEventListener('touchstart', onTouchstart, { passive: true }); el.addEventListener('touchend', onTouchend, { passive: true }); + el.addEventListener('click', close, { passive: true }); } }, { immediate: true, flush: 'post', }); + + onUnmounted(() => { + close(); + }); } From 8e7744a69582a05f43944d0db01ec4064988eca8 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Fri, 24 Dec 2021 23:25:23 +0900 Subject: [PATCH 8/9] =?UTF-8?q?fix(client):=20=E3=83=89=E3=83=AD=E3=83=AF?= =?UTF-8?q?=E3=83=BC=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=81=A7=E3=82=BB?= =?UTF-8?q?=E3=83=BC=E3=83=95=E3=82=A8=E3=83=AA=E3=82=A2=E3=82=92=E8=80=83?= =?UTF-8?q?=E6=85=AE=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/client/src/components/ui/menu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 { From c77fe1f2cf5da7c111e9008d869c702644075d44 Mon Sep 17 00:00:00 2001 From: tamaina <tamaina@hotmail.co.jp> Date: Sat, 25 Dec 2021 02:01:35 +0900 Subject: [PATCH 9/9] Truncate push notification message (#8089) * Truncate push notification message * fix --- .../backend/src/services/push-notification.ts | 27 ++++++++++++++++++- .../client/src/sw/compose-notification.ts | 13 +++++---- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/services/push-notification.ts b/packages/backend/src/services/push-notification.ts index 616bc74411..2133768a96 100644 --- a/packages/backend/src/services/push-notification.ts +++ b/packages/backend/src/services/push-notification.ts @@ -3,10 +3,33 @@ import config from '@/config/index'; import { SwSubscriptions } from '@/models/index'; import { fetchMeta } from '@/misc/fetch-meta'; import { Packed } from '@/misc/schema'; +import { getNoteSummary } from '@/misc/get-note-summary'; type notificationType = 'notification' | 'unreadMessagingMessage'; type notificationBody = Packed<'Notification'> | Packed<'MessagingMessage'>; +// プッシュメッセージサーバーには文字数制限があるため、内容を削減します +function truncateNotification(notification: Packed<'Notification'>): any { + if (notification.note) { + return { + ...notification, + note: { + ...notification.note, + // textをgetNoteSummaryしたものに置き換える + text: getNoteSummary(notification.type === 'renote' ? notification.note.renote as Packed<'Note'> : notification.note), + ...{ + cw: undefined, + reply: undefined, + renote: undefined, + user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる + } + } + }; + } + + return notification; +} + export default async function(userId: string, type: notificationType, body: notificationBody) { const meta = await fetchMeta(); @@ -32,7 +55,9 @@ export default async function(userId: string, type: notificationType, body: noti }; push.sendNotification(pushSubscription, JSON.stringify({ - type, body, + type, + body: type === 'notification' ? truncateNotification(body as Packed<'Notification'>) : body, + userId, }), { proxy: config.proxy, }).catch((err: any) => { diff --git a/packages/client/src/sw/compose-notification.ts b/packages/client/src/sw/compose-notification.ts index 0aed9610ea..10bd27c9ec 100644 --- a/packages/client/src/sw/compose-notification.ts +++ b/packages/client/src/sw/compose-notification.ts @@ -3,7 +3,6 @@ */ declare var self: ServiceWorkerGlobalScope; -import { getNoteSummary } from '@/scripts/get-note-summary'; import * as misskey from 'misskey-js'; function getUserName(user: misskey.entities.User): string { @@ -26,37 +25,37 @@ export default async function(type, data, i18n): Promise<[string, NotificationOp switch (data.type) { case 'mention': return [i18n.t('_notification.youGotMention', { name: getUserName(data.user) }), { - body: getNoteSummary(data.note, i18n.locale), + body: data.note.text, icon: data.user.avatarUrl }]; case 'reply': return [i18n.t('_notification.youGotReply', { name: getUserName(data.user) }), { - body: getNoteSummary(data.note, i18n.locale), + body: data.note.text, icon: data.user.avatarUrl }]; case 'renote': return [i18n.t('_notification.youRenoted', { name: getUserName(data.user) }), { - body: getNoteSummary(data.note, i18n.locale), + body: data.note.text, icon: data.user.avatarUrl }]; case 'quote': return [i18n.t('_notification.youGotQuote', { name: getUserName(data.user) }), { - body: getNoteSummary(data.note, i18n.locale), + body: data.note.text, icon: data.user.avatarUrl }]; case 'reaction': return [`${data.reaction} ${getUserName(data.user)}`, { - body: getNoteSummary(data.note, i18n.locale), + body: data.note.text, icon: data.user.avatarUrl }]; case 'pollVote': return [i18n.t('_notification.youGotPoll', { name: getUserName(data.user) }), { - body: getNoteSummary(data.note, i18n.locale), + body: data.note.text, icon: data.user.avatarUrl }];