summaryrefslogtreecommitdiff
path: root/src/client/app/common/views/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/app/common/views/components')
-rw-r--r--src/client/app/common/views/components/autocomplete.vue12
-rw-r--r--src/client/app/common/views/components/avatar.vue42
-rw-r--r--src/client/app/common/views/components/google.vue67
-rw-r--r--src/client/app/common/views/components/index.ts2
-rw-r--r--src/client/app/common/views/components/media-list.vue17
-rw-r--r--src/client/app/common/views/components/messaging-room.message.vue32
-rw-r--r--src/client/app/common/views/components/messaging-room.vue16
-rw-r--r--src/client/app/common/views/components/messaging.vue45
-rw-r--r--src/client/app/common/views/components/nav.vue10
-rw-r--r--src/client/app/common/views/components/note-html.ts21
-rw-r--r--src/client/app/common/views/components/note-menu.vue12
-rw-r--r--src/client/app/common/views/components/othello.vue20
-rw-r--r--src/client/app/common/views/components/poll-editor.vue10
-rw-r--r--src/client/app/common/views/components/poll.vue17
-rw-r--r--src/client/app/common/views/components/reaction-picker.vue21
-rw-r--r--src/client/app/common/views/components/reactions-viewer.vue33
-rw-r--r--src/client/app/common/views/components/signin.vue4
-rw-r--r--src/client/app/common/views/components/signup.vue4
-rw-r--r--src/client/app/common/views/components/stream-indicator.vue2
-rw-r--r--src/client/app/common/views/components/switch.vue25
-rw-r--r--src/client/app/common/views/components/twitter-setting.vue2
-rw-r--r--src/client/app/common/views/components/url-preview.vue127
-rw-r--r--src/client/app/common/views/components/visibility-chooser.vue223
-rw-r--r--src/client/app/common/views/components/welcome-timeline.vue17
24 files changed, 592 insertions, 189 deletions
diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue
index 5c8f61a2a2..84173d20b5 100644
--- a/src/client/app/common/views/components/autocomplete.vue
+++ b/src/client/app/common/views/components/autocomplete.vue
@@ -234,7 +234,7 @@ export default Vue.extend({
margin-top calc(1em + 8px)
overflow hidden
background #fff
- border solid 1px rgba(0, 0, 0, 0.1)
+ border solid 1px rgba(#000, 0.1)
border-radius 4px
transition top 0.1s ease, left 0.1s ease
@@ -253,7 +253,7 @@ export default Vue.extend({
white-space nowrap
overflow hidden
font-size 0.9em
- color rgba(0, 0, 0, 0.8)
+ color rgba(#000, 0.8)
cursor default
&, *
@@ -285,10 +285,10 @@ export default Vue.extend({
.name
margin 0 8px 0 0
- color rgba(0, 0, 0, 0.8)
+ color rgba(#000, 0.8)
.username
- color rgba(0, 0, 0, 0.3)
+ color rgba(#000, 0.3)
> .emojis > li
@@ -298,10 +298,10 @@ export default Vue.extend({
width 24px
.name
- color rgba(0, 0, 0, 0.8)
+ color rgba(#000, 0.8)
.alias
margin 0 0 0 8px
- color rgba(0, 0, 0, 0.3)
+ color rgba(#000, 0.3)
</style>
diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue
new file mode 100644
index 0000000000..a4648c272e
--- /dev/null
+++ b/src/client/app/common/views/components/avatar.vue
@@ -0,0 +1,42 @@
+<template>
+ <router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-if="disablePreview"></router-link>
+ <router-link class="mk-avatar" :to="user | userPage" :title="user | acct" :target="target" :style="style" v-else v-user-preview="user.id"></router-link>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: {
+ user: {
+ type: Object,
+ required: true
+ },
+ target: {
+ required: false,
+ default: null
+ },
+ disablePreview: {
+ required: false,
+ default: false
+ }
+ },
+ computed: {
+ style(): any {
+ return {
+ backgroundColor: this.user.avatarColor ? `rgb(${ this.user.avatarColor.join(',') })` : null,
+ backgroundImage: `url(${ this.user.avatarUrl }?thumbnail)`,
+ borderRadius: (this as any).clientSettings.circleIcons ? '100%' : null
+ };
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-avatar
+ display inline-block
+ vertical-align bottom
+ background-size cover
+ background-position center center
+ transition border-radius 1s ease
+</style>
diff --git a/src/client/app/common/views/components/google.vue b/src/client/app/common/views/components/google.vue
new file mode 100644
index 0000000000..92817d3c1f
--- /dev/null
+++ b/src/client/app/common/views/components/google.vue
@@ -0,0 +1,67 @@
+<template>
+<div class="mk-google">
+ <input type="search" v-model="query" :placeholder="q">
+ <button @click="search">検索</button>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+export default Vue.extend({
+ props: ['q'],
+ data() {
+ return {
+ query: null
+ };
+ },
+ mounted() {
+ this.query = this.q;
+ },
+ methods: {
+ search() {
+ window.open(`https://www.google.com/?#q=${this.query}`, '_blank');
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+root(isDark)
+ display flex
+ margin 8px 0
+
+ > input
+ flex-shrink 1
+ padding 10px
+ width 100%
+ height 40px
+ font-family sans-serif
+ font-size 16px
+ color isDark ? #dee4e8 : #55595c
+ background isDark ? #191b22 : #fff
+ border solid 1px isDark ? #495156 : #dadada
+ border-radius 4px 0 0 4px
+
+ &:hover
+ border-color isDark ? #777c86 : #b0b0b0
+
+ > button
+ flex-shrink 0
+ padding 0 16px
+ border solid 1px isDark ? #495156 : #dadada
+ border-left none
+ border-radius 0 4px 4px 0
+
+ &:hover
+ background-color isDark ? #2e3440 : #eee
+
+ &:active
+ box-shadow 0 2px 4px rgba(#000, 0.15) inset
+
+.mk-google[data-darkmode]
+ root(true)
+
+.mk-google:not([data-darkmode])
+ root(false)
+
+</style>
diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts
index 6bfe43a800..69fed00c74 100644
--- a/src/client/app/common/views/components/index.ts
+++ b/src/client/app/common/views/components/index.ts
@@ -3,6 +3,7 @@ import Vue from 'vue';
import signin from './signin.vue';
import signup from './signup.vue';
import forkit from './forkit.vue';
+import avatar from './avatar.vue';
import nav from './nav.vue';
import noteHtml from './note-html';
import poll from './poll.vue';
@@ -28,6 +29,7 @@ import welcomeTimeline from './welcome-timeline.vue';
Vue.component('mk-signin', signin);
Vue.component('mk-signup', signup);
Vue.component('mk-forkit', forkit);
+Vue.component('mk-avatar', avatar);
Vue.component('mk-nav', nav);
Vue.component('mk-note-html', noteHtml);
Vue.component('mk-poll', poll);
diff --git a/src/client/app/common/views/components/media-list.vue b/src/client/app/common/views/components/media-list.vue
index 64172ad0b4..ff9d5e1022 100644
--- a/src/client/app/common/views/components/media-list.vue
+++ b/src/client/app/common/views/components/media-list.vue
@@ -2,7 +2,7 @@
<div class="mk-media-list" :data-count="mediaList.length">
<template v-for="media in mediaList">
<mk-media-video :video="media" :key="media.id" v-if="media.type.startsWith('video')" :inline-playable="mediaList.length === 1"/>
- <mk-media-image :image="media" :key="media.id" v-else />
+ <mk-media-image :image="media" :key="media.id" v-else :raw="raw"/>
</template>
</div>
</template>
@@ -11,7 +11,14 @@
import Vue from 'vue';
export default Vue.extend({
- props: ['mediaList'],
+ props: {
+ mediaList: {
+ required: true
+ },
+ raw: {
+ default: false
+ }
+ }
});
</script>
@@ -23,7 +30,7 @@ export default Vue.extend({
@media (max-width 500px)
height 192px
-
+
&[data-count="1"]
grid-template-rows 1fr
&[data-count="2"]
@@ -40,7 +47,7 @@ export default Vue.extend({
&[data-count="4"]
grid-template-columns 1fr 1fr
grid-template-rows 1fr 1fr
-
+
:nth-child(1)
grid-column 1 / 2
grid-row 1 / 2
@@ -53,5 +60,5 @@ export default Vue.extend({
:nth-child(4)
grid-column 2 / 3
grid-row 2 / 3
-
+
</style>
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 afd700e777..ba0ab3209f 100644
--- a/src/client/app/common/views/components/messaging-room.message.vue
+++ b/src/client/app/common/views/components/messaging-room.message.vue
@@ -1,8 +1,6 @@
<template>
<div class="message" :data-is-me="isMe">
- <router-link class="avatar-anchor" :to="message.user | userPage" :title="message.user | acct" target="_blank">
- <img class="avatar" :src="`${message.user.avatarUrl}?thumbnail&size=80`" alt=""/>
- </router-link>
+ <mk-avatar class="avatar" :user="message.user" target="_blank"/>
<div class="content">
<div class="balloon" :data-no-text="message.text == null">
<p class="read" v-if="isMe && message.isRead">%i18n:@is-read%</p>
@@ -67,20 +65,14 @@ export default Vue.extend({
padding 10px 12px 10px 12px
background-color transparent
- > .avatar-anchor
+ > .avatar
display block
position absolute
top 10px
-
- > .avatar
- display block
- min-width 54px
- min-height 54px
- max-width 54px
- max-height 54px
- margin 0
- border-radius 8px
- transition all 0.1s ease
+ width 54px
+ height 54px
+ border-radius 8px
+ transition all 0.1s ease
> .content
@@ -134,7 +126,7 @@ export default Vue.extend({
bottom -4px
left -12px
margin 0
- color rgba(0, 0, 0, 0.5)
+ color rgba(#000, 0.5)
font-size 11px
> .content
@@ -146,7 +138,7 @@ export default Vue.extend({
overflow hidden
overflow-wrap break-word
font-size 1em
- color rgba(0, 0, 0, 0.5)
+ color rgba(#000, 0.5)
> .text
display block
@@ -155,7 +147,7 @@ export default Vue.extend({
overflow hidden
overflow-wrap break-word
font-size 1em
- color rgba(0, 0, 0, 0.8)
+ color rgba(#000, 0.8)
& + .file
> a
@@ -195,13 +187,13 @@ export default Vue.extend({
display block
margin 2px 0 0 0
font-size 10px
- color rgba(0, 0, 0, 0.4)
+ color rgba(#000, 0.4)
> [data-fa]
margin-left 4px
&:not([data-is-me])
- > .avatar-anchor
+ > .avatar
left 12px
> .content
@@ -225,7 +217,7 @@ export default Vue.extend({
text-align left
&[data-is-me]
- > .avatar-anchor
+ > .avatar
right 12px
> .content
diff --git a/src/client/app/common/views/components/messaging-room.vue b/src/client/app/common/views/components/messaging-room.vue
index 38202d7581..a45114e6bb 100644
--- a/src/client/app/common/views/components/messaging-room.vue
+++ b/src/client/app/common/views/components/messaging-room.vue
@@ -256,7 +256,7 @@ export default Vue.extend({
padding 16px 8px 8px 8px
text-align center
font-size 0.8em
- color rgba(0, 0, 0, 0.4)
+ color rgba(#000, 0.4)
[data-fa]
margin-right 4px
@@ -267,7 +267,7 @@ export default Vue.extend({
padding 16px 8px 8px 8px
text-align center
font-size 0.8em
- color rgba(0, 0, 0, 0.4)
+ color rgba(#000, 0.4)
[data-fa]
margin-right 4px
@@ -278,7 +278,7 @@ export default Vue.extend({
padding 16px
text-align center
font-size 0.8em
- color rgba(0, 0, 0, 0.4)
+ color rgba(#000, 0.4)
[data-fa]
margin-right 4px
@@ -289,14 +289,14 @@ export default Vue.extend({
padding 0 12px
line-height 24px
color #fff
- background rgba(0, 0, 0, 0.3)
+ background rgba(#000, 0.3)
border-radius 12px
&:hover
- background rgba(0, 0, 0, 0.4)
+ background rgba(#000, 0.4)
&:active
- background rgba(0, 0, 0, 0.5)
+ background rgba(#000, 0.5)
&.fetching
cursor wait
@@ -322,7 +322,7 @@ export default Vue.extend({
left 0
right 0
margin 0 auto
- background rgba(0, 0, 0, 0.1)
+ background rgba(#000, 0.1)
> span
display inline-block
@@ -330,7 +330,7 @@ export default Vue.extend({
padding 0 16px
//font-weight bold
line-height 32px
- color rgba(0, 0, 0, 0.3)
+ color rgba(#000, 0.3)
background #fff
> footer
diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue
index f74d9643eb..11f9c366d4 100644
--- a/src/client/app/common/views/components/messaging.vue
+++ b/src/client/app/common/views/components/messaging.vue
@@ -13,7 +13,7 @@
@click="navigate(user)"
tabindex="-1"
>
- <img class="avatar" :src="`${user.avatarUrl}?thumbnail&size=32`" alt=""/>
+ <mk-avatar class="avatar" :user="user"/>
<span class="name">{{ user | userName }}</span>
<span class="username">@{{ user | acct }}</span>
</li>
@@ -31,7 +31,7 @@
:key="message.id"
>
<div>
- <img class="avatar" :src="`${isMe(message) ? message.recipient.avatarUrl : message.user.avatarUrl}?thumbnail&size=64`" alt=""/>
+ <mk-avatar class="avatar" :user="isMe(message) ? message.recipient : message.user"/>
<header>
<span class="name">{{ isMe(message) ? message.recipient : message.user | userName }}</span>
<span class="username">@{{ isMe(message) ? message.recipient : message.user | acct }}</span>
@@ -169,7 +169,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
@import '~const.styl'
-.mk-messaging
+root(isDark)
&[data-compact]
font-size 0.8em
@@ -205,11 +205,11 @@ export default Vue.extend({
z-index 1
width 100%
background #fff
- box-shadow 0 0px 2px rgba(0, 0, 0, 0.2)
+ box-shadow 0 0px 2px rgba(#000, 0.2)
> .form
padding 8px
- background #f7f7f7
+ background isDark ? #282c37 : #f7f7f7
> label
display block
@@ -241,13 +241,14 @@ export default Vue.extend({
line-height 38px
color #000
outline none
- border solid 1px #eee
+ background isDark ? #191b22 : #fff
+ border solid 1px isDark ? #495156 : #eee
border-radius 5px
box-shadow none
transition color 0.5s ease, border 0.5s ease
&:hover
- border solid 1px #ddd
+ border solid 1px isDark ? #b0b0b0 : #ddd
transition border 0.2s ease
&:focus
@@ -278,7 +279,7 @@ export default Vue.extend({
vertical-align top
white-space nowrap
overflow hidden
- color rgba(0, 0, 0, 0.8)
+ color rgba(#000, 0.8)
text-decoration none
transition none
cursor pointer
@@ -317,32 +318,32 @@ export default Vue.extend({
margin 0 8px 0 0
/*font-weight bold*/
font-weight normal
- color rgba(0, 0, 0, 0.8)
+ color rgba(#000, 0.8)
.username
font-weight normal
- color rgba(0, 0, 0, 0.3)
+ color rgba(#000, 0.3)
> .history
> a
display block
text-decoration none
- background #fff
- border-bottom solid 1px #eee
+ background isDark ? #282c37 : #fff
+ border-bottom solid 1px isDark ? #1c2023 : #eee
*
pointer-events none
user-select none
&:hover
- background #fafafa
+ background isDark ? #1e2129 : #fafafa
> .avatar
filter saturate(200%)
&:active
- background #eee
+ background isDark ? #14161b : #eee
&[data-is-read]
&[data-is-me]
@@ -382,17 +383,17 @@ export default Vue.extend({
overflow hidden
text-overflow ellipsis
font-size 1em
- color rgba(0, 0, 0, 0.9)
+ color isDark ? #fff : rgba(#000, 0.9)
font-weight bold
transition all 0.1s ease
> .username
margin 0 8px
- color rgba(0, 0, 0, 0.5)
+ color isDark ? #606984 : rgba(#000, 0.5)
> .mk-time
margin 0 0 0 auto
- color rgba(0, 0, 0, 0.5)
+ color isDark ? #606984 : rgba(#000, 0.5)
font-size 80%
> .avatar
@@ -412,10 +413,10 @@ export default Vue.extend({
overflow hidden
overflow-wrap break-word
font-size 1.1em
- color rgba(0, 0, 0, 0.8)
+ color isDark ? #fff : rgba(#000, 0.8)
.me
- color rgba(0, 0, 0, 0.4)
+ color isDark ? rgba(#fff, 0.7) : rgba(#000, 0.4)
> .image
display block
@@ -460,4 +461,10 @@ export default Vue.extend({
> .avatar
margin 0 12px 0 0
+.mk-messaging[data-darkmode]
+ root(true)
+
+.mk-messaging:not([data-darkmode])
+ root(false)
+
</style>
diff --git a/src/client/app/common/views/components/nav.vue b/src/client/app/common/views/components/nav.vue
index 2295957928..cd1f99288a 100644
--- a/src/client/app/common/views/components/nav.vue
+++ b/src/client/app/common/views/components/nav.vue
@@ -2,16 +2,10 @@
<span class="mk-nav">
<a :href="aboutUrl">%i18n:@about%</a>
<i>・</i>
- <a :href="statsUrl">%i18n:@stats%</a>
- <i>・</i>
- <a :href="statusUrl">%i18n:@status%</a>
- <i>・</i>
- <a href="http://zawazawa.jp/misskey/">%i18n:@wiki%</a>
- <i>・</i>
- <a href="https://github.com/syuilo/misskey/blob/master/DONORS.md">%i18n:@donors%</a>
- <i>・</i>
<a href="https://github.com/syuilo/misskey">%i18n:@repository%</a>
<i>・</i>
+ <a href="https://github.com/syuilo/misskey/issues/new" target="_blank">%i18n:@feedback%</a>
+ <i>・</i>
<a :href="devUrl">%i18n:@develop%</a>
<i>・</i>
<a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a>
diff --git a/src/client/app/common/views/components/note-html.ts b/src/client/app/common/views/components/note-html.ts
index 24e750a671..f86b50659e 100644
--- a/src/client/app/common/views/components/note-html.ts
+++ b/src/client/app/common/views/components/note-html.ts
@@ -4,6 +4,7 @@ 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), []
@@ -97,7 +98,9 @@ export default Vue.component('mk-note-html', {
}, token.content);
case 'code':
- return createElement('pre', [
+ return createElement('pre', {
+ class: 'code'
+ }, [
createElement('code', {
domProps: {
innerHTML: token.html
@@ -132,10 +135,24 @@ export default Vue.component('mk-note-html', {
}, 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);
}
@@ -144,7 +161,7 @@ export default Vue.component('mk-note-html', {
const _els = [];
els.forEach((el, i) => {
if (el.tag == 'br') {
- if (els[i - 1].tag != 'div') {
+ if (!['div', 'pre'].includes(els[i - 1].tag)) {
_els.push(el);
}
} else {
diff --git a/src/client/app/common/views/components/note-menu.vue b/src/client/app/common/views/components/note-menu.vue
index 877d2c16bb..88dc22aaf4 100644
--- a/src/client/app/common/views/components/note-menu.vue
+++ b/src/client/app/common/views/components/note-menu.vue
@@ -2,6 +2,7 @@
<div class="mk-note-menu">
<div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ compact }" ref="popover">
+ <button @click="favorite">%i18n:@favorite%</button>
<button v-if="note.userId == os.i.id" @click="pin">%i18n:@pin%</button>
<a v-if="note.uri" :href="note.uri" target="_blank">%i18n:@remote%</a>
</div>
@@ -58,6 +59,14 @@ export default Vue.extend({
});
},
+ favorite() {
+ (this as any).api('notes/favorites/create', {
+ noteId: this.note.id
+ }).then(() => {
+ this.$destroy();
+ });
+ },
+
close() {
(this.$refs.backdrop as any).style.pointerEvents = 'none';
anime({
@@ -96,7 +105,7 @@ $border-color = rgba(27, 31, 35, 0.15)
z-index 10000
width 100%
height 100%
- background rgba(0, 0, 0, 0.1)
+ background rgba(#000, 0.1)
opacity 0
> .popover
@@ -142,6 +151,7 @@ $border-color = rgba(27, 31, 35, 0.15)
> a
display block
padding 8px 16px
+ width 100%
&:hover
color $theme-color-foreground
diff --git a/src/client/app/common/views/components/othello.vue b/src/client/app/common/views/components/othello.vue
index 8f7d9dfd6a..a0971c45b4 100644
--- a/src/client/app/common/views/components/othello.vue
+++ b/src/client/app/common/views/components/othello.vue
@@ -31,7 +31,7 @@
<section v-if="invitations.length > 0">
<h2>対局の招待があります!:</h2>
<div class="invitation" v-for="i in invitations" tabindex="-1" @click="accept(i)">
- <img :src="`${i.parent.avatarUrl}?thumbnail&size=32`" alt="">
+ <mk-avatar class="avatar" :user="i.parent"/>
<span class="name"><b>{{ i.parent.name }}</b></span>
<span class="username">@{{ i.parent.username }}</span>
<mk-time :time="i.createdAt"/>
@@ -40,8 +40,8 @@
<section v-if="myGames.length > 0">
<h2>自分の対局</h2>
<a class="game" v-for="g in myGames" tabindex="-1" @click.prevent="go(g)" :href="`/othello/${g.id}`">
- <img :src="`${g.user1.avatarUrl}?thumbnail&size=32`" alt="">
- <img :src="`${g.user2.avatarUrl}?thumbnail&size=32`" alt="">
+ <mk-avatar class="avatar" :user="g.user1"/>
+ <mk-avatar class="avatar" :user="g.user2"/>
<span><b>{{ g.user1.name }}</b> vs <b>{{ g.user2.name }}</b></span>
<span class="state">{{ g.isEnded ? '終了' : '進行中' }}</span>
</a>
@@ -49,8 +49,8 @@
<section v-if="games.length > 0">
<h2>みんなの対局</h2>
<a class="game" v-for="g in games" tabindex="-1" @click.prevent="go(g)" :href="`/othello/${g.id}`">
- <img :src="`${g.user1.avatarUrl}?thumbnail&size=32`" alt="">
- <img :src="`${g.user2.avatarUrl}?thumbnail&size=32`" alt="">
+ <mk-avatar class="avatar" :user="g.user1"/>
+ <mk-avatar class="avatar" :user="g.user2"/>
<span><b>{{ g.user1.name }}</b> vs <b>{{ g.user2.name }}</b></span>
<span class="state">{{ g.isEnded ? '終了' : '進行中' }}</span>
</a>
@@ -271,8 +271,9 @@ export default Vue.extend({
&:active
background #eee
- > img
- vertical-align bottom
+ > .avatar
+ width 32px
+ height 32px
border-radius 100%
> span
@@ -301,8 +302,9 @@ export default Vue.extend({
&:active
background #eee
- > img
- vertical-align bottom
+ > .avatar
+ width 32px
+ height 32px
border-radius 100%
> span
diff --git a/src/client/app/common/views/components/poll-editor.vue b/src/client/app/common/views/components/poll-editor.vue
index 189172679b..95bcba996e 100644
--- a/src/client/app/common/views/components/poll-editor.vue
+++ b/src/client/app/common/views/components/poll-editor.vue
@@ -69,7 +69,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
@import '~const.styl'
-.mk-poll-editor
+root(isDark)
padding 8px
> .caution
@@ -102,6 +102,8 @@ export default Vue.extend({
padding 6px 8px
width 300px
font-size 14px
+ color isDark ? #fff : #000
+ background isDark ? #191b22 : #fff
border solid 1px rgba($theme-color, 0.1)
border-radius 4px
@@ -139,4 +141,10 @@ export default Vue.extend({
&:active
color darken($theme-color, 30%)
+.mk-poll-editor[data-darkmode]
+ root(true)
+
+.mk-poll-editor:not([data-darkmode])
+ root(false)
+
</style>
diff --git a/src/client/app/common/views/components/poll.vue b/src/client/app/common/views/components/poll.vue
index 1834d4ddc2..46e41cbcdb 100644
--- a/src/client/app/common/views/components/poll.vue
+++ b/src/client/app/common/views/components/poll.vue
@@ -68,7 +68,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
@import '~const.styl'
-.mk-poll
+root(isDark)
> ul
display block
@@ -81,16 +81,17 @@ export default Vue.extend({
margin 4px 0
padding 4px 8px
width 100%
- border solid 1px #eee
+ color isDark ? #fff : #000
+ border solid 1px isDark ? #5e636f : #eee
border-radius 4px
overflow hidden
cursor pointer
&:hover
- background rgba(0, 0, 0, 0.05)
+ background rgba(#000, 0.05)
&:active
- background rgba(0, 0, 0, 0.1)
+ background rgba(#000, 0.1)
> .backdrop
position absolute
@@ -108,6 +109,8 @@ export default Vue.extend({
margin-left 4px
> p
+ color isDark ? #a3aebf : #000
+
a
color inherit
@@ -121,4 +124,10 @@ export default Vue.extend({
&:active
background transparent
+.mk-poll[data-darkmode]
+ root(true)
+
+.mk-poll:not([data-darkmode])
+ root(false)
+
</style>
diff --git a/src/client/app/common/views/components/reaction-picker.vue b/src/client/app/common/views/components/reaction-picker.vue
index 267eeb3a14..e2c8a6ed3f 100644
--- a/src/client/app/common/views/components/reaction-picker.vue
+++ b/src/client/app/common/views/components/reaction-picker.vue
@@ -110,7 +110,7 @@ export default Vue.extend({
$border-color = rgba(27, 31, 35, 0.15)
-.mk-reaction-picker
+root(isDark)
position initial
> .backdrop
@@ -120,13 +120,14 @@ $border-color = rgba(27, 31, 35, 0.15)
z-index 10000
width 100%
height 100%
- background rgba(0, 0, 0, 0.1)
+ background isDark ? rgba(#000, 0.4) : rgba(#000, 0.1)
opacity 0
> .popover
+ $bgcolor = isDark ? #2c303c : #fff
position absolute
z-index 10001
- background #fff
+ background $bgcolor
border 1px solid $border-color
border-radius 4px
box-shadow 0 3px 12px rgba(27, 31, 35, 0.15)
@@ -159,15 +160,15 @@ $border-color = rgba(27, 31, 35, 0.15)
border-top solid $balloon-size transparent
border-left solid $balloon-size transparent
border-right solid $balloon-size transparent
- border-bottom solid $balloon-size #fff
+ border-bottom solid $balloon-size $bgcolor
> p
display block
margin 0
padding 8px 10px
font-size 14px
- color #586069
- border-bottom solid 1px #e1e4e8
+ color isDark ? #d6dce2 : #586069
+ border-bottom solid 1px isDark ? #1c2023 : #e1e4e8
> div
padding 4px
@@ -182,10 +183,16 @@ $border-color = rgba(27, 31, 35, 0.15)
border-radius 2px
&:hover
- background #eee
+ background isDark ? #252731 : #eee
&:active
background $theme-color
box-shadow inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15)
+.mk-reaction-picker[data-darkmode]
+ root(true)
+
+.mk-reaction-picker:not([data-darkmode])
+ root(false)
+
</style>
diff --git a/src/client/app/common/views/components/reactions-viewer.vue b/src/client/app/common/views/components/reactions-viewer.vue
index 1afcf525d2..97cb6be17c 100644
--- a/src/client/app/common/views/components/reactions-viewer.vue
+++ b/src/client/app/common/views/components/reactions-viewer.vue
@@ -1,15 +1,15 @@
<template>
<div class="mk-reactions-viewer">
<template v-if="reactions">
- <span v-if="reactions.like"><mk-reaction-icon reaction='like'/><span>{{ reactions.like }}</span></span>
- <span v-if="reactions.love"><mk-reaction-icon reaction='love'/><span>{{ reactions.love }}</span></span>
- <span v-if="reactions.laugh"><mk-reaction-icon reaction='laugh'/><span>{{ reactions.laugh }}</span></span>
- <span v-if="reactions.hmm"><mk-reaction-icon reaction='hmm'/><span>{{ reactions.hmm }}</span></span>
- <span v-if="reactions.surprise"><mk-reaction-icon reaction='surprise'/><span>{{ reactions.surprise }}</span></span>
- <span v-if="reactions.congrats"><mk-reaction-icon reaction='congrats'/><span>{{ reactions.congrats }}</span></span>
- <span v-if="reactions.angry"><mk-reaction-icon reaction='angry'/><span>{{ reactions.angry }}</span></span>
- <span v-if="reactions.confused"><mk-reaction-icon reaction='confused'/><span>{{ reactions.confused }}</span></span>
- <span v-if="reactions.pudding"><mk-reaction-icon reaction='pudding'/><span>{{ reactions.pudding }}</span></span>
+ <span v-if="reactions.like"><mk-reaction-icon reaction="like"/><span>{{ reactions.like }}</span></span>
+ <span v-if="reactions.love"><mk-reaction-icon reaction="love"/><span>{{ reactions.love }}</span></span>
+ <span v-if="reactions.laugh"><mk-reaction-icon reaction="laugh"/><span>{{ reactions.laugh }}</span></span>
+ <span v-if="reactions.hmm"><mk-reaction-icon reaction="hmm"/><span>{{ reactions.hmm }}</span></span>
+ <span v-if="reactions.surprise"><mk-reaction-icon reaction="surprise"/><span>{{ reactions.surprise }}</span></span>
+ <span v-if="reactions.congrats"><mk-reaction-icon reaction="congrats"/><span>{{ reactions.congrats }}</span></span>
+ <span v-if="reactions.angry"><mk-reaction-icon reaction="angry"/><span>{{ reactions.angry }}</span></span>
+ <span v-if="reactions.confused"><mk-reaction-icon reaction="confused"/><span>{{ reactions.confused }}</span></span>
+ <span v-if="reactions.pudding"><mk-reaction-icon reaction="pudding"/><span>{{ reactions.pudding }}</span></span>
</template>
</div>
</template>
@@ -27,9 +27,10 @@ export default Vue.extend({
</script>
<style lang="stylus" scoped>
-.mk-reactions-viewer
- border-top dashed 1px #eee
- border-bottom dashed 1px #eee
+root(isDark)
+ $borderColor = isDark ? #5e6673 : #eee
+ border-top dashed 1px $borderColor
+ border-bottom dashed 1px $borderColor
margin 4px 0
&:empty
@@ -44,6 +45,12 @@ export default Vue.extend({
> span
margin-left 4px
font-size 1.2em
- color #444
+ color isDark ? #d1d5dc : #444
+
+.mk-reactions-viewer[data-darkmode]
+ root(true)
+
+.mk-reactions-viewer:not([data-darkmode])
+ root(false)
</style>
diff --git a/src/client/app/common/views/components/signin.vue b/src/client/app/common/views/components/signin.vue
index 25f90a2f13..7fb9fc3fd4 100644
--- a/src/client/app/common/views/components/signin.vue
+++ b/src/client/app/common/views/components/signin.vue
@@ -91,7 +91,7 @@ export default Vue.extend({
width 100%
line-height 44px
font-size 1em
- color rgba(0, 0, 0, 0.7)
+ color rgba(#000, 0.7)
background #fff
outline none
border solid 1px #eee
@@ -117,7 +117,7 @@ export default Vue.extend({
margin -6px 0 0 0
width 100%
font-size 1.2em
- color rgba(0, 0, 0, 0.5)
+ color rgba(#000, 0.5)
outline none
border none
border-radius 0
diff --git a/src/client/app/common/views/components/signup.vue b/src/client/app/common/views/components/signup.vue
index 33a559ff8f..516979acd0 100644
--- a/src/client/app/common/views/components/signup.vue
+++ b/src/client/app/common/views/components/signup.vue
@@ -234,13 +234,13 @@ export default Vue.extend({
color #333 !important
background #fff !important
outline none
- border solid 1px rgba(0, 0, 0, 0.1)
+ border solid 1px rgba(#000, 0.1)
border-radius 4px
box-shadow 0 0 0 114514px #fff inset
transition all .3s ease
&:hover
- border-color rgba(0, 0, 0, 0.2)
+ border-color rgba(#000, 0.2)
transition all .1s ease
&:focus
diff --git a/src/client/app/common/views/components/stream-indicator.vue b/src/client/app/common/views/components/stream-indicator.vue
index 93758102de..d573db32e6 100644
--- a/src/client/app/common/views/components/stream-indicator.vue
+++ b/src/client/app/common/views/components/stream-indicator.vue
@@ -73,7 +73,7 @@ export default Vue.extend({
padding 6px 12px
font-size 0.9em
color #fff
- background rgba(0, 0, 0, 0.8)
+ background rgba(#000, 0.8)
border-radius 4px
> p
diff --git a/src/client/app/common/views/components/switch.vue b/src/client/app/common/views/components/switch.vue
index 19a4adc3de..32caab638a 100644
--- a/src/client/app/common/views/components/switch.vue
+++ b/src/client/app/common/views/components/switch.vue
@@ -87,7 +87,7 @@ export default Vue.extend({
<style lang="stylus" scoped>
@import '~const.styl'
-.mk-switch
+root(isDark)
display flex
margin 12px 0
cursor pointer
@@ -121,11 +121,12 @@ export default Vue.extend({
&:hover
> .label
> span
- color #2e3338
+ color isDark ? #fff : #2e3338
> .button
- background #ced2da
- border-color #ced2da
+ $color = isDark ? #15181d : #ced2da
+ background $color
+ border-color $color
> input
position absolute
@@ -147,14 +148,16 @@ export default Vue.extend({
border-radius 14px
> .button
+ $color = isDark ? #1c1f25 : #dcdfe6
+
display inline-block
margin 0
width 40px
min-width 40px
height 20px
min-height 20px
- background #dcdfe6
- border 1px solid #dcdfe6
+ background $color
+ border 1px solid $color
outline none
border-radius 10px
transition inherit
@@ -179,12 +182,18 @@ export default Vue.extend({
> span
display block
line-height 20px
- color #4a535a
+ color isDark ? #c4ccd2 : #4a535a
transition inherit
> p
margin 0
//font-size 90%
- color #9daab3
+ color isDark ? #78858e : #9daab3
+
+.mk-switch[data-darkmode]
+ root(true)
+
+.mk-switch:not([data-darkmode])
+ root(false)
</style>
diff --git a/src/client/app/common/views/components/twitter-setting.vue b/src/client/app/common/views/components/twitter-setting.vue
index 6ca1037aba..ab07e6d09a 100644
--- a/src/client/app/common/views/components/twitter-setting.vue
+++ b/src/client/app/common/views/components/twitter-setting.vue
@@ -50,8 +50,6 @@ export default Vue.extend({
<style lang="stylus" scoped>
.mk-twitter-setting
- color #4a535a
-
.account
border solid 1px #e1e8ed
border-radius 4px
diff --git a/src/client/app/common/views/components/url-preview.vue b/src/client/app/common/views/components/url-preview.vue
index fd25480f61..3bae6e5078 100644
--- a/src/client/app/common/views/components/url-preview.vue
+++ b/src/client/app/common/views/components/url-preview.vue
@@ -2,8 +2,8 @@
<iframe v-if="youtubeId" type="text/html" height="250"
:src="`https://www.youtube.com/embed/${youtubeId}?origin=${misskeyUrl}`"
frameborder="0"/>
-<div v-else>
- <a class="mk-url-preview" :href="url" target="_blank" :title="url" v-if="!fetching">
+<div v-else class="mk-url-preview">
+ <a :href="url" target="_blank" :title="url" v-if="!fetching">
<div class="thumbnail" v-if="thumbnail" :style="`background-image: url(${thumbnail})`"></div>
<article>
<header>
@@ -45,7 +45,7 @@ export default Vue.extend({
} else if (url.hostname == 'youtu.be') {
this.youtubeId = url.pathname;
} else {
- fetch('/url?url=' + this.url).then(res => {
+ fetch('/url?url=' + encodeURIComponent(this.url)).then(res => {
res.json().then(info => {
this.title = info.title;
this.description = info.description;
@@ -65,78 +65,85 @@ export default Vue.extend({
iframe
width 100%
-.mk-url-preview
- display block
- font-size 16px
- border solid 1px #eee
- border-radius 4px
- overflow hidden
+root(isDark)
+ > a
+ display block
+ font-size 16px
+ border solid 1px isDark ? #191b1f : #eee
+ border-radius 4px
+ overflow hidden
- &:hover
- text-decoration none
- border-color #ddd
+ &:hover
+ text-decoration none
+ border-color isDark ? #4f5561 : #ddd
- > article > header > h1
- text-decoration underline
+ > article > header > h1
+ text-decoration underline
- > .thumbnail
- position absolute
- width 100px
- height 100%
- background-position center
- background-size cover
+ > .thumbnail
+ position absolute
+ width 100px
+ height 100%
+ background-position center
+ background-size cover
+
+ & + article
+ left 100px
+ width calc(100% - 100px)
- & + article
- left 100px
- width calc(100% - 100px)
+ > article
+ padding 16px
- > article
- padding 16px
+ > header
+ margin-bottom 8px
- > header
- margin-bottom 8px
+ > h1
+ margin 0
+ font-size 1em
+ color isDark ? #d6dae0 : #555
- > h1
+ > p
margin 0
- font-size 1em
- color #555
+ color isDark ? #a4aab3 : #777
+ font-size 0.8em
- > p
- margin 0
- color #777
- font-size 0.8em
+ > footer
+ margin-top 8px
+ height 16px
- > footer
- margin-top 8px
- height 16px
+ > img
+ display inline-block
+ width 16px
+ height 16px
+ margin-right 4px
+ vertical-align top
- > img
- display inline-block
- width 16px
- height 16px
- margin-right 4px
- vertical-align top
+ > p
+ display inline-block
+ margin 0
+ color isDark ? #b0b4bf : #666
+ font-size 0.8em
+ line-height 16px
+ vertical-align top
- > p
- display inline-block
- margin 0
- color #666
- font-size 0.8em
- line-height 16px
- vertical-align top
+ @media (max-width 500px)
+ font-size 8px
+ border none
- @media (max-width 500px)
- font-size 8px
- border none
+ > .thumbnail
+ width 70px
- > .thumbnail
- width 70px
+ & + article
+ left 70px
+ width calc(100% - 70px)
- & + article
- left 70px
- width calc(100% - 70px)
+ > article
+ padding 8px
- > article
- padding 8px
+.mk-url-preview[data-darkmode]
+ root(true)
+
+.mk-url-preview:not([data-darkmode])
+ root(false)
</style>
diff --git a/src/client/app/common/views/components/visibility-chooser.vue b/src/client/app/common/views/components/visibility-chooser.vue
new file mode 100644
index 0000000000..50f0877ae9
--- /dev/null
+++ b/src/client/app/common/views/components/visibility-chooser.vue
@@ -0,0 +1,223 @@
+<template>
+<div class="mk-visibility-chooser">
+ <div class="backdrop" ref="backdrop" @click="close"></div>
+ <div class="popover" :class="{ compact }" ref="popover">
+ <div @click="choose('public')" :class="{ active: v == 'public' }">
+ <div>%fa:globe%</div>
+ <div>
+ <span>公開</span>
+ </div>
+ </div>
+ <div @click="choose('home')" :class="{ active: v == 'home' }">
+ <div>%fa:home%</div>
+ <div>
+ <span>ホーム</span>
+ <span>ホームタイムラインにのみ公開</span>
+ </div>
+ </div>
+ <div @click="choose('followers')" :class="{ active: v == 'followers' }">
+ <div>%fa:unlock%</div>
+ <div>
+ <span>フォロワー</span>
+ <span>自分のフォロワーにのみ公開</span>
+ </div>
+ </div>
+ <div @click="choose('specified')" :class="{ active: v == 'specified' }">
+ <div>%fa:envelope%</div>
+ <div>
+ <span>ダイレクト</span>
+ <span>指定したユーザーにのみ公開</span>
+ </div>
+ </div>
+ <div @click="choose('private')" :class="{ active: v == 'private' }">
+ <div>%fa:lock%</div>
+ <div>
+ <span>非公開</span>
+ </div>
+ </div>
+ </div>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import * as anime from 'animejs';
+
+export default Vue.extend({
+ props: ['source', 'compact', 'v'],
+ mounted() {
+ this.$nextTick(() => {
+ const popover = this.$refs.popover as any;
+
+ const rect = this.source.getBoundingClientRect();
+ const width = popover.offsetWidth;
+ const height = popover.offsetHeight;
+
+ let left;
+ let top;
+
+ if (this.compact) {
+ const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
+ const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2);
+ left = (x - (width / 2));
+ top = (y - (height / 2));
+ } else {
+ const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2);
+ const y = rect.top + window.pageYOffset + this.source.offsetHeight;
+ left = (x - (width / 2));
+ top = y;
+ }
+
+ if (left + width > window.innerWidth) {
+ left = window.innerWidth - width;
+ }
+
+ popover.style.left = left + 'px';
+ popover.style.top = top + 'px';
+
+ anime({
+ targets: this.$refs.backdrop,
+ opacity: 1,
+ duration: 100,
+ easing: 'linear'
+ });
+
+ anime({
+ targets: this.$refs.popover,
+ opacity: 1,
+ scale: [0.5, 1],
+ duration: 500
+ });
+ });
+ },
+ methods: {
+ choose(visibility) {
+ this.$emit('chosen', visibility);
+ this.$destroy();
+ },
+ close() {
+ (this.$refs.backdrop as any).style.pointerEvents = 'none';
+ anime({
+ targets: this.$refs.backdrop,
+ opacity: 0,
+ duration: 200,
+ easing: 'linear'
+ });
+
+ (this.$refs.popover as any).style.pointerEvents = 'none';
+ anime({
+ targets: this.$refs.popover,
+ opacity: 0,
+ scale: 0.5,
+ duration: 200,
+ easing: 'easeInBack',
+ complete: () => this.$destroy()
+ });
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+@import '~const.styl'
+
+$border-color = rgba(27, 31, 35, 0.15)
+
+root(isDark)
+ position initial
+
+ > .backdrop
+ position fixed
+ top 0
+ left 0
+ z-index 10000
+ width 100%
+ height 100%
+ background isDark ? rgba(#000, 0.4) : rgba(#000, 0.1)
+ opacity 0
+
+ > .popover
+ $bgcolor = isDark ? #2c303c : #fff
+ position absolute
+ z-index 10001
+ width 240px
+ padding 8px 0
+ background $bgcolor
+ border 1px solid $border-color
+ border-radius 4px
+ box-shadow 0 3px 12px rgba(27, 31, 35, 0.15)
+ transform scale(0.5)
+ opacity 0
+
+ $balloon-size = 10px
+
+ &:not(.compact)
+ margin-top $balloon-size
+ transform-origin center -($balloon-size)
+
+ &:before
+ content ""
+ display block
+ position absolute
+ top -($balloon-size * 2)
+ left s('calc(50% - %s)', $balloon-size)
+ border-top solid $balloon-size transparent
+ border-left solid $balloon-size transparent
+ border-right solid $balloon-size transparent
+ border-bottom solid $balloon-size $border-color
+
+ &:after
+ content ""
+ display block
+ position absolute
+ top -($balloon-size * 2) + 1.5px
+ left s('calc(50% - %s)', $balloon-size)
+ border-top solid $balloon-size transparent
+ border-left solid $balloon-size transparent
+ border-right solid $balloon-size transparent
+ border-bottom solid $balloon-size $bgcolor
+
+ > div
+ display flex
+ padding 8px 14px
+ font-size 12px
+ color isDark ? #fff : #666
+ cursor pointer
+
+ &:hover
+ background isDark ? #252731 : #eee
+
+ &:active
+ background isDark ? #21242b : #ddd
+
+ &.active
+ color $theme-color-foreground
+ background $theme-color
+
+ > *
+ user-select none
+ pointer-events none
+
+ > *:first-child
+ display flex
+ justify-content center
+ align-items center
+ margin-right 10px
+
+ > *:last-child
+ flex 1 1 auto
+
+ > span:first-child
+ display block
+ font-weight bold
+
+ > span:last-child:not(:first-child)
+ opacity 0.6
+
+.mk-visibility-chooser[data-darkmode]
+ root(true)
+
+.mk-visibility-chooser:not([data-darkmode])
+ root(false)
+
+</style>
diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue
index a80bc04f7f..6fadb030c3 100644
--- a/src/client/app/common/views/components/welcome-timeline.vue
+++ b/src/client/app/common/views/components/welcome-timeline.vue
@@ -1,9 +1,7 @@
<template>
<div class="mk-welcome-timeline">
<div v-for="note in notes">
- <router-link class="avatar-anchor" :to="note.user | userPage" v-user-preview="note.user.id">
- <img class="avatar" :src="`${note.user.avatarUrl}?thumbnail&size=96`" alt="avatar"/>
- </router-link>
+ <mk-avatar class="avatar" :user="note.user" target="_blank"/>
<div class="body">
<header>
<router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link>
@@ -62,25 +60,22 @@ export default Vue.extend({
overflow-wrap break-word
font-size .9em
color #4C4C4C
- border-bottom 1px solid rgba(0, 0, 0, 0.05)
+ border-bottom 1px solid rgba(#000, 0.05)
&:after
content ""
display block
clear both
- > .avatar-anchor
+ > .avatar
display block
float left
position -webkit-sticky
position sticky
top 16px
-
- > img
- display block
- width 42px
- height 42px
- border-radius 6px
+ width 42px
+ height 42px
+ border-radius 6px
> .body
float right