From 2458255e2244944b24cd90101e9fa00d07e35a1d Mon Sep 17 00:00:00 2001 From: syuilo Date: Wed, 20 Jun 2018 19:55:34 +0900 Subject: nanka iroiro --- src/client/app/common/views/components/index.ts | 4 +- .../views/components/messaging-room.message.vue | 2 +- .../views/components/misskey-flavored-markdown.ts | 185 +++++++++++++++++++++ .../app/common/views/components/note-html.ts | 185 --------------------- .../common/views/components/welcome-timeline.vue | 2 +- .../app/desktop/views/components/note-detail.vue | 2 +- .../app/desktop/views/components/notes.note.vue | 2 +- .../desktop/views/components/sub-note-content.vue | 2 +- .../app/desktop/views/pages/deck/deck.note.vue | 2 +- .../app/desktop/views/pages/user/user.header.vue | 101 ++++------- .../app/desktop/views/pages/user/user.home.vue | 103 ------------ .../app/desktop/views/pages/user/user.profile.vue | 16 +- src/client/app/desktop/views/pages/user/user.vue | 88 ++++++++-- .../app/mobile/views/components/note-detail.vue | 2 +- src/client/app/mobile/views/components/note.vue | 2 +- .../mobile/views/components/sub-note-content.vue | 2 +- src/client/app/mobile/views/pages/user.vue | 4 +- 17 files changed, 317 insertions(+), 387 deletions(-) create mode 100644 src/client/app/common/views/components/misskey-flavored-markdown.ts delete mode 100644 src/client/app/common/views/components/note-html.ts delete mode 100644 src/client/app/desktop/views/pages/user/user.home.vue (limited to 'src/client') 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..d7e7c6dcb5 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 @@ Delete
- +
diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts new file mode 100644 index 0000000000..61dbc02d9a --- /dev/null +++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts @@ -0,0 +1,185 @@ +import Vue from 'vue'; +import * as emojilib from 'emojilib'; +import parse from '../../../../../text/parse'; +import getAcct from '../../../../../acct/render'; +import { url } from '../../../config'; +import MkUrl from './url.vue'; +import MkGoogle from './google.vue'; + +const flatten = list => list.reduce( + (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [] +); + +export default Vue.component('misskey-flavored-markdown', { + props: { + text: { + type: String, + required: true + }, + ast: { + type: [], + required: false + }, + shouldBreak: { + type: Boolean, + default: true + }, + i: { + type: Object, + default: null + } + }, + + render(createElement) { + let ast; + + if (this.ast == null) { + // Parse text to ast + ast = parse(this.text); + } else { + ast = this.ast; + } + + if (ast.filter(x => x.type != 'hashtag').length == 0) { + return; + } + + while (ast[ast.length - 1] && ( + ast[ast.length - 1].type == 'hashtag' || + (ast[ast.length - 1].type == 'text' && ast[ast.length - 1].content == ' ') || + (ast[ast.length - 1].type == 'text' && ast[ast.length - 1].content == '\n'))) { + ast.pop(); + } + + // Parse ast to DOM + const els = flatten(ast.map(token => { + switch (token.type) { + case 'text': + const text = token.content.replace(/(\r\n|\n|\r)/g, '\n'); + + if (this.shouldBreak) { + const x = text.split('\n') + .map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]); + x[x.length - 1].pop(); + return x; + } else { + return createElement('span', text.replace(/\n/g, ' ')); + } + + case 'bold': + return createElement('strong', token.bold); + + case 'url': + return createElement(MkUrl, { + props: { + url: token.content, + target: '_blank' + } + }); + + case 'link': + return createElement('a', { + attrs: { + class: 'link', + href: token.url, + target: '_blank', + title: token.url + } + }, token.title); + + case 'mention': + return (createElement as any)('a', { + attrs: { + href: `${url}/@${getAcct(token)}`, + target: '_blank', + dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token) + }, + directives: [{ + name: 'user-preview', + value: token.content + }] + }, token.content); + + case 'hashtag': + return createElement('a', { + attrs: { + href: `${url}/tags/${token.hashtag}`, + target: '_blank' + } + }, token.content); + + case 'code': + return createElement('pre', { + class: 'code' + }, [ + createElement('code', { + domProps: { + innerHTML: token.html + } + }) + ]); + + case 'inline-code': + return createElement('code', { + domProps: { + innerHTML: token.html + } + }); + + case 'quote': + const text2 = token.quote.replace(/(\r\n|\n|\r)/g, '\n'); + + if (this.shouldBreak) { + const x = text2.split('\n') + .map(t => [createElement('span', t), createElement('br')]); + x[x.length - 1].pop(); + return createElement('div', { + attrs: { + class: 'quote' + } + }, x); + } else { + return createElement('span', { + attrs: { + class: 'quote' + } + }, text2.replace(/\n/g, ' ')); + } + + case 'title': + return createElement('div', { + attrs: { + class: 'title' + } + }, token.title); + + case 'emoji': + const emoji = emojilib.lib[token.emoji]; + return createElement('span', emoji ? emoji.char : token.content); + + case 'search': + return createElement(MkGoogle, { + props: { + q: token.query + } + }); + + default: + console.log('unknown ast type:', token.type); + } + })); + + const _els = []; + els.forEach((el, i) => { + if (el.tag == 'br') { + if (!['div', 'pre'].includes(els[i - 1].tag)) { + _els.push(el); + } + } else { + _els.push(el); + } + }); + + return createElement('span', _els); + } +}); diff --git a/src/client/app/common/views/components/note-html.ts b/src/client/app/common/views/components/note-html.ts deleted file mode 100644 index 8fa5f380dd..0000000000 --- a/src/client/app/common/views/components/note-html.ts +++ /dev/null @@ -1,185 +0,0 @@ -import Vue from 'vue'; -import * as emojilib from 'emojilib'; -import parse from '../../../../../text/parse'; -import getAcct from '../../../../../acct/render'; -import { url } from '../../../config'; -import MkUrl from './url.vue'; -import MkGoogle from './google.vue'; - -const flatten = list => list.reduce( - (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [] -); - -export default Vue.component('mk-note-html', { - props: { - text: { - type: String, - required: true - }, - ast: { - type: [], - required: false - }, - shouldBreak: { - type: Boolean, - default: true - }, - i: { - type: Object, - default: null - } - }, - - render(createElement) { - let ast; - - if (this.ast == null) { - // Parse text to ast - ast = parse(this.text); - } else { - ast = this.ast; - } - - if (ast.filter(x => x.type != 'hashtag').length == 0) { - return; - } - - while (ast[ast.length - 1] && ( - ast[ast.length - 1].type == 'hashtag' || - (ast[ast.length - 1].type == 'text' && ast[ast.length - 1].content == ' ') || - (ast[ast.length - 1].type == 'text' && ast[ast.length - 1].content == '\n'))) { - ast.pop(); - } - - // Parse ast to DOM - const els = flatten(ast.map(token => { - switch (token.type) { - case 'text': - const text = token.content.replace(/(\r\n|\n|\r)/g, '\n'); - - if (this.shouldBreak) { - const x = text.split('\n') - .map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]); - x[x.length - 1].pop(); - return x; - } else { - return createElement('span', text.replace(/\n/g, ' ')); - } - - case 'bold': - return createElement('strong', token.bold); - - case 'url': - return createElement(MkUrl, { - props: { - url: token.content, - target: '_blank' - } - }); - - case 'link': - return createElement('a', { - attrs: { - class: 'link', - href: token.url, - target: '_blank', - title: token.url - } - }, token.title); - - case 'mention': - return (createElement as any)('a', { - attrs: { - href: `${url}/@${getAcct(token)}`, - target: '_blank', - dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token) - }, - directives: [{ - name: 'user-preview', - value: token.content - }] - }, token.content); - - case 'hashtag': - return createElement('a', { - attrs: { - href: `${url}/tags/${token.hashtag}`, - target: '_blank' - } - }, token.content); - - case 'code': - return createElement('pre', { - class: 'code' - }, [ - createElement('code', { - domProps: { - innerHTML: token.html - } - }) - ]); - - case 'inline-code': - return createElement('code', { - domProps: { - innerHTML: token.html - } - }); - - case 'quote': - const text2 = token.quote.replace(/(\r\n|\n|\r)/g, '\n'); - - if (this.shouldBreak) { - const x = text2.split('\n') - .map(t => [createElement('span', t), createElement('br')]); - x[x.length - 1].pop(); - return createElement('div', { - attrs: { - class: 'quote' - } - }, x); - } else { - return createElement('span', { - attrs: { - class: 'quote' - } - }, text2.replace(/\n/g, ' ')); - } - - case 'title': - return createElement('div', { - attrs: { - class: 'title' - } - }, token.title); - - case 'emoji': - const emoji = emojilib.lib[token.emoji]; - return createElement('span', emoji ? emoji.char : token.content); - - case 'search': - return createElement(MkGoogle, { - props: { - q: token.query - } - }); - - default: - console.log('unknown ast type:', token.type); - } - })); - - const _els = []; - els.forEach((el, i) => { - if (el.tag == 'br') { - if (!['div', 'pre'].includes(els[i - 1].tag)) { - _els.push(el); - } - } else { - _els.push(el); - } - }); - - return createElement('span', _els); - } -}); 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 @@
- +
diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue index 4b5e5bebdf..017f599e31 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 @@
%i18n:@private% %i18n:@deleted% - +
diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue index ee11fcc55f..661223ee25 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 @@ %i18n:@private% %i18n:@deleted% %fa:reply% - + RP:
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 @@ %i18n:@private% %i18n:@deleted% %fa:reply% - + RP: ...
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..067297af37 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 @@ (%i18n:@private%) (%i18n:@deleted%) %fa:reply% - + RP:
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..d0976a32e1 100644 --- a/src/client/app/desktop/views/pages/user/user.header.vue +++ b/src/client/app/desktop/views/pages/user/user.header.vue @@ -5,17 +5,15 @@ -
-

{{ user | userName }}

%fa:map-marker%{{ user.profile.location }}

-
- %fa:home%ホーム -
+
+ +
+
@@ -76,12 +74,11 @@ export default Vue.extend({ 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 @@ - - - - - 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 @@ -
{{ user.description }}

%fa:birthday-cake%{{ user.profile.birthday.replace('-', '年').replace('-', '月') + '日' }} ({{ age }}歳)

@@ -116,8 +115,8 @@ export default Vue.extend({ diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue index 3644286fbc..3741629b72 100644 --- a/src/client/app/desktop/views/pages/user/user.vue +++ b/src/client/app/desktop/views/pages/user/user.vue @@ -1,8 +1,21 @@ @@ -13,17 +26,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 +63,60 @@ export default Vue.extend({ Progress.done(); document.title = getUserName(this.user) + ' | Misskey'; }); + }, + + warp(date) { + (this.$refs.tl as any).warp(date); } } }); + diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue index f3e77d7062..6499f78f1b 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 @@
(%i18n:@private%) (%i18n:@deleted%) - +
{{ tag }} diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue index 4498bb5633..77513a6591 100644 --- a/src/client/app/mobile/views/components/note.vue +++ b/src/client/app/mobile/views/components/note.vue @@ -25,7 +25,7 @@ (%i18n:@private%) (%i18n:@deleted%) %fa:reply% - + RP:
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 @@ (%i18n:@private%) (%i18n:@deleted%) %fa:reply% - + RP: ...
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 @@ %i18n:@follows-you% -
{{ user.description }}
+
+ +

%fa:map-marker%{{ user.profile.location }} -- cgit v1.2.3-freya