diff options
Diffstat (limited to 'src/client')
27 files changed, 419 insertions, 262 deletions
diff --git a/src/client/app/common/scripts/check-for-update.ts b/src/client/app/common/scripts/check-for-update.ts index b5ba6916d1..4445eefc39 100644 --- a/src/client/app/common/scripts/check-for-update.ts +++ b/src/client/app/common/scripts/check-for-update.ts @@ -23,7 +23,10 @@ export default async function(mios: MiOS, force = false, silent = false) { } if (!silent) { - alert('%i18n:common.update-available%'.replace('{newer}', newer).replace('{current}', current)); + mios.apis.dialog({ + title: '%i18n:common.update-available-title%', + text: '%i18n:common.update-available%'.replace('{newer}', newer).replace('{current}', current) + }); } return newer; diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 5b2fa084fb..e2cba2e53b 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -9,7 +9,7 @@ import forkit from './forkit.vue'; import acct from './acct.vue'; import avatar from './avatar.vue'; import nav from './nav.vue'; -import noteHtml from './note-html'; +import misskeyFlavoredMarkdown from './misskey-flavored-markdown'; import poll from './poll.vue'; import pollEditor from './poll-editor.vue'; import reactionIcon from './reaction-icon.vue'; @@ -47,7 +47,7 @@ Vue.component('mk-forkit', forkit); Vue.component('mk-acct', acct); Vue.component('mk-avatar', avatar); Vue.component('mk-nav', nav); -Vue.component('mk-note-html', noteHtml); +Vue.component('misskey-flavored-markdown', misskeyFlavoredMarkdown); Vue.component('mk-poll', poll); Vue.component('mk-poll-editor', pollEditor); Vue.component('mk-reaction-icon', reactionIcon); diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue index a77b5f3658..f33173da6f 100644 --- a/src/client/app/common/views/components/messaging-room.message.vue +++ b/src/client/app/common/views/components/messaging-room.message.vue @@ -8,7 +8,7 @@ <img src="/assets/desktop/messaging/delete.png" alt="Delete"/> </button> <div class="content" v-if="!message.isDeleted"> - <mk-note-html class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/> + <misskey-flavored-markdown class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/> <div class="file" v-if="message.file"> <a :href="message.file.url" target="_blank" :title="message.file.name"> <img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/> @@ -32,7 +32,7 @@ <script lang="ts"> import Vue from 'vue'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; export default Vue.extend({ props: { diff --git a/src/client/app/common/views/components/note-html.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts index 8fa5f380dd..30ad3ce3f2 100644 --- a/src/client/app/common/views/components/note-html.ts +++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts @@ -1,6 +1,6 @@ import Vue from 'vue'; import * as emojilib from 'emojilib'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import getAcct from '../../../../../acct/render'; import { url } from '../../../config'; import MkUrl from './url.vue'; @@ -10,7 +10,7 @@ const flatten = list => list.reduce( (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [] ); -export default Vue.component('mk-note-html', { +export default Vue.component('misskey-flavored-markdown', { props: { text: { type: String, diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue index f3372bf062..bf2c653766 100644 --- a/src/client/app/common/views/components/welcome-timeline.vue +++ b/src/client/app/common/views/components/welcome-timeline.vue @@ -13,7 +13,7 @@ </div> </header> <div class="text"> - <mk-note-html v-if="note.text" :text="note.text"/> + <misskey-flavored-markdown v-if="note.text" :text="note.text"/> </div> </div> </div> diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue index 4b5e5bebdf..a9640ff9c4 100644 --- a/src/client/app/desktop/views/components/note-detail.vue +++ b/src/client/app/desktop/views/components/note-detail.vue @@ -40,7 +40,7 @@ <div class="text"> <span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span> - <mk-note-html v-if="p.text" :text="p.text" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/> </div> <div class="media" v-if="p.media.length > 0"> <mk-media-list :media-list="p.media" :raw="true"/> @@ -83,7 +83,7 @@ <script lang="ts"> import Vue from 'vue'; import dateStringify from '../../../common/scripts/date-stringify'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import MkPostFormWindow from './post-form-window.vue'; import MkRenoteFormWindow from './renote-form-window.vue'; diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue index ee11fcc55f..b96ae2da5a 100644 --- a/src/client/app/desktop/views/components/notes.note.vue +++ b/src/client/app/desktop/views/components/notes.note.vue @@ -25,7 +25,7 @@ <span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="p.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span> <a class="reply" v-if="p.reply">%fa:reply%</a> - <mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/> + <misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/> <a class="rp" v-if="p.renote">RP:</a> </div> <div class="media" v-if="p.media.length > 0"> @@ -76,7 +76,7 @@ import Vue from 'vue'; import dateStringify from '../../../common/scripts/date-stringify'; import canHideText from '../../../common/scripts/can-hide-text'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import MkPostFormWindow from './post-form-window.vue'; import MkRenoteFormWindow from './renote-form-window.vue'; diff --git a/src/client/app/desktop/views/components/notes.vue b/src/client/app/desktop/views/components/notes.vue index 69f3739f79..5c595c4ca5 100644 --- a/src/client/app/desktop/views/components/notes.vue +++ b/src/client/app/desktop/views/components/notes.vue @@ -9,7 +9,8 @@ <button @click="resolveInitPromise">%i18n:@retry%</button> </div> - <transition-group name="mk-notes" class="transition"> + <!-- トランジションを有効にするとなぜかメモリリークする --> + <!--<transition-group name="mk-notes" class="transition">--> <template v-for="(note, i) in _notes"> <x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)"/> <p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date"> @@ -17,7 +18,7 @@ <span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span> </p> </template> - </transition-group> + <!--</transition-group>--> <footer v-if="more"> <button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue index 33f2288e06..3832e5b38c 100644 --- a/src/client/app/desktop/views/components/post-form.vue +++ b/src/client/app/desktop/views/components/post-form.vue @@ -49,7 +49,7 @@ import Vue from 'vue'; import * as XDraggable from 'vuedraggable'; import getKao from '../../../common/scripts/get-kao'; import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import { host } from '../../../config'; export default Vue.extend({ diff --git a/src/client/app/desktop/views/components/sub-note-content.vue b/src/client/app/desktop/views/components/sub-note-content.vue index 45ce6a6f8f..cb0374b910 100644 --- a/src/client/app/desktop/views/components/sub-note-content.vue +++ b/src/client/app/desktop/views/components/sub-note-content.vue @@ -4,7 +4,7 @@ <span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="note.deletedAt" style="opacity: 0.5">%i18n:@deleted%</span> <a class="reply" v-if="note.replyId">%fa:reply%</a> - <mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/> <a class="rp" v-if="note.renoteId" :href="`/notes/${note.renoteId}`">RP: ...</a> </div> <details v-if="note.media.length > 0"> diff --git a/src/client/app/desktop/views/pages/deck/deck.note.vue b/src/client/app/desktop/views/pages/deck/deck.note.vue index 5a8dc2ea65..d50fc3c235 100644 --- a/src/client/app/desktop/views/pages/deck/deck.note.vue +++ b/src/client/app/desktop/views/pages/deck/deck.note.vue @@ -25,7 +25,7 @@ <span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span> <span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span> <a class="reply" v-if="p.reply">%fa:reply%</a> - <mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i"/> <a class="rp" v-if="p.renote != null">RP:</a> </div> <div class="media" v-if="p.media.length > 0"> @@ -67,7 +67,7 @@ <script lang="ts"> import Vue from 'vue'; -import parse from '../../../../../../text/parse'; +import parse from '../../../../../../mfm/parse'; import canHideText from '../../../../common/scripts/can-hide-text'; import MkNoteMenu from '../../../../common/views/components/note-menu.vue'; diff --git a/src/client/app/desktop/views/pages/deck/deck.notes.vue b/src/client/app/desktop/views/pages/deck/deck.notes.vue index 8862b0e0fc..c135c6cd5a 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notes.vue +++ b/src/client/app/desktop/views/pages/deck/deck.notes.vue @@ -7,7 +7,8 @@ <button @click="resolveInitPromise">%i18n:@retry%</button> </div> - <transition-group name="mk-notes" class="transition"> + <!-- トランジションを有効にするとなぜかメモリリークする --> + <!--<transition-group name="mk-notes" class="transition">--> <template v-for="(note, i) in _notes"> <x-note :note="note" :key="note.id" @update:note="onNoteUpdated(i, $event)" :media-view="mediaView"/> <p class="date" :key="note.id + '_date'" v-if="i != notes.length - 1 && note._date != _notes[i + 1]._date"> @@ -15,7 +16,7 @@ <span>%fa:angle-down%{{ _notes[i + 1]._datetext }}</span> </p> </template> - </transition-group> + <!--</transition-group>--> <footer v-if="more"> <button @click="loadMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }"> diff --git a/src/client/app/desktop/views/pages/deck/deck.notifications.vue b/src/client/app/desktop/views/pages/deck/deck.notifications.vue index f54ad1a3cd..10c06b0ad2 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notifications.vue +++ b/src/client/app/desktop/views/pages/deck/deck.notifications.vue @@ -1,6 +1,8 @@ <template> <div class="oxynyeqmfvracxnglgulyqfgqxnxmehl"> - <transition-group name="mk-notifications" class="transition notifications"> + <!-- トランジションを有効にするとなぜかメモリリークする --> + <!--<transition-group name="mk-notifications" class="transition notifications">--> + <div class="notifications"> <template v-for="(notification, i) in _notifications"> <x-notification class="notification" :notification="notification" :key="notification.id"/> <p class="date" v-if="i != notifications.length - 1 && notification._date != _notifications[i + 1]._date" :key="notification.id + '-time'"> @@ -8,7 +10,8 @@ <span>%fa:angle-down%{{ _notifications[i + 1]._datetext }}</span> </p> </template> - </transition-group> + </div> + <!--</transition-group>--> <button class="more" :class="{ fetching: fetchingMoreNotifications }" v-if="moreNotifications" @click="fetchMoreNotifications" :disabled="fetchingMoreNotifications"> <template v-if="fetchingMoreNotifications">%fa:spinner .pulse .fw%</template>{{ fetchingMoreNotifications ? '%i18n:common.loading%' : '%i18n:@more%' }} </button> diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue index d52c6b762c..afb8de4b2a 100644 --- a/src/client/app/desktop/views/pages/user/user.header.vue +++ b/src/client/app/desktop/views/pages/user/user.header.vue @@ -1,21 +1,17 @@ <template> <div class="header" :data-is-dark-background="user.bannerUrl != null"> - <div class="is-suspended" v-if="user.isSuspended"><p>%fa:exclamation-triangle% %i18n:@is-suspended%</p></div> - <div class="is-remote" v-if="user.host != null"><p>%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></p></div> <div class="banner-container" :style="style"> <div class="banner" ref="banner" :style="style" @click="onBannerClick"></div> <div class="fade"></div> - </div> - <div class="container"> - <mk-avatar class="avatar" :user="user" :disable-preview="true"/> <div class="title"> <p class="name">{{ user | userName }}</p> <p class="username"><mk-acct :user="user"/></p> <p class="location" v-if="user.host === null && user.profile.location">%fa:map-marker%{{ user.profile.location }}</p> </div> - <footer> - <router-link :to="user | userPage" :data-active="$parent.page == 'home'">%fa:home%ホーム</router-link> - </footer> + </div> + <mk-avatar class="avatar" :user="user" :disable-preview="true"/> + <div class="body"> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/> </div> </div> </template> @@ -36,16 +32,16 @@ export default Vue.extend({ }, mounted() { if (this.user.bannerUrl) { - window.addEventListener('load', this.onScroll); - window.addEventListener('scroll', this.onScroll, { passive: true }); - window.addEventListener('resize', this.onScroll); + //window.addEventListener('load', this.onScroll); + //window.addEventListener('scroll', this.onScroll, { passive: true }); + //window.addEventListener('resize', this.onScroll); } }, beforeDestroy() { if (this.user.bannerUrl) { - window.removeEventListener('load', this.onScroll); - window.removeEventListener('scroll', this.onScroll); - window.removeEventListener('resize', this.onScroll); + //window.removeEventListener('load', this.onScroll); + //window.removeEventListener('scroll', this.onScroll); + //window.removeEventListener('resize', this.onScroll); } }, methods: { @@ -76,31 +72,11 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.header - $footer-height = 58px - +root(isDark) + background isDark ? #282C37 : #fff + border 1px solid rgba(#000, 0.075) + border-radius 6px overflow hidden - background #f7f7f7 - box-shadow 0 1px 1px rgba(#000, 0.075) - - > .is-suspended - > .is-remote - &.is-suspended - color #570808 - background #ffdbdb - - &.is-remote - color #573c08 - background #fff0db - - > p - margin 0 auto - padding 14px 16px - max-width 1200px - font-size 14px - - > a - font-weight bold &[data-is-dark-background] > .banner-container @@ -110,7 +86,6 @@ export default Vue.extend({ > .fade background linear-gradient(transparent, rgba(#000, 0.7)) - > .container > .title color #fff @@ -118,7 +93,7 @@ export default Vue.extend({ text-shadow 0 0 8px #000 > .banner-container - height 320px + height 250px overflow hidden background-size cover background-position center @@ -136,37 +111,21 @@ export default Vue.extend({ width 100% height 78px - > .container - max-width 1200px - margin 0 auto - - > .avatar - display block - position absolute - bottom 16px - left 16px - z-index 2 - width 160px - height 160px - border solid 3px #fff - border-radius 8px - box-shadow 1px 1px 3px rgba(#000, 0.2) - > .title position absolute - bottom $footer-height + bottom 0 left 0 width 100% - padding 0 0 8px 195px + padding 0 0 8px 154px color #5e6367 font-family '游ゴシック', 'YuGothic', 'ヒラギノ角ゴ ProN W3', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif > .name display block margin 0 - line-height 40px + line-height 32px font-weight bold - font-size 2em + font-size 1.8em > .username > .location @@ -178,41 +137,24 @@ export default Vue.extend({ > i margin-right 4px - > footer - z-index 1 - height $footer-height - padding-left 195px + > .avatar + display block + position absolute + top 170px + left 16px + z-index 2 + width 120px + height 120px + box-shadow 1px 1px 3px rgba(#000, 0.2) - > a - display inline-block - margin 0 - padding 0 16px - height $footer-height - line-height $footer-height - color #555 + > .body + padding 16px 16px 16px 154px + color isDark ? #c5ced6 : #555 - &[data-active] - border-bottom solid 4px $theme-color - - > i - margin-right 6px - - > button - display block - position absolute - top 0 - right 0 - margin 8px - padding 0 - width $footer-height - 16px - line-height $footer-height - 16px - 2px - font-size 1.2em - color #777 - border solid 1px #eee - border-radius 4px +.header[data-darkmode] + root(true) - &:hover - color #555 - border solid 1px #ddd +.header:not([data-darkmode]) + root(false) </style> diff --git a/src/client/app/desktop/views/pages/user/user.home.vue b/src/client/app/desktop/views/pages/user/user.home.vue deleted file mode 100644 index afaf97dc9e..0000000000 --- a/src/client/app/desktop/views/pages/user/user.home.vue +++ /dev/null @@ -1,103 +0,0 @@ -<template> -<div class="home"> - <div> - <div ref="left"> - <x-profile :user="user"/> - <x-photos :user="user"/> - <x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> - <p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p> - </div> - </div> - <main> - <mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/> - <x-timeline class="timeline" ref="tl" :user="user"/> - </main> - <div> - <div ref="right"> - <mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/> - <mk-activity :user="user"/> - <x-friends :user="user"/> - <div class="nav"><mk-nav/></div> - </div> - </div> -</div> -</template> - -<script lang="ts"> -import Vue from 'vue'; -import XTimeline from './user.timeline.vue'; -import XProfile from './user.profile.vue'; -import XPhotos from './user.photos.vue'; -import XFollowersYouKnow from './user.followers-you-know.vue'; -import XFriends from './user.friends.vue'; - -export default Vue.extend({ - components: { - XTimeline, - XProfile, - XPhotos, - XFollowersYouKnow, - XFriends - }, - props: ['user'], - methods: { - warp(date) { - (this.$refs.tl as any).warp(date); - } - } -}); -</script> - -<style lang="stylus" scoped> -.home - display flex - justify-content center - margin 0 auto - max-width 1200px - - > main - > div > div - > *:not(:last-child) - margin-bottom 16px - - > main - padding 16px - width calc(100% - 275px * 2) - - > .timeline - border solid 1px rgba(#000, 0.075) - border-radius 6px - - > div - width 275px - margin 0 - - &:first-child > div - padding 16px 0 16px 16px - - > p - display block - margin 0 - padding 0 12px - text-align center - font-size 0.8em - color #aaa - - &:last-child > div - padding 16px 16px 16px 0 - - > .nav - padding 16px - font-size 12px - color #aaa - background #fff - border solid 1px rgba(#000, 0.075) - border-radius 6px - - a - color #999 - - i - color #ccc - -</style> diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue index 5aa08f7c85..8afa7122b3 100644 --- a/src/client/app/desktop/views/pages/user/user.profile.vue +++ b/src/client/app/desktop/views/pages/user/user.profile.vue @@ -15,7 +15,6 @@ </button> <button class="mute ui" @click="list">%fa:list% リストに追加</button> </div> - <div class="description" v-if="user.description">{{ user.description }}</div> <div class="birthday" v-if="user.host === null && user.profile.birthday"> <p>%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)</p> </div> @@ -116,8 +115,8 @@ export default Vue.extend({ </script> <style lang="stylus" scoped> -.profile - background #fff +root(isDark) + background isDark ? #282C37 : #fff border solid 1px rgba(#000, 0.075) border-radius 6px @@ -153,11 +152,6 @@ export default Vue.extend({ &:not(:last-child) margin-bottom 12px - > .description - padding 16px - color #555 - border-top solid 1px #eee - > .birthday padding 16px color #555 @@ -192,4 +186,10 @@ export default Vue.extend({ margin-left 8px margin-right 8px +.profile[data-darkmode] + root(true) + +.profile:not([data-darkmode]) + root(false) + </style> diff --git a/src/client/app/desktop/views/pages/user/user.timeline.vue b/src/client/app/desktop/views/pages/user/user.timeline.vue index 812b5b4229..67987fcb94 100644 --- a/src/client/app/desktop/views/pages/user/user.timeline.vue +++ b/src/client/app/desktop/views/pages/user/user.timeline.vue @@ -1,9 +1,9 @@ <template> -<div class="timeline"> +<div class="oh5y2r7l5lx8j6jj791ykeiwgihheguk"> <header> - <span :data-active="mode == 'default'" @click="mode = 'default'">%i18n:@default%</span> - <span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%i18n:@with-replies%</span> - <span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%i18n:@with-media%</span> + <span :data-active="mode == 'default'" @click="mode = 'default'">%fa:comment-alt R% %i18n:@default%</span> + <span :data-active="mode == 'with-replies'" @click="mode = 'with-replies'">%fa:comments% %i18n:@with-replies%</span> + <span :data-active="mode == 'with-media'" @click="mode = 'with-media'">%fa:images% %i18n:@with-media%</span> </header> <div class="loading" v-if="fetching"> <mk-ellipsis-icon/> @@ -114,25 +114,44 @@ export default Vue.extend({ <style lang="stylus" scoped> @import '~const.styl' -.timeline - background #fff +root(isDark) + background isDark ? #282C37 : #fff > header - padding 8px 16px - border-bottom solid 1px #eee + padding 0 8px + z-index 10 + background isDark ? #313543 : #fff + border-radius 6px 6px 0 0 + box-shadow 0 1px isDark ? rgba(#000, 0.15) : rgba(#000, 0.08) > span - margin-right 16px - line-height 27px - font-size 18px - color #555 + display inline-block + padding 0 10px + line-height 42px + font-size 12px + user-select none - &:not([data-active]) + &[data-active] color $theme-color + cursor default + font-weight bold + + &:before + content "" + display block + position absolute + bottom 0 + left -8px + width calc(100% + 16px) + height 2px + background $theme-color + + &:not([data-active]) + color isDark ? #9aa2a7 : #6f7477 cursor pointer &:hover - text-decoration underline + color isDark ? #d9dcde : #525a5f > .loading padding 64px 0 @@ -151,4 +170,10 @@ export default Vue.extend({ font-size 3em color #ccc +.oh5y2r7l5lx8j6jj791ykeiwgihheguk[data-darkmode] + root(true) + +.oh5y2r7l5lx8j6jj791ykeiwgihheguk:not([data-darkmode]) + root(false) + </style> diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue index 3644286fbc..7f05c695af 100644 --- a/src/client/app/desktop/views/pages/user/user.vue +++ b/src/client/app/desktop/views/pages/user/user.vue @@ -1,8 +1,25 @@ <template> <mk-ui> - <div class="user" v-if="!fetching"> - <x-header :user="user"/> - <x-home v-if="page == 'home'" :user="user"/> + <div class="zwwan0di1v4356rmdbjmwnn32tptpdp2" v-if="!fetching" :data-darkmode="$store.state.device.darkmode"> + <div class="is-suspended" v-if="user.isSuspended">%fa:exclamation-triangle% %i18n:@is-suspended%</div> + <div class="is-remote" v-if="user.host != null">%fa:exclamation-triangle% %i18n:@is-remote%<a :href="user.url || user.uri" target="_blank">%i18n:@view-remote%</a></div> + <main> + <div class="main"> + <x-header :user="user"/> + <mk-note-detail v-if="user.pinnedNote" :note="user.pinnedNote" :compact="true"/> + <x-timeline class="timeline" ref="tl" :user="user"/> + </div> + <div class="side"> + <x-profile :user="user"/> + <mk-calendar @chosen="warp" :start="new Date(user.createdAt)"/> + <mk-activity :user="user"/> + <x-photos :user="user"/> + <x-friends :user="user"/> + <x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> + <div class="nav"><mk-nav/></div> + <p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p> + </div> + </main> </div> </mk-ui> </template> @@ -13,17 +30,20 @@ import parseAcct from '../../../../../../acct/parse'; import getUserName from '../../../../../../renderers/get-user-name'; import Progress from '../../../../common/scripts/loading'; import XHeader from './user.header.vue'; -import XHome from './user.home.vue'; +import XTimeline from './user.timeline.vue'; +import XProfile from './user.profile.vue'; +import XPhotos from './user.photos.vue'; +import XFollowersYouKnow from './user.followers-you-know.vue'; +import XFriends from './user.friends.vue'; export default Vue.extend({ components: { XHeader, - XHome - }, - props: { - page: { - default: 'home' - } + XTimeline, + XProfile, + XPhotos, + XFollowersYouKnow, + XFriends }, data() { return { @@ -47,8 +67,87 @@ export default Vue.extend({ Progress.done(); document.title = getUserName(this.user) + ' | Misskey'; }); + }, + + warp(date) { + (this.$refs.tl as any).warp(date); } } }); </script> +<style lang="stylus" scoped> +root(isDark) + width 980px + padding 16px + margin 0 auto + + > .is-suspended + > .is-remote + margin-bottom 16px + padding 14px 16px + font-size 14px + border-radius 6px + + &.is-suspended + color isDark ? #ffb4b4 : #570808 + background isDark ? #611d1d : #ffdbdb + border solid 1px isDarl ? #d64a4a : #e09696 + + &.is-remote + color isDark ? #ffbd3e : #573c08 + background isDark ? #42321c : #fff0db + border solid 1px isDark ? #90733c : #dcbb7b + + > a + font-weight bold + + > main + display flex + justify-content center + + > .main + > .side + > *:not(:last-child) + margin-bottom 16px + + > .main + flex 1 + margin-right 16px + + > .timeline + border 1px solid rgba(#000, 0.075) + border-radius 6px + + > .side + width 275px + + > p + display block + margin 0 + padding 0 12px + text-align center + font-size 0.8em + color #aaa + + > .nav + padding 16px + font-size 12px + color #aaa + background #fff + border solid 1px rgba(#000, 0.075) + border-radius 6px + + a + color #999 + + i + color #ccc + +.zwwan0di1v4356rmdbjmwnn32tptpdp2[data-darkmode] + root(true) + +.zwwan0di1v4356rmdbjmwnn32tptpdp2:not([data-darkmode]) + root(false) + +</style> diff --git a/src/client/app/mobile/api/dialog.ts b/src/client/app/mobile/api/dialog.ts index a2378767be..23f35b7aa9 100644 --- a/src/client/app/mobile/api/dialog.ts +++ b/src/client/app/mobile/api/dialog.ts @@ -1,5 +1,18 @@ -export default function(opts) { +import OS from '../../mios'; +import Dialog from '../views/components/dialog.vue'; + +export default (os: OS) => opts => { return new Promise<string>((res, rej) => { - alert('dialog not implemented yet'); + const o = opts || {}; + const d = os.new(Dialog, { + title: o.title, + text: o.text, + modal: o.modal, + buttons: o.actions + }); + d.$once('clicked', id => { + res(id); + }); + document.body.appendChild(d.$el); }); -} +}; diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts index cc0a8331ba..cfa9654e61 100644 --- a/src/client/app/mobile/script.ts +++ b/src/client/app/mobile/script.ts @@ -88,7 +88,7 @@ init((launch) => { launch(router, os => ({ chooseDriveFolder, chooseDriveFile, - dialog, + dialog: dialog(os), input, post: post(os), notify diff --git a/src/client/app/mobile/views/components/dialog.vue b/src/client/app/mobile/views/components/dialog.vue new file mode 100644 index 0000000000..9ee01cb782 --- /dev/null +++ b/src/client/app/mobile/views/components/dialog.vue @@ -0,0 +1,171 @@ +<template> +<div class="mk-dialog"> + <div class="bg" ref="bg" @click="onBgClick"></div> + <div class="main" ref="main"> + <header v-html="title" :class="$style.header"></header> + <div class="body" v-html="text"></div> + <div class="buttons"> + <button v-for="button in buttons" @click="click(button)">{{ button.text }}</button> + </div> + </div> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import * as anime from 'animejs'; + +export default Vue.extend({ + props: { + title: { + type: String, + required: false + }, + text: { + type: String, + required: true + }, + buttons: { + type: Array, + default: () => { + return [{ + text: 'OK' + }]; + } + }, + modal: { + type: Boolean, + default: false + } + }, + mounted() { + this.$nextTick(() => { + (this.$refs.bg as any).style.pointerEvents = 'auto'; + anime({ + targets: this.$refs.bg, + opacity: 1, + duration: 100, + easing: 'linear' + }); + + anime({ + targets: this.$refs.main, + opacity: 1, + scale: [1.2, 1], + duration: 300, + easing: [0, 0.5, 0.5, 1] + }); + }); + }, + methods: { + click(button) { + this.$emit('clicked', button.id); + this.close(); + }, + close() { + (this.$refs.bg as any).style.pointerEvents = 'none'; + anime({ + targets: this.$refs.bg, + opacity: 0, + duration: 300, + easing: 'linear' + }); + + (this.$refs.main as any).style.pointerEvents = 'none'; + anime({ + targets: this.$refs.main, + opacity: 0, + scale: 0.8, + duration: 300, + easing: [ 0.5, -0.5, 1, 0.5 ], + complete: () => this.$destroy() + }); + }, + onBgClick() { + if (!this.modal) { + this.close(); + } + } + } +}); +</script> + +<style lang="stylus" scoped> +@import '~const.styl' + +.mk-dialog + > .bg + display block + position fixed + z-index 8192 + top 0 + left 0 + width 100% + height 100% + background rgba(#000, 0.7) + opacity 0 + pointer-events none + + > .main + display block + position fixed + z-index 8192 + top 20% + left 0 + right 0 + margin 0 auto 0 auto + padding 16px + width calc(100% - 32px) + max-width 300px + background #fff + opacity 0 + + > .body + margin 1em 0 + color #888 + + > .buttons + > button + display inline-block + float right + margin 0 + padding 0 10px + font-size 1.1em + font-weight normal + text-decoration none + color #888 + background transparent + outline none + border none + border-radius 0 + cursor pointer + transition color 0.1s ease + + i + margin 0 0.375em + + &:hover + color $theme-color + + &:active + color darken($theme-color, 10%) + transition color 0s ease + +</style> + +<style lang="stylus" module> +@import '~const.styl' + +.header + margin 0 0 1em 0 + color $theme-color + // color #43A4EC + font-weight bold + + &:empty + display none + + > i + margin-right 0.5em + +</style> diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue index f3e77d7062..76633490fd 100644 --- a/src/client/app/mobile/views/components/note-detail.vue +++ b/src/client/app/mobile/views/components/note-detail.vue @@ -38,7 +38,7 @@ <div class="text"> <span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span> <span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span> - <mk-note-html v-if="p.text" :text="p.text" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="p.text" :text="p.text" :i="$store.state.i"/> </div> <div class="tags" v-if="p.tags && p.tags.length > 0"> <router-link v-for="tag in p.tags" :key="tag" :to="`/tags/${tag}`">{{ tag }}</router-link> @@ -83,7 +83,7 @@ <script lang="ts"> import Vue from 'vue'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import MkNoteMenu from '../../../common/views/components/note-menu.vue'; import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue index 4498bb5633..ecdfee3b44 100644 --- a/src/client/app/mobile/views/components/note.vue +++ b/src/client/app/mobile/views/components/note.vue @@ -25,7 +25,7 @@ <span v-if="p.isHidden" style="opacity: 0.5">(%i18n:@private%)</span> <span v-if="p.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span> <a class="reply" v-if="p.reply">%fa:reply%</a> - <mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/> + <misskey-flavored-markdown v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/> <a class="rp" v-if="p.renote != null">RP:</a> </div> <div class="media" v-if="p.media.length > 0"> @@ -68,7 +68,7 @@ <script lang="ts"> import Vue from 'vue'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import canHideText from '../../../common/scripts/can-hide-text'; import MkNoteMenu from '../../../common/views/components/note-menu.vue'; diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue index 62fa185085..1015a44115 100644 --- a/src/client/app/mobile/views/components/post-form.vue +++ b/src/client/app/mobile/views/components/post-form.vue @@ -45,7 +45,7 @@ import Vue from 'vue'; import * as XDraggable from 'vuedraggable'; import MkVisibilityChooser from '../../../common/views/components/visibility-chooser.vue'; import getKao from '../../../common/scripts/get-kao'; -import parse from '../../../../../text/parse'; +import parse from '../../../../../mfm/parse'; import { host } from '../../../config'; export default Vue.extend({ diff --git a/src/client/app/mobile/views/components/sub-note-content.vue b/src/client/app/mobile/views/components/sub-note-content.vue index 4ad90b97df..a4ce49786e 100644 --- a/src/client/app/mobile/views/components/sub-note-content.vue +++ b/src/client/app/mobile/views/components/sub-note-content.vue @@ -4,7 +4,7 @@ <span v-if="note.isHidden" style="opacity: 0.5">(%i18n:@private%)</span> <span v-if="note.deletedAt" style="opacity: 0.5">(%i18n:@deleted%)</span> <a class="reply" v-if="note.replyId">%fa:reply%</a> - <mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="note.text" :text="note.text" :i="$store.state.i"/> <a class="rp" v-if="note.renoteId">RP: ...</a> </div> <details v-if="note.media.length > 0"> diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue index 3d37015906..ba9de9f8a6 100644 --- a/src/client/app/mobile/views/pages/user.vue +++ b/src/client/app/mobile/views/pages/user.vue @@ -18,7 +18,9 @@ <span class="username"><mk-acct :user="user"/></span> <span class="followed" v-if="user.isFollowed">%i18n:@follows-you%</span> </div> - <div class="description">{{ user.description }}</div> + <div class="description"> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :i="$store.state.i"/> + </div> <div class="info"> <p class="location" v-if="user.host === null && user.profile.location"> %fa:map-marker%{{ user.profile.location }} diff --git a/src/client/assets/manifest.json b/src/client/assets/manifest.json index dcd1e26790..bae0ee7f1d 100644 --- a/src/client/assets/manifest.json +++ b/src/client/assets/manifest.json @@ -37,6 +37,6 @@ } ], "share_target": { - "url_template": "share?text={title}%20-%20{text}%20-%20{url}" + "url_template": "share?text=【{title}】%0A{text}%0A{url}" } } |