diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2021-04-25 15:20:39 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2021-04-25 15:20:39 +0900 |
| commit | 92977f303ddc3d004418b3166606f16b1d8dec52 (patch) | |
| tree | 2e122d83bf8a10c60b7cf71671900344da779a54 /src/client | |
| parent | Merge branch 'develop' (diff) | |
| parent | 12.79.1 (diff) | |
| download | misskey-92977f303ddc3d004418b3166606f16b1d8dec52.tar.gz misskey-92977f303ddc3d004418b3166606f16b1d8dec52.tar.bz2 misskey-92977f303ddc3d004418b3166606f16b1d8dec52.zip | |
Merge branch 'develop'
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/components/launch-pad.vue | 10 | ||||
| -rw-r--r-- | src/client/pages/about.vue | 96 | ||||
| -rw-r--r-- | src/client/pages/gallery/post.vue | 14 | ||||
| -rw-r--r-- | src/client/pages/instance-info.vue | 3 | ||||
| -rw-r--r-- | src/client/pages/page.vue | 199 | ||||
| -rw-r--r-- | src/client/store.ts | 3 | ||||
| -rw-r--r-- | src/client/ui/chat/index.vue | 2 | ||||
| -rw-r--r-- | src/client/ui/deck/main-column.vue | 2 | ||||
| -rw-r--r-- | src/client/ui/default.sidebar.vue | 25 | ||||
| -rw-r--r-- | src/client/ui/default.vue | 2 | ||||
| -rw-r--r-- | src/client/ui/universal.vue | 2 |
11 files changed, 250 insertions, 108 deletions
diff --git a/src/client/components/launch-pad.vue b/src/client/components/launch-pad.vue index e66bbd73e4..58b74bdaee 100644 --- a/src/client/components/launch-pad.vue +++ b/src/client/components/launch-pad.vue @@ -16,16 +16,16 @@ </template> </div> <div class="sub"> - <MkA to="/docs" @click.passive="close()"> + <MkA to="/docs" @click.passive="close()" v-click-anime> <i class="fas fa-question-circle icon"></i> <div class="text">{{ $ts.help }}</div> </MkA> - <MkA to="/about" @click.passive="close()"> + <MkA to="/about" @click.passive="close()" v-click-anime> <i class="fas fa-info-circle icon"></i> <div class="text">{{ $t('aboutX', { x: instanceName }) }}</div> </MkA> - <MkA to="/about-misskey" @click.passive="close()"> - <i class="fas fa-info-circle icon"></i> + <MkA to="/about-misskey" @click.passive="close()" v-click-anime> + <img src="/static-assets/favicon.png" class="icon"/> <div class="text">{{ $ts.aboutMisskey }}</div> </MkA> </div> @@ -101,6 +101,7 @@ export default defineComponent({ flex-direction: column; align-items: center; justify-content: center; + vertical-align: bottom; width: 128px; height: 128px; border-radius: var(--radius); @@ -117,6 +118,7 @@ export default defineComponent({ > .icon { font-size: 26px; + height: 32px; } > .text { diff --git a/src/client/pages/about.vue b/src/client/pages/about.vue index 4f70998eee..bdd4c78827 100644 --- a/src/client/pages/about.vue +++ b/src/client/pages/about.vue @@ -1,39 +1,57 @@ <template> -<FormBase class="mmnnbwxb" v-if="meta"> - <div class="_formItem logo"> - <img v-if="meta.logoImageUrl" :src="meta.logoImageUrl"> - <span v-else class="text">{{ instanceName }}</span> +<FormBase> + <div class="_formItem"> + <div class="_formPanel fwhjspax"> + <img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" alt="" class="icon"/> + <span class="name">{{ $instance.name || host }}</span> + </div> </div> + + <FormTextarea readonly :value="$instance.description"> + </FormTextarea> + <FormGroup> <FormKeyValueView> <template #key>Misskey</template> <template #value>v{{ version }}</template> </FormKeyValueView> + <FormLink to="/about-misskey">{{ $ts.aboutMisskey }}</FormLink> </FormGroup> <FormGroup> <FormKeyValueView> <template #key>{{ $ts.administrator }}</template> - <template #value>{{ meta.maintainerName }}</template> + <template #value>{{ $instance.maintainerName }}</template> </FormKeyValueView> <FormKeyValueView> <template #key>{{ $ts.contact }}</template> - <template #value>{{ meta.maintainerEmail }}</template> + <template #value>{{ $instance.maintainerEmail }}</template> </FormKeyValueView> </FormGroup> - <FormLink v-if="meta.tosUrl" :to="meta.tosUrl" external>{{ $ts.tos }}</FormLink> + <FormLink v-if="$instance.tosUrl" :to="$instance.tosUrl" external>{{ $ts.tos }}</FormLink> - <FormGroup v-if="stats"> - <template #label>{{ $ts.statistics }}</template> - <FormKeyValueView> - <template #key>{{ $ts.users }}</template> - <template #value>{{ number(stats.originalUsersCount) }}</template> - </FormKeyValueView> - <FormKeyValueView> - <template #key>{{ $ts.notes }}</template> - <template #value>{{ number(stats.originalNotesCount) }}</template> - </FormKeyValueView> + <FormSuspense :p="initStats"> + <FormGroup> + <template #label>{{ $ts.statistics }}</template> + <FormKeyValueView> + <template #key>{{ $ts.users }}</template> + <template #value>{{ number(stats.originalUsersCount) }}</template> + </FormKeyValueView> + <FormKeyValueView> + <template #key>{{ $ts.notes }}</template> + <template #value>{{ number(stats.originalNotesCount) }}</template> + </FormKeyValueView> + </FormGroup> + </FormSuspense> + + <FormGroup> + <template #label>Well-known resources</template> + <FormLink :to="`/.well-known/host-meta`" external>host-meta</FormLink> + <FormLink :to="`/.well-known/host-meta.json`" external>host-meta.json</FormLink> + <FormLink :to="`/.well-known/nodeinfo`" external>nodeinfo</FormLink> + <FormLink :to="`/robots.txt`" external>robots.txt</FormLink> + <FormLink :to="`/manifest.json`" external>manifest.json</FormLink> </FormGroup> </FormBase> </template> @@ -45,9 +63,12 @@ import FormLink from '@client/components/form/link.vue'; import FormBase from '@client/components/form/base.vue'; import FormGroup from '@client/components/form/group.vue'; import FormKeyValueView from '@client/components/form/key-value-view.vue'; +import FormTextarea from '@client/components/form/textarea.vue'; +import FormSuspense from '@client/components/form/suspense.vue'; import * as os from '@client/os'; import number from '@client/filters/number'; import * as symbols from '@client/symbols'; +import { host } from '@client/config'; export default defineComponent({ components: { @@ -55,6 +76,8 @@ export default defineComponent({ FormGroup, FormLink, FormKeyValueView, + FormTextarea, + FormSuspense, }, data() { @@ -63,24 +86,17 @@ export default defineComponent({ title: this.$ts.instanceInfo, icon: 'fas fa-info-circle' }, + host, version, instanceName, stats: null, + initStats: () => os.api('stats', { + }).then((stats) => { + this.stats = stats; + }) } }, - computed: { - meta() { - return this.$instance; - }, - }, - - created() { - os.api('stats').then(stats => { - this.stats = stats; - }); - }, - methods: { number } @@ -88,18 +104,20 @@ export default defineComponent({ </script> <style lang="scss" scoped> -.mmnnbwxb { - max-width: 800px; - box-sizing: border-box; - margin: 0 auto; +.fwhjspax { + padding: 16px; + text-align: center; - > .logo { - text-align: center; + > .icon { + display: block; + margin: auto; + height: 64px; + border-radius: 8px; + } - > img { - vertical-align: bottom; - max-height: 100px; - } + > .name { + display: block; + margin-top: 12px; } } </style> diff --git a/src/client/pages/gallery/post.vue b/src/client/pages/gallery/post.vue index 86fae99888..9bd102cee2 100644 --- a/src/client/pages/gallery/post.vue +++ b/src/client/pages/gallery/post.vue @@ -19,7 +19,7 @@ <MkButton class="button" @click="like()" v-else v-tooltip="$ts._gallery.like"><i class="far fa-heart"></i><span class="count" v-if="post.likedCount > 0">{{ post.likedCount }}</span></MkButton> </div> <div class="other"> - <button class="_button" @click="createNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button> + <button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button> <button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button> </div> </div> @@ -125,6 +125,12 @@ export default defineComponent({ }); }, + shareWithNote() { + os.post({ + initialText: `${this.post.title} ${url}/gallery/${this.post.id}` + }); + }, + like() { os.apiWithDialog('gallery/posts/like', { postId: this.postId, @@ -148,12 +154,6 @@ export default defineComponent({ this.post.likedCount--; }); }, - - createNote() { - os.post({ - initialText: `${this.post.title} ${url}/gallery/${this.post.id}` - }); - } } }); </script> diff --git a/src/client/pages/instance-info.vue b/src/client/pages/instance-info.vue index 662b82ddb1..c66ad50f6d 100644 --- a/src/client/pages/instance-info.vue +++ b/src/client/pages/instance-info.vue @@ -147,7 +147,6 @@ import * as os from '@client/os'; import number from '@client/filters/number'; import bytes from '@client/filters/bytes'; import * as symbols from '@client/symbols'; -import { url } from '@client/config'; const chartLimit = 90; const sum = (...arr) => arr.reduce((r, a) => r.map((b, i) => a[i] + b)); @@ -449,7 +448,7 @@ export default defineComponent({ .fnfelxur { padding: 16px; - > img { + > .icon { display: block; margin: auto; height: 64px; diff --git a/src/client/pages/page.vue b/src/client/pages/page.vue index e43add7b0b..6ee3ee8d26 100644 --- a/src/client/pages/page.vue +++ b/src/client/pages/page.vue @@ -1,35 +1,60 @@ <template> -<div class="xcukqgmh _root" v-if="page" :key="page.id" v-size="{ max: [450] }"> - <div class="_block main"> - <!-- - <div class="header"> - <h1>{{ page.title }}</h1> +<div class="_root"> + <transition name="fade" mode="out-in"> + <div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }"> + <div class="_block main"> + <!-- + <div class="header"> + <h1>{{ page.title }}</h1> + </div> + --> + <div class="banner"> + <img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/> + </div> + <div class="content"> + <XPage :page="page"/> + </div> + <div class="actions"> + <div class="like"> + <MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> + <MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> + </div> + <div class="other"> + <button class="_button" @click="shareWithNote" v-tooltip="$ts.shareWithNote" v-click-anime><i class="fas fa-retweet fa-fw"></i></button> + <button class="_button" @click="share" v-tooltip="$ts.share" v-click-anime><i class="fas fa-share-alt fa-fw"></i></button> + </div> + </div> + <div class="user"> + <MkAvatar :user="page.user" class="avatar"/> + <div class="name"> + <MkUserName :user="page.user" style="display: block;"/> + <MkAcct :user="page.user"/> + </div> + <MkFollowButton v-if="!$i || $i.id != page.user.id" :user="page.user" :inline="true" :transparent="false" :full="true" large class="koudoku"/> + </div> + <div class="links"> + <MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA> + <template v-if="$i && $i.id === page.userId"> + <MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA> + <button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button> + <button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button> + </template> + </div> + </div> + <div class="footer"> + <div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div> + <div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div> + </div> + <MkContainer :max-height="300" :foldable="true" class="other"> + <template #header><i class="fas fa-clock"></i> {{ $ts.recentPosts }}</template> + <MkPagination :pagination="otherPostsPagination" #default="{items}"> + <MkPagePreview v-for="page in items" :page="page" :key="page.id" class="_gap"/> + </MkPagination> + </MkContainer> </div> - --> - <div class="banner"> - <img :src="page.eyeCatchingImage.url" v-if="page.eyeCatchingImageId"/> - </div> - <div class="content"> - <XPage :page="page"/> - <small style="display: block; opacity: 0.7; margin-top: 1em;">@{{ page.user.username }}</small> - </div> - <div class="like"> - <MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> - <MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton> - </div> - <div class="links"> - <MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA> - <template v-if="$i && $i.id === page.userId"> - <MkA :to="`/pages/edit/${page.id}`" class="link">{{ $ts._pages.editThisPage }}</MkA> - <button v-if="$i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $ts.unpin }}</button> - <button v-else @click="pin(true)" class="link _textButton">{{ $ts.pin }}</button> - </template> - </div> - </div> - <div class="footer"> - <div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div> - <div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div> - </div> + <MkError v-else-if="error" @retry="fetch()"/> + <MkLoading v-else/> + </transition> </div> </template> @@ -39,11 +64,20 @@ import XPage from '@client/components/page/page.vue'; import MkButton from '@client/components/ui/button.vue'; import * as os from '@client/os'; import * as symbols from '@client/symbols'; +import { url } from '@client/config'; +import MkFollowButton from '@client/components/follow-button.vue'; +import MkContainer from '@client/components/ui/container.vue'; +import MkPagination from '@client/components/ui/pagination.vue'; +import MkPagePreview from '@client/components/page-preview.vue'; export default defineComponent({ components: { XPage, MkButton, + MkFollowButton, + MkContainer, + MkPagination, + MkPagePreview, }, props: { @@ -69,6 +103,14 @@ export default defineComponent({ }, } : null), page: null, + error: null, + otherPostsPagination: { + endpoint: 'users/pages', + limit: 6, + params: () => ({ + userId: this.page.user.id + }) + }, }; }, @@ -90,11 +132,28 @@ export default defineComponent({ methods: { fetch() { + this.page = null; os.api('pages/show', { name: this.pageName, username: this.username, }).then(page => { this.page = page; + }).catch(e => { + this.error = e; + }); + }, + + share() { + navigator.share({ + title: this.page.title || this.page.name, + text: this.page.summary, + url: `${url}/@${this.page.user.username}/pages/${this.page.name}` + }); + }, + + shareWithNote() { + os.post({ + initialText: `${this.page.title || this.page.name} ${url}/@${this.page.user.username}/pages/${this.page.name}` }); }, @@ -132,6 +191,15 @@ export default defineComponent({ </script> <style lang="scss" scoped> +.fade-enter-active, +.fade-leave-active { + transition: opacity 0.125s ease; +} +.fade-enter-from, +.fade-leave-to { + opacity: 0; +} + .xcukqgmh { --padding: 32px; @@ -140,6 +208,8 @@ export default defineComponent({ } > .main { + padding: var(--padding); + > .header { padding: 16px; @@ -150,36 +220,79 @@ export default defineComponent({ > .banner { > img { + // TODO: 良い感じのアスペクト比で表示 display: block; width: 100%; - height: 120px; + height: 150px; object-fit: cover; } } > .content { - padding: var(--padding); + margin-top: 16px; + padding: 16px 0 0 0; } - > .like { - padding: var(--padding); + > .actions { + display: flex; + align-items: center; + margin-top: 16px; + padding: 16px 0 0 0; border-top: solid 0.5px var(--divider); - > .button { - --accent: rgb(241 97 132); - --X8: rgb(241 92 128); - --buttonBg: rgb(216 71 106 / 5%); - --buttonHoverBg: rgb(216 71 106 / 10%); - color: #ff002f; + > .like { + > .button { + --accent: rgb(241 97 132); + --X8: rgb(241 92 128); + --buttonBg: rgb(216 71 106 / 5%); + --buttonHoverBg: rgb(216 71 106 / 10%); + color: #ff002f; - ::v-deep(.count) { - margin-left: 0.5em; + ::v-deep(.count) { + margin-left: 0.5em; + } } } + + > .other { + margin-left: auto; + + > button { + padding: 8px; + margin: 0 8px; + + &:hover { + color: var(--fgHighlighted); + } + } + } + } + + > .user { + margin-top: 16px; + padding: 16px 0 0 0; + border-top: solid 0.5px var(--divider); + display: flex; + align-items: center; + + > .avatar { + width: 52px; + height: 52px; + } + + > .name { + margin: 0 0 0 12px; + font-size: 90%; + } + + > .koudoku { + margin-left: auto; + } } > .links { - padding: var(--padding); + margin-top: 16px; + padding: 24px 0 0 0; border-top: solid 0.5px var(--divider); > .link { diff --git a/src/client/store.ts b/src/client/store.ts index 0d34a02364..376135a99d 100644 --- a/src/client/store.ts +++ b/src/client/store.ts @@ -62,8 +62,9 @@ export const defaultStore = markRaw(new Storage('base', { 'notifications', 'messaging', 'drive', - '-', 'followRequests', + '-', + 'gallery', 'featured', 'explore', 'announcements', diff --git a/src/client/ui/chat/index.vue b/src/client/ui/chat/index.vue index be1bd7758a..bf55cc2b3f 100644 --- a/src/client/ui/chat/index.vue +++ b/src/client/ui/chat/index.vue @@ -313,7 +313,7 @@ export default defineComponent({ } }; if (isLink(e.target)) return; - if (['INPUT', 'TEXTAREA', 'IMG'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; + if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; if (window.getSelection().toString() !== '') return; const path = this.$route.path; os.contextMenu([{ diff --git a/src/client/ui/deck/main-column.vue b/src/client/ui/deck/main-column.vue index de36fd5966..7b5b50fedc 100644 --- a/src/client/ui/deck/main-column.vue +++ b/src/client/ui/deck/main-column.vue @@ -64,7 +64,7 @@ export default defineComponent({ } }; if (isLink(e.target)) return; - if (['INPUT', 'TEXTAREA', 'IMG'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; + if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; if (window.getSelection().toString() !== '') return; const path = this.$route.path; os.contextMenu([{ diff --git a/src/client/ui/default.sidebar.vue b/src/client/ui/default.sidebar.vue index a55a1770ff..725fd844d9 100644 --- a/src/client/ui/default.sidebar.vue +++ b/src/client/ui/default.sidebar.vue @@ -31,8 +31,10 @@ <i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span> </MkA> <div class="divider"></div> - <div class="foo"> - <MkEmoji :normal="true" :no-style="true" emoji="🍮"/> + <div class="about"> + <MkA class="link" to="/about" v-click-anime> + <img :src="$instance.iconUrl || $instance.faviconUrl || '/favicon.ico'" class="_ghost"/> + </MkA> </div> <!--<MisskeyLogo class="misskey"/>--> </div> @@ -260,14 +262,21 @@ export default defineComponent({ } } - > .misskey { + > .about { fill: currentColor; - } - - > .foo { - text-align: center; padding: 8px 0 16px 0; - opacity: 0.5; + text-align: center; + + > .link { + display: block; + width: 32px; + margin: 0 auto; + + img { + display: block; + width: 100%; + } + } } > .item { diff --git a/src/client/ui/default.vue b/src/client/ui/default.vue index 6cfb680719..64fdef2947 100644 --- a/src/client/ui/default.vue +++ b/src/client/ui/default.vue @@ -165,7 +165,7 @@ export default defineComponent({ } }; if (isLink(e.target)) return; - if (['INPUT', 'TEXTAREA', 'IMG'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; + if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; if (window.getSelection().toString() !== '') return; const path = this.$route.path; os.contextMenu([{ diff --git a/src/client/ui/universal.vue b/src/client/ui/universal.vue index 478fa13076..ad3c616b8e 100644 --- a/src/client/ui/universal.vue +++ b/src/client/ui/universal.vue @@ -191,7 +191,7 @@ export default defineComponent({ } }; if (isLink(e.target)) return; - if (['INPUT', 'TEXTAREA', 'IMG'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; + if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO'].includes(e.target.tagName) || e.target.attributes['contenteditable']) return; if (window.getSelection().toString() !== '') return; const path = this.$route.path; os.contextMenu([{ |