Compare commits

...

28 Commits

Author SHA1 Message Date
syuilo
b6dc6c6984 10.90.4 2019-02-28 15:57:02 +09:00
syuilo
517084b1fc Fix error 2019-02-28 14:17:39 +09:00
syuilo
27763e6898 🎨 2019-02-28 14:14:05 +09:00
syuilo
57dde1da38 Fix error 2019-02-28 14:13:18 +09:00
syuilo
0bb961767c Fix i18n 2019-02-28 14:10:56 +09:00
syuilo
88515ce677 Use internal dialog 2019-02-28 14:07:03 +09:00
syuilo
00562e840c Improve usability 2019-02-28 12:53:31 +09:00
syuilo
b7927ba386 Refactor 2019-02-28 12:49:13 +09:00
syuilo
9c363ff045 Improve usability 2019-02-28 12:29:04 +09:00
syuilo
1dbce5e3e2 Improve performance 2019-02-28 12:14:24 +09:00
syuilo
361a9ca1be url-previewでembedプレイヤー展開をオプトインにする (#4382)
* url-previewでembedプレイヤー展開をオプトインにする

* remove tabs
2019-02-28 12:05:47 +09:00
syuilo
cde6514839 Add log 2019-02-28 12:00:57 +09:00
syuilo
507e2f727e 読み込む通知数を増やした 2019-02-28 11:44:16 +09:00
syuilo
8028499d2b 🎨 2019-02-28 11:42:41 +09:00
syuilo
c2c79c4a87 [Client] Use class selector to improve performance 2019-02-28 11:39:34 +09:00
mei23
d56f7f3390 remove tabs 2019-02-28 03:57:35 +09:00
mei23
ef70d17194 url-previewでembedプレイヤー展開をオプトインにする 2019-02-28 03:46:37 +09:00
syuilo
9789b9a083 🎨 2019-02-27 16:47:13 +09:00
syuilo
e6311fdb13 🎨 2019-02-27 09:27:19 +09:00
syuilo
2231c54dee 10.90.3 2019-02-27 05:33:05 +09:00
syuilo
20de9a5e35 Resolve #4374 2019-02-27 05:31:16 +09:00
syuilo
ec3a6d7097 🎨 2019-02-27 05:20:29 +09:00
syuilo
9d99bf5af8 🎨 2019-02-27 05:16:32 +09:00
syuilo
52911cc9fd 🎨 2019-02-27 05:13:11 +09:00
syuilo
6f71ba376d Improve doc 2019-02-27 05:08:42 +09:00
syuilo
9f439aabba Fix schema 2019-02-27 05:02:46 +09:00
syuilo
33ad60b1f3 Improve doc 2019-02-27 05:02:36 +09:00
Big Buddha
010d3f8281 Update translations of CONTRIBUTING.md (#4371)
* Update translationa about Nyaize

* Update translation about description of source code

* Fix translation
2019-02-26 18:00:47 +09:00
45 changed files with 378 additions and 432 deletions

View File

@@ -1,6 +1,19 @@
ChangeLog ChangeLog
========= =========
10.90.4
----------
* url-previewでembedプレイヤー展開をオプトインにするように
* デザインの調整
* ユーザビリティの強化
10.90.3
----------
* モバイルのデッキで投稿フォームウィジェットが設置できなかった問題を修正
* ドキュメントの強化
* デザインの調整
* ユーザビリティの強化
10.90.2 10.90.2
---------- ----------
* アカウントが削除できない問題を修正 * アカウントが削除できない問題を修正

View File

@@ -40,10 +40,10 @@ Stands for _**M**iss**k**ey_.
Stands for _**S**ervice**W**orker_. Stands for _**S**ervice**W**orker_.
### Nyaize ### Nyaize
な を にゃ にすること Convert な(na) to にゃ(nya)
#### Denyaize #### Denyaize
Nyaizeを解除すること Revert Nyaize
## Code style ## Code style
### Don't use `export default` ### Don't use `export default`
@@ -59,16 +59,16 @@ export function something(foo: string): string {
## Directory structure ## Directory structure
``` ```
src ... ソースコード src ... Source code
@types ... 外部ライブラリなどの型定義 @types ... Type definitions
prelude ... Misskeyに関係ないかつ副作用なし prelude ... Independence utils for coding JavaScript without side effects
misc ... 副作用なしのユーティリティ処理 misc ... Independence utils for Misskey without side effects
service ... 副作用ありの共通処理 service ... Common functions with side effects
queue ... ジョブキューとジョブ queue ... Job queues and Jobs
server ... Webサーバー server ... Web Server
client ... クライアント client ... Client
mfm ... MFM mfm ... MFM
test ... テスト test ... Test code
``` ```

View File

@@ -38,6 +38,7 @@ common:
signin: "ログイン" signin: "ログイン"
signup: "新規登録" signup: "新規登録"
signout: "ログアウト" signout: "ログアウト"
reload-to-apply-the-setting: "この設定を反映するにはページをリロードする必要があります。今すぐリロードしますか?"
got-it: "わかった" got-it: "わかった"
customization-tips: customization-tips:
@@ -257,6 +258,9 @@ common/views/pages/explore.vue:
explore: "{host}を探索" explore: "{host}を探索"
users-info: "現在{users}ユーザーが登録されています" users-info: "現在{users}ユーザーが登録されています"
common/views/components/url-preview.vue:
enable-player: "プレイヤーを開く"
common/views/components/user-list.vue: common/views/components/user-list.vue:
no-users: "ユーザーがいません" no-users: "ユーザーがいません"

View File

@@ -1,7 +1,7 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <i@syuilo.com>", "author": "syuilo <i@syuilo.com>",
"version": "10.90.2", "version": "10.90.4",
"codename": "nighthike", "codename": "nighthike",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -1,5 +1,5 @@
export default function(me, settings, note) { export default function(me, settings, note) {
const isMyNote = note.userId == me.id; const isMyNote = me && (note.userId == me.id);
const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null; const isPureRenote = note.renoteId != null && note.text == null && note.fileIds.length == 0 && note.poll == null;
const includesMutedWords = (text: string) => const includesMutedWords = (text: string) =>

View File

@@ -1,5 +1,5 @@
<template> <template>
<span class="mk-acct"> <span class="mk-acct" v-once>
<span class="name">@{{ user.username }}</span> <span class="name">@{{ user.username }}</span>
<span class="host" :class="{ fade: $store.state.settings.contrastedAcct }" v-if="user.host || detail || $store.state.settings.showFullAcct">@{{ user.host || host }}</span> <span class="host" :class="{ fade: $store.state.settings.contrastedAcct }" v-if="user.host || detail || $store.state.settings.showFullAcct">@{{ user.host || host }}</span>
<fa v-if="user.isLocked == true" class="locked" icon="lock" fixed-width/> <fa v-if="user.isLocked == true" class="locked" icon="lock" fixed-width/>

View File

@@ -1,14 +1,14 @@
<template> <template>
<span class="mk-avatar" :style="style" :class="{ cat }" :title="user | acct" v-if="disableLink && !disablePreview" v-user-preview="user.id" @click="onClick"> <span class="mk-avatar" :style="style" :class="{ cat }" :title="user | acct" v-if="disableLink && !disablePreview" v-user-preview="user.id" @click="onClick" v-once>
<span class="inner" :style="icon"></span> <span class="inner" :style="icon"></span>
</span> </span>
<span class="mk-avatar" :style="style" :class="{ cat }" :title="user | acct" v-else-if="disableLink && disablePreview" @click="onClick"> <span class="mk-avatar" :style="style" :class="{ cat }" :title="user | acct" v-else-if="disableLink && disablePreview" @click="onClick" v-once>
<span class="inner" :style="icon"></span> <span class="inner" :style="icon"></span>
</span> </span>
<router-link class="mk-avatar" :style="style" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && !disablePreview" v-user-preview="user.id"> <router-link class="mk-avatar" :style="style" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && !disablePreview" v-user-preview="user.id" v-once>
<span class="inner" :style="icon"></span> <span class="inner" :style="icon"></span>
</router-link> </router-link>
<router-link class="mk-avatar" :style="style" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && disablePreview"> <router-link class="mk-avatar" :style="style" :class="{ cat }" :to="user | userPage" :title="user | acct" :target="target" v-else-if="!disableLink && disablePreview" v-once>
<span class="inner" :style="icon"></span> <span class="inner" :style="icon"></span>
</router-link> </router-link>
</template> </template>

View File

@@ -80,7 +80,7 @@ export default Vue.extend({
> div > div
background-color var(--text) background-color var(--text)
border-radius var(--round) border-radius 6px
color var(--secondary) color var(--secondary)
display inline-block display inline-block
font-size 14px font-size 14px

View File

@@ -1,5 +1,5 @@
<template> <template>
<mfm-core v-bind="$attrs" class="havbbuyv"/> <mfm-core v-bind="$attrs" class="havbbuyv" v-once/>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="ui-card" :class="{ shadow: $store.state.device.useShadow }"> <div class="ui-card" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<header> <header>
<slot name="title"></slot> <slot name="title"></slot>
</header> </header>
@@ -25,7 +25,9 @@ export default Vue.extend({
max-width 850px max-width 850px
color var(--faceText) color var(--faceText)
background var(--face) background var(--face)
border-radius var(--round)
&.round
border-radius 6px
&.shadow &.shadow
box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12) box-shadow 0 3px 1px -2px rgba(#000, 0.2), 0 2px 2px 0 rgba(#000, 0.14), 0 1px 5px 0 rgba(#000, 0.12)

View File

@@ -1,6 +1,6 @@
<template> <template>
<div v-if="player.url" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`"> <div v-if="playerEnabled" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`">
<iframe :src="player.url" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen /> <iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
</div> </div>
<div v-else-if="tweetUrl && detail" class="twitter"> <div v-else-if="tweetUrl && detail" class="twitter">
<blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null"> <blockquote ref="tweet" class="twitter-tweet" :data-theme="$store.state.device.darkmode ? 'dark' : null">
@@ -9,7 +9,9 @@
</div> </div>
<div v-else class="mk-url-preview"> <div v-else class="mk-url-preview">
<a :class="{ mini: narrow, compact }" :href="url" target="_blank" :title="url" v-if="!fetching"> <a :class="{ mini: narrow, compact }" :href="url" target="_blank" :title="url" v-if="!fetching">
<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`"></div> <div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
<button v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$t('enable-player')"><fa :icon="['far', 'play-circle']"/></button>
</div>
<article> <article>
<header> <header>
<h1 :title="title">{{ title }}</h1> <h1 :title="title">{{ title }}</h1>
@@ -26,88 +28,11 @@
<script lang="ts"> <script lang="ts">
import Vue from 'vue'; import Vue from 'vue';
import i18n from '../../../i18n';
import { url as misskeyUrl } from '../../../config'; import { url as misskeyUrl } from '../../../config';
// THIS IS THE WHITELIST FOR THE EMBED PLAYER
const whiteList = [
'afreecatv.com',
'aparat.com',
'applemusic.com',
'amazon.com',
'awa.fm',
'bandcamp.com',
'bbc.co.uk',
'beatport.com',
'bilibili.com',
'boomstream.com',
'breakers.tv',
'cam4.com',
'cavelis.net',
'chaturbate.com',
'cnn.com',
'cybergame.tv',
'dailymotion.com',
'deezer.com',
'djlive.pl',
'e-onkyo.com',
'eventials.com',
'facebook.com',
'fc2.com',
'gameplank.tv',
'goodgame.ru',
'google.com',
'hardtunes.com',
'instagram.com',
'johnnylooch.com',
'kexp.org',
'lahzenegar.com',
'liveedu.tv',
'livetube.cc',
'livestream.com',
'meridix.com',
'mixcloud.com',
'mixer.com',
'mobcrush.com',
'mylive.in.th',
'myspace.com',
'netflix.com',
'newretrowave.com',
'nhk.or.jp',
'nicovideo.jp',
'nico.ms',
'noisetrade.com',
'nood.tv',
'npr.org',
'openrec.tv',
'pandora.com',
'pandora.tv',
'picarto.tv',
'pscp.tv',
'restream.io',
'reverbnation.com',
'sermonaudio.com',
'smashcast.tv',
'songkick.com',
'soundcloud.com',
'spinninrecords.com',
'spotify.com',
'stitcher.com',
'stream.me',
'switchboard.live',
'tunein.com',
'twitcasting.tv',
'twitch.tv',
'twitter.com',
'vaughnlive.tv',
'veoh.com',
'vimeo.com',
'watchpeoplecode.com',
'web.tv',
'youtube.com',
'youtu.be'
];
export default Vue.extend({ export default Vue.extend({
i18n: i18n('common/views/components/url-preview.vue'),
props: { props: {
url: { url: {
type: String, type: String,
@@ -147,7 +72,8 @@ export default Vue.extend({
height: null height: null
}, },
tweetUrl: null, tweetUrl: null,
misskeyUrl playerEnabled: false,
misskeyUrl,
}; };
}, },
@@ -188,9 +114,7 @@ export default Vue.extend({
this.icon = info.icon; this.icon = info.icon;
this.sitename = info.sitename; this.sitename = info.sitename;
this.fetching = false; this.fetching = false;
if (whiteList.some(x => x == url.hostname || url.hostname.endsWith(`.${x}`))) { this.player = info.player;
this.player = info.player;
}
}) })
}); });
} }
@@ -230,6 +154,17 @@ export default Vue.extend({
height 100% height 100%
background-position center background-position center
background-size cover background-size cover
display flex
justify-content center
align-items center
> button
font-size 3.5em
opacity: 0.7
&:hover
font-size 4em
opacity 0.9
& + article & + article
left 100px left 100px

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready }" <div class="dnpfarvgbnfmyzbdquhhzyxcmstpdqzs" :class="{ naked, narrow, active, isStacked, draghover, dragging, dropready, isMobile: $root.isMobile, shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }"
@dragover.prevent.stop="onDragover" @dragover.prevent.stop="onDragover"
@dragleave="onDragleave" @dragleave="onDragleave"
@drop.prevent.stop="onDrop" @drop.prevent.stop="onDrop"
@@ -322,10 +322,14 @@ export default Vue.extend({
height 100% height 100%
background var(--face) background var(--face)
border-radius var(--round)
box-shadow var(--shadow)
overflow hidden overflow hidden
&.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
&.draghover &.draghover
box-shadow 0 0 0 2px var(--primaryAlpha08) box-shadow 0 0 0 2px var(--primaryAlpha08)
@@ -366,6 +370,10 @@ export default Vue.extend({
> button > button
color var(--text) color var(--text)
&.isMobile
> header
box-shadow none
> header > header
display flex display flex
z-index 2 z-index 2

View File

@@ -14,6 +14,7 @@ import wTips from './tips.vue';
import wNav from './nav.vue'; import wNav from './nav.vue';
import wHashtags from './hashtags.vue'; import wHashtags from './hashtags.vue';
import wInstance from './instance.vue'; import wInstance from './instance.vue';
import wPostForm from './post-form.vue';
Vue.component('mkw-analog-clock', wAnalogClock); Vue.component('mkw-analog-clock', wAnalogClock);
Vue.component('mkw-nav', wNav); Vue.component('mkw-nav', wNav);
@@ -29,3 +30,4 @@ Vue.component('mkw-rss', wRss);
Vue.component('mkw-version', wVersion); Vue.component('mkw-version', wVersion);
Vue.component('mkw-hashtags', wHashtags); Vue.component('mkw-hashtags', wHashtags);
Vue.component('mkw-instance', wInstance); Vue.component('mkw-instance', wInstance);
Vue.component('mkw-post-form', wPostForm);

View File

@@ -17,7 +17,7 @@
ref="text" ref="text"
v-autocomplete="{ model: 'text' }" v-autocomplete="{ model: 'text' }"
></textarea> ></textarea>
<button class="emoji" @click="emoji" ref="emoji"> <button class="emoji" @click="emoji" ref="emoji" v-if="!$root.isMobile">
<fa :icon="['far', 'laugh']"/> <fa :icon="['far', 'laugh']"/>
</button> </button>
</div> </div>
@@ -161,7 +161,7 @@ export default define({
}, },
async emoji() { async emoji() {
const Picker = await import('../components/emoji-picker-dialog.vue').then(m => m.default); const Picker = await import('../../../desktop/views/components/emoji-picker-dialog.vue').then(m => m.default);
const button = this.$refs.emoji; const button = this.$refs.emoji;
const rect = button.getBoundingClientRect(); const rect = button.getBoundingClientRect();
const vm = this.$root.new(Picker, { const vm = this.$root.new(Picker, {
@@ -186,6 +186,9 @@ export default define({
alert('Something happened'); alert('Something happened');
}).then(() => { }).then(() => {
this.posting = false; this.posting = false;
this.$nextTick(() => {
this.$refs.text.focus();
});
}); });
}, },

View File

@@ -7,7 +7,7 @@
<div class="mkw-rss--body" :data-mobile="platform == 'mobile'"> <div class="mkw-rss--body" :data-mobile="platform == 'mobile'">
<p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p> <p class="fetching" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('@.loading') }}<mk-ellipsis/></p>
<div class="feed" v-else> <div class="feed" v-else>
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a> <a v-for="item in items" :href="item.link" target="_blank" :title="item.title">{{ item.title }}</a>
</div> </div>
</div> </div>
</ui-container> </ui-container>
@@ -55,12 +55,18 @@ export default define({
}); });
}, },
setting() { setting() {
const url = window.prompt('URL', this.props.url); this.$root.dialog({
if (url && url != '') { title: 'URL',
input: {
type: 'url',
default: this.props.url
}
}).then(({ canceled, result: url }) => {
if (canceled) return;
this.props.url = url; this.props.url = url;
this.save(); this.save();
this.fetch(); this.fetch();
} });
} }
} }
}); });

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="mk-calendar" :data-melt="design == 4 || design == 5"> <div class="mk-calendar" :data-melt="design == 4 || design == 5" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<template v-if="design == 0 || design == 1"> <template v-if="design == 0 || design == 1">
<button @click="prev" :title="$t('prev')"><fa icon="chevron-circle-left"/></button> <button @click="prev" :title="$t('prev')"><fa icon="chevron-circle-left"/></button>
<p class="title">{{ $t('title', { year, month }) }}</p> <p class="title">{{ $t('title', { year, month }) }}</p>
@@ -133,10 +133,14 @@ export default Vue.extend({
.mk-calendar .mk-calendar
color var(--calendarDay) color var(--calendarDay)
background var(--face) background var(--face)
box-shadow var(--shadow)
border-radius var(--round)
overflow hidden overflow hidden
&.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
&[data-melt] &[data-melt]
background transparent !important background transparent !important
border none !important border none !important

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="mk-note-detail" :title="title" tabindex="-1"> <div class="mk-note-detail" :title="title" tabindex="-1" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<button <button
class="read-more" class="read-more"
v-if="appearNote.reply && appearNote.reply.replyId && conversation.length == 0" v-if="appearNote.reply && appearNote.reply.replyId && conversation.length == 0"
@@ -159,8 +159,15 @@ export default Vue.extend({
overflow hidden overflow hidden
text-align left text-align left
background var(--face) background var(--face)
box-shadow var(--shadow)
border-radius var(--round) &.round
border-radius 6px
> .read-more
border-radius 6px 6px 0 0
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
> .read-more > .read-more
display block display block
@@ -175,7 +182,6 @@ export default Vue.extend({
outline none outline none
border none border none
border-bottom solid 1px var(--faceDivider) border-bottom solid 1px var(--faceDivider)
border-radius var(--round) var(--round) 0 0
&:hover &:hover
box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05) box-shadow 0 0 0 100px inset rgba(0, 0, 0, 0.05)

View File

@@ -39,30 +39,30 @@
<mk-url-preview v-for="url in urls" :url="url" :key="url" :compact="compact"/> <mk-url-preview v-for="url in urls" :url="url" :key="url" :compact="compact"/>
</div> </div>
</div> </div>
<footer v-if="appearNote.deletedAt == null"> <footer v-if="appearNote.deletedAt == null" class="footer">
<span class="app" v-if="appearNote.app && narrow && $store.state.settings.showVia">via <b>{{ appearNote.app.name }}</b></span> <span class="app" v-if="appearNote.app && narrow && $store.state.settings.showVia">via <b>{{ appearNote.app.name }}</b></span>
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/> <mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
<button class="replyButton" @click="reply()" :title="$t('reply')"> <button class="replyButton button" @click="reply()" :title="$t('reply')">
<template v-if="appearNote.reply"><fa icon="reply-all"/></template> <template v-if="appearNote.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template> <template v-else><fa icon="reply"/></template>
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p> <p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
</button> </button>
<button v-if="['public', 'home'].includes(appearNote.visibility)" class="renoteButton" @click="renote()" :title="$t('renote')"> <button v-if="['public', 'home'].includes(appearNote.visibility)" class="renoteButton button" @click="renote()" :title="$t('renote')">
<fa icon="retweet"/> <fa icon="retweet"/>
<p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p> <p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
</button> </button>
<button v-else class="inhibitedButton"> <button v-else class="inhibitedButton button">
<fa icon="ban"/> <fa icon="ban"/>
</button> </button>
<button v-if="!isMyNote && appearNote.myReaction == null" class="reactionButton" @click="react()" ref="reactButton" :title="$t('add-reaction')"> <button v-if="!isMyNote && appearNote.myReaction == null" class="reactionButton button" @click="react()" ref="reactButton" :title="$t('add-reaction')">
<fa icon="plus"/> <fa icon="plus"/>
<p class="count" v-if="Object.values(appearNote.reactionCounts).some(x => x)">{{ Object.values(appearNote.reactionCounts).reduce((a, c) => a + c, 0) }}</p> <p class="count" v-if="Object.values(appearNote.reactionCounts).some(x => x)">{{ Object.values(appearNote.reactionCounts).reduce((a, c) => a + c, 0) }}</p>
</button> </button>
<button v-if="!isMyNote && appearNote.myReaction != null" class="reactionButton reacted" @click="undoReact(appearNote)" ref="reactButton" :title="$t('undo-reaction')"> <button v-if="!isMyNote && appearNote.myReaction != null" class="reactionButton reacted button" @click="undoReact(appearNote)" ref="reactButton" :title="$t('undo-reaction')">
<fa icon="minus"/> <fa icon="minus"/>
<p class="count" v-if="Object.values(appearNote.reactionCounts).some(x => x)">{{ Object.values(appearNote.reactionCounts).reduce((a, c) => a + c, 0) }}</p> <p class="count" v-if="Object.values(appearNote.reactionCounts).some(x => x)">{{ Object.values(appearNote.reactionCounts).reduce((a, c) => a + c, 0) }}</p>
</button> </button>
<button @click="menu()" ref="menuButton"> <button @click="menu()" ref="menuButton" class="button">
<fa icon="ellipsis-h"/> <fa icon="ellipsis-h"/>
</button> </button>
</footer> </footer>
@@ -274,7 +274,7 @@ export default Vue.extend({
border dashed var(--lineWidth) var(--quoteBorder) border dashed var(--lineWidth) var(--quoteBorder)
border-radius 8px border-radius 8px
> footer > .footer
> .app > .app
display block display block
margin-top 0.5em margin-top 0.5em
@@ -282,7 +282,7 @@ export default Vue.extend({
color var(--noteHeaderInfo) color var(--noteHeaderInfo)
font-size 0.8em font-size 0.8em
> button > .button
margin 0 28px 0 0 margin 0 28px 0 0
padding 0 8px padding 0 8px
line-height 32px line-height 32px

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="mk-notes"> <div class="mk-notes" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<slot name="header"></slot> <slot name="header"></slot>
<div class="newer-indicator" :style="{ top: $store.state.uiHeaderHeight + 'px' }" v-show="queue.length > 0"></div> <div class="newer-indicator" :style="{ top: $store.state.uiHeaderHeight + 'px' }" v-show="queue.length > 0"></div>
@@ -191,10 +191,14 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.mk-notes .mk-notes
background var(--face) background var(--face)
box-shadow var(--shadow)
border-radius var(--round)
overflow hidden overflow hidden
&.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
.transition .transition
.mk-notes-enter .mk-notes-enter
.mk-notes-leave-to .mk-notes-leave-to

View File

@@ -463,17 +463,26 @@ export default Vue.extend({
circleIcons: { circleIcons: {
get() { return this.$store.state.settings.circleIcons; }, get() { return this.$store.state.settings.circleIcons; },
set(value) { this.$store.dispatch('settings/set', { key: 'circleIcons', value }); } set(value) {
this.$store.dispatch('settings/set', { key: 'circleIcons', value });
this.reload();
}
}, },
contrastedAcct: { contrastedAcct: {
get() { return this.$store.state.settings.contrastedAcct; }, get() { return this.$store.state.settings.contrastedAcct; },
set(value) { this.$store.dispatch('settings/set', { key: 'contrastedAcct', value }); } set(value) {
this.$store.dispatch('settings/set', { key: 'contrastedAcct', value });
this.reload();
}
}, },
showFullAcct: { showFullAcct: {
get() { return this.$store.state.settings.showFullAcct; }, get() { return this.$store.state.settings.showFullAcct; },
set(value) { this.$store.dispatch('settings/set', { key: 'showFullAcct', value }); } set(value) {
this.$store.dispatch('settings/set', { key: 'showFullAcct', value });
this.reload();
}
}, },
showVia: { showVia: {
@@ -517,6 +526,17 @@ export default Vue.extend({
}); });
}, },
methods: { methods: {
reload() {
this.$root.dialog({
type: 'warning',
text: this.$t('@.reload-to-apply-the-setting'),
showCancelButton: true
}).then(({ canceled }) => {
if (!canceled) {
location.reload();
}
});
},
customizeHome() { customizeHome() {
location.href = '/?customize'; location.href = '/?customize';
}, },
@@ -583,9 +603,6 @@ export default Vue.extend({
z-index 1 z-index 1
font-size 15px font-size 15px
&.inWindow
box-shadow var(--shadowRight)
> p > p
display block display block
padding 10px 16px padding 10px 16px

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="kedshtep" :class="{ naked, inNakedDeckColumn }"> <div class="kedshtep" :class="{ naked, inNakedDeckColumn, shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<header v-if="showHeader"> <header v-if="showHeader">
<div class="title"><slot name="header"></slot></div> <div class="title"><slot name="header"></slot></div>
<slot name="func"></slot> <slot name="func"></slot>
@@ -60,8 +60,12 @@ export default Vue.extend({
&:not(.inNakedDeckColumn) &:not(.inNakedDeckColumn)
background var(--face) background var(--face)
box-shadow var(--shadow)
border-radius var(--round) &.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
& + .kedshtep & + .kedshtep
margin-top 16px margin-top 16px

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="header" :class="navbar"> <div class="header" :class="navbar" :data-shadow="$store.state.device.useShadow">
<div class="body"> <div class="body">
<div class="post"> <div class="post">
<button @click="post" :title="$t('title')"><fa icon="pencil-alt"/></button> <button @click="post" :title="$t('title')"><fa icon="pencil-alt"/></button>
@@ -62,7 +62,7 @@
</div> </div>
<transition :name="`slide-${navbar}`"> <transition :name="`slide-${navbar}`">
<div class="notifications" v-if="showNotifications" ref="notifications" :class="navbar"> <div class="notifications" v-if="showNotifications" ref="notifications" :class="navbar" :data-shadow="$store.state.device.useShadow">
<mk-notifications/> <mk-notifications/>
</div> </div>
</transition> </transition>
@@ -226,11 +226,15 @@ export default Vue.extend({
&.left &.left
left 0 left 0
box-shadow var(--shadowRight)
&[data-shadow]
box-shadow 4px 0 4px rgba(0, 0, 0, 0.1)
&.right &.right
right 0 right 0
box-shadow var(--shadowLeft)
&[data-shadow]
box-shadow -4px 0 4px rgba(0, 0, 0, 0.1)
> .body > .body
position fixed position fixed
@@ -302,11 +306,15 @@ export default Vue.extend({
&.left &.left
left $width left $width
box-shadow var(--shadowRight)
&[data-shadow]
box-shadow 4px 0 4px rgba(0, 0, 0, 0.1)
&.right &.right
right $width right $width
box-shadow var(--shadowLeft)
&[data-shadow]
box-shadow -4px 0 4px rgba(0, 0, 0, 0.1)
.nav .nav
> * > *

View File

@@ -22,7 +22,7 @@
<option value="users">{{ $t('@.widgets.users') }}</option> <option value="users">{{ $t('@.widgets.users') }}</option>
<option value="polls">{{ $t('@.widgets.polls') }}</option> <option value="polls">{{ $t('@.widgets.polls') }}</option>
<option value="post-form">{{ $t('@.widgets.post-form') }}</option> <option value="post-form">{{ $t('@.widgets.post-form') }}</option>
<option value="messaging">{{ $t('@.widgets.messaging') }}</option> <option value="messaging">{{ $t('@.messaging') }}</option>
<option value="memo">{{ $t('@.widgets.memo') }}</option> <option value="memo">{{ $t('@.widgets.memo') }}</option>
<option value="hashtags">{{ $t('@.widgets.hashtags') }}</option> <option value="hashtags">{{ $t('@.widgets.hashtags') }}</option>
<option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option> <option value="posts-monitor">{{ $t('@.widgets.posts-monitor') }}</option>
@@ -109,6 +109,10 @@ export default Vue.extend({
name: 'broadcast', name: 'broadcast',
place: 'right', place: 'right',
data: {} data: {}
}, {
name: 'hashtags',
place: 'right',
data: {}
}]; }];
} }
}, },

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="pwbzawku"> <div class="pwbzawku">
<mk-post-form class="form" v-if="$store.state.settings.showPostFormOnTopOfTl"/> <mk-post-form class="form" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }" v-if="$store.state.settings.showPostFormOnTopOfTl"/>
<div class="main"> <div class="main">
<component :is="src == 'list' ? 'mk-user-list-timeline' : 'x-core'" ref="tl" v-bind="options"> <component :is="src == 'list' ? 'mk-user-list-timeline' : 'x-core'" ref="tl" v-bind="options">
<header class="zahtxcqi"> <header class="zahtxcqi">
@@ -193,8 +193,12 @@ export default Vue.extend({
.pwbzawku .pwbzawku
> .form > .form
margin-bottom 16px margin-bottom 16px
box-shadow var(--shadow)
border-radius var(--round) &.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
.zahtxcqi .zahtxcqi
padding 0 8px padding 0 8px

View File

@@ -1,7 +1,11 @@
<template> <template>
<div class="omechnps" v-if="!fetching"> <div class="omechnps" v-if="!fetching">
<div class="is-suspended" v-if="user.isSuspended"><fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}</div> <div class="is-suspended" v-if="user.isSuspended" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<div class="is-remote" v-if="user.host != null"><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a></div> <fa icon="exclamation-triangle"/> {{ $t('@.user-suspended') }}
</div>
<div class="is-remote" v-if="user.host != null" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a>
</div>
<div class="main"> <div class="main">
<x-header class="header" :user="user"/> <x-header class="header" :user="user"/>
<router-view :user="user"></router-view> <router-view :user="user"></router-view>
@@ -61,8 +65,12 @@ export default Vue.extend({
margin-bottom 16px margin-bottom 16px
padding 14px 16px padding 14px 16px
font-size 14px font-size 14px
box-shadow var(--shadow)
border-radius var(--round) &.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
&.is-suspended &.is-suspended
color var(--suspendedInfoFg) color var(--suspendedInfoFg)

View File

@@ -1,84 +0,0 @@
<template>
<div class="vahgrswmbzfdlmomxnqftuueyvwaafth">
<p class="title"><fa icon="users"/>{{ $t('title') }}</p>
<p class="initializing" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('loading') }}<mk-ellipsis/></p>
<div v-if="!fetching && users.length > 0">
<router-link v-for="user in users" :to="user | userPage" :key="user.id">
<img :src="user.avatarUrl" :alt="user | userName" v-user-preview="user.id"/>
</router-link>
</div>
<p class="empty" v-if="!fetching && users.length == 0">{{ $t('no-users') }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
export default Vue.extend({
i18n: i18n('desktop/views/pages/user/user.followers-you-know.vue'),
props: ['user'],
data() {
return {
users: [],
fetching: true
};
},
mounted() {
this.$root.api('users/followers', {
userId: this.user.id,
iknow: true,
limit: 16
}).then(x => {
this.users = x.users;
this.fetching = false;
});
}
});
</script>
<style lang="stylus" scoped>
.vahgrswmbzfdlmomxnqftuueyvwaafth
background var(--face)
box-shadow var(--shadow)
border-radius var(--round)
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
color var(--faceHeaderText)
box-shadow 0 1px rgba(#000, 0.07)
> i
margin-right 4px
> div
padding 8px
> a
display inline-block
margin 4px
> img
display inline-block
text-align center
width 48px
height 48px
vertical-align bottom
border-radius 100%
> .initializing
> .empty
margin 0
padding 16px
text-align center
color var(--text)
> i
margin-right 4px
</style>

View File

@@ -1,112 +0,0 @@
<template>
<div class="hozptpaliadatkehcmcayizwzwwctpbc">
<p class="title"><fa icon="users"/>{{ $t('title') }}</p>
<p class="initializing" v-if="fetching"><fa icon="spinner" pulse fixed-width/>{{ $t('loading') }}<mk-ellipsis/></p>
<template v-if="!fetching && users.length != 0">
<div class="user" v-for="friend in users">
<mk-avatar class="avatar" :user="friend"/>
<div class="body">
<router-link class="name" :to="friend | userPage" v-user-preview="friend.id"><mk-user-name :user="friend"/></router-link>
<p class="username">@{{ friend | acct }}</p>
</div>
</div>
</template>
<p class="empty" v-if="!fetching && users.length == 0">{{ $t('no-users') }}</p>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import i18n from '../../../../i18n';
export default Vue.extend({
i18n: i18n('desktop/views/pages/user/user.friends.vue'),
props: ['user'],
data() {
return {
users: [],
fetching: true
};
},
mounted() {
this.$root.api('users/get_frequently_replied_users', {
userId: this.user.id,
limit: 4
}).then(docs => {
this.users = docs.map(doc => doc.user);
this.fetching = false;
});
}
});
</script>
<style lang="stylus" scoped>
.hozptpaliadatkehcmcayizwzwwctpbc
background var(--face)
box-shadow var(--shadow)
border-radius var(--round)
overflow hidden
> .title
z-index 1
margin 0
padding 0 16px
line-height 42px
font-size 0.9em
font-weight bold
background var(--faceHeader)
color var(--faceHeaderText)
box-shadow 0 1px rgba(#000, 0.07)
> i
margin-right 4px
> .initializing
> .empty
margin 0
padding 16px
text-align center
color var(--text)
> i
margin-right 4px
> .user
padding 16px
border-bottom solid 1px var(--faceDivider)
&:last-child
border-bottom none
&:after
content ""
display block
clear both
> .avatar
display block
float left
margin 0 12px 0 0
width 42px
height 42px
border-radius 8px
> .body
float left
width calc(100% - 54px)
> .name
margin 0
font-size 16px
line-height 24px
color var(--text)
> .username
display block
margin 0
font-size 15px
line-height 16px
color var(--text)
opacity 0.7
</style>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="header"> <div class="header" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<div class="banner-container" :style="style"> <div class="banner-container" :style="style">
<div class="banner" ref="banner" :style="style" @click="onBannerClick"></div> <div class="banner" ref="banner" :style="style" @click="onBannerClick"></div>
<div class="fade"></div> <div class="fade"></div>
@@ -126,10 +126,14 @@ export default Vue.extend({
<style lang="stylus" scoped> <style lang="stylus" scoped>
.header .header
background var(--face) background var(--face)
box-shadow var(--shadow)
border-radius var(--round)
overflow hidden overflow hidden
&.round
border-radius 6px
&.shadow
box-shadow 0 3px 8px rgba(0, 0, 0, 0.2)
> .banner-container > .banner-container
height 250px height 250px
overflow hidden overflow hidden

View File

@@ -35,7 +35,7 @@
<span class="signin" @click="signin">{{ $t('@.signin') }}</span> <span class="signin" @click="signin">{{ $t('@.signin') }}</span>
</p> </p>
<img :src="meta.mascotImageUrl" alt="" title="藍" class="char"> <img v-if="meta" :src="meta.mascotImageUrl" alt="" title="藍" class="char">
</div> </div>
</div> </div>
@@ -344,8 +344,6 @@ export default Vue.extend({
.block .block
color var(--text) color var(--text)
background var(--face) background var(--face)
box-shadow var(--shadow)
//border-radius 8px
overflow auto overflow auto
> header > header

View File

@@ -6,7 +6,6 @@ import wActivity from './activity.vue';
import wTrends from './trends.vue'; import wTrends from './trends.vue';
import wUsers from './users.vue'; import wUsers from './users.vue';
import wPolls from './polls.vue'; import wPolls from './polls.vue';
import wPostForm from './post-form.vue';
import wMessaging from './messaging.vue'; import wMessaging from './messaging.vue';
import wProfile from './profile.vue'; import wProfile from './profile.vue';
import wCustomize from './customize.vue'; import wCustomize from './customize.vue';
@@ -17,7 +16,6 @@ Vue.component('mkw-activity', wActivity);
Vue.component('mkw-trends', wTrends); Vue.component('mkw-trends', wTrends);
Vue.component('mkw-users', wUsers); Vue.component('mkw-users', wUsers);
Vue.component('mkw-polls', wPolls); Vue.component('mkw-polls', wPolls);
Vue.component('mkw-post-form', wPostForm);
Vue.component('mkw-messaging', wMessaging); Vue.component('mkw-messaging', wMessaging);
Vue.component('mkw-profile', wProfile); Vue.component('mkw-profile', wProfile);
Vue.component('mkw-customize', wCustomize); Vue.component('mkw-customize', wCustomize);

View File

@@ -401,34 +401,6 @@ export default (callback: (launch: (router: VueRouter) => [Vue, MiOS], os: MiOS)
console.log(`Cannot reapply theme. ${e}`); console.log(`Cannot reapply theme. ${e}`);
} }
//#region shadow
const shadow = '0 3px 8px rgba(0, 0, 0, 0.2)';
const shadowRight = '4px 0 4px rgba(0, 0, 0, 0.1)';
const shadowLeft = '-4px 0 4px rgba(0, 0, 0, 0.1)';
if (os.store.state.device.useShadow) {
document.documentElement.style.setProperty('--shadow', shadow);
document.documentElement.style.setProperty('--shadowRight', shadowRight);
document.documentElement.style.setProperty('--shadowLeft', shadowLeft);
}
os.store.watch(s => {
return s.device.useShadow;
}, v => {
document.documentElement.style.setProperty('--shadow', v ? shadow : 'none');
document.documentElement.style.setProperty('--shadowRight', v ? shadowRight : 'none');
document.documentElement.style.setProperty('--shadowLeft', v ? shadowLeft : 'none');
});
//#endregion
//#region rounded corners
const round = '6px';
if (os.store.state.device.roundedCorners) document.documentElement.style.setProperty('--round', round);
os.store.watch(s => {
return s.device.roundedCorners;
}, v => {
document.documentElement.style.setProperty('--round', v ? round : '0');
});
//#endregion
//#region line width //#region line width
document.documentElement.style.setProperty('--lineWidth', `${os.store.state.device.lineWidth}px`); document.documentElement.style.setProperty('--lineWidth', `${os.store.state.device.lineWidth}px`);
os.store.watch(s => { os.store.watch(s => {

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="mk-note-detail" tabindex="-1" :class="{ shadow: $store.state.device.useShadow }"> <div class="mk-note-detail" tabindex="-1" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<button <button
class="more" class="more"
v-if="appearNote.reply && appearNote.reply.replyId && conversation.length == 0" v-if="appearNote.reply && appearNote.reply.replyId && conversation.length == 0"
@@ -164,7 +164,9 @@ export default Vue.extend({
width 100% width 100%
text-align left text-align left
background var(--face) background var(--face)
border-radius 8px
&.round
border-radius 8px
&.shadow &.shadow
box-shadow 0 4px 16px rgba(#000, 0.1) box-shadow 0 4px 16px rgba(#000, 0.1)

View File

@@ -36,26 +36,26 @@
</div> </div>
<span class="app" v-if="appearNote.app && $store.state.settings.showVia">via <b>{{ appearNote.app.name }}</b></span> <span class="app" v-if="appearNote.app && $store.state.settings.showVia">via <b>{{ appearNote.app.name }}</b></span>
</div> </div>
<footer v-if="appearNote.deletedAt == null"> <footer v-if="appearNote.deletedAt == null" class="footer">
<mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/> <mk-reactions-viewer :note="appearNote" ref="reactionsViewer"/>
<button @click="reply()"> <button @click="reply()" class="button">
<template v-if="appearNote.reply"><fa icon="reply-all"/></template> <template v-if="appearNote.reply"><fa icon="reply-all"/></template>
<template v-else><fa icon="reply"/></template> <template v-else><fa icon="reply"/></template>
<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p> <p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
</button> </button>
<button v-if="['public', 'home'].includes(appearNote.visibility)" @click="renote()" title="Renote"> <button v-if="['public', 'home'].includes(appearNote.visibility)" @click="renote()" title="Renote" class="button">
<fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p> <fa icon="retweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
</button> </button>
<button v-else> <button v-else class="button">
<fa icon="ban"/> <fa icon="ban"/>
</button> </button>
<button v-if="!isMyNote && appearNote.myReaction == null" class="reactionButton" @click="react()" ref="reactButton"> <button v-if="!isMyNote && appearNote.myReaction == null" class="button" @click="react()" ref="reactButton">
<fa icon="plus"/> <fa icon="plus"/>
</button> </button>
<button v-if="!isMyNote && appearNote.myReaction != null" class="reactionButton reacted" @click="undoReact(appearNote)" ref="reactButton"> <button v-if="!isMyNote && appearNote.myReaction != null" class="button reacted" @click="undoReact(appearNote)" ref="reactButton">
<fa icon="minus"/> <fa icon="minus"/>
</button> </button>
<button class="menu" @click="menu()" ref="menuButton"> <button class="button" @click="menu()" ref="menuButton">
<fa icon="ellipsis-h"/> <fa icon="ellipsis-h"/>
</button> </button>
</footer> </footer>
@@ -107,20 +107,6 @@ export default Vue.extend({
font-size 13px font-size 13px
border-bottom solid var(--lineWidth) var(--faceDivider) border-bottom solid var(--lineWidth) var(--faceDivider)
&:focus
z-index 1
&:after
content ""
pointer-events none
position absolute
top 2px
right 2px
bottom 2px
left 2px
border 2px solid var(--primaryAlpha03)
border-radius 4px
&:last-of-type &:last-of-type
border-bottom none border-bottom none
@@ -251,8 +237,8 @@ export default Vue.extend({
font-size 12px font-size 12px
color #ccc color #ccc
> footer > .footer
> button > .button
margin 0 margin 0
padding 8px padding 8px
background transparent background transparent

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="ivaojijs" :class="{ shadow: $store.state.device.useShadow }"> <div class="ivaojijs" :class="{ shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<div class="empty" v-if="notes.length == 0 && !fetching && inited">{{ $t('@.no-notes') }}</div> <div class="empty" v-if="notes.length == 0 && !fetching && inited">{{ $t('@.no-notes') }}</div>
<mk-error v-if="!fetching && !inited" @retry="init()"/> <mk-error v-if="!fetching && !inited" @retry="init()"/>
@@ -191,7 +191,9 @@ export default Vue.extend({
.ivaojijs .ivaojijs
overflow hidden overflow hidden
background var(--face) background var(--face)
border-radius 8px
&.round
border-radius 8px
&.shadow &.shadow
box-shadow 0 4px 16px rgba(#000, 0.1) box-shadow 0 4px 16px rgba(#000, 0.1)

View File

@@ -61,7 +61,7 @@ export default Vue.extend({
this.connection.on('notification', this.onNotification); this.connection.on('notification', this.onNotification);
const max = 10; const max = 15;
this.$root.api('i/notifications', { this.$root.api('i/notifications', {
limit: max + 1 limit: max + 1

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="ukygtjoj" :class="{ naked, inNakedDeckColumn, hideHeader: !showHeader, shadow: $store.state.device.useShadow }"> <div class="ukygtjoj" :class="{ naked, inNakedDeckColumn, hideHeader: !showHeader, shadow: $store.state.device.useShadow, round: $store.state.device.roundedCorners }">
<header v-if="showHeader"> <header v-if="showHeader">
<div class="title"><slot name="header"></slot></div> <div class="title"><slot name="header"></slot></div>
<slot name="func"></slot> <slot name="func"></slot>
@@ -59,7 +59,9 @@ export default Vue.extend({
&:not(.inNakedDeckColumn) &:not(.inNakedDeckColumn)
background var(--face) background var(--face)
border-radius 8px
&.round
border-radius 8px
&.shadow &.shadow
box-shadow 0 4px 16px rgba(#000, 0.1) box-shadow 0 4px 16px rgba(#000, 0.1)
@@ -82,7 +84,6 @@ export default Vue.extend({
font-weight normal font-weight normal
color var(--faceHeaderText) color var(--faceHeaderText)
background var(--faceHeader) background var(--faceHeader)
border-radius 8px 8px 0 0
> [data-icon] > [data-icon]
margin-right 6px margin-right 6px

View File

@@ -51,6 +51,7 @@
<div class="notifications" v-if="showNotifications"> <div class="notifications" v-if="showNotifications">
<header> <header>
<button @click="showNotifications = false"><fa icon="times"/></button> <button @click="showNotifications = false"><fa icon="times"/></button>
<i v-if="hasUnreadNotification" class="circle"><fa icon="circle"/></i>
</header> </header>
<mk-notifications/> <mk-notifications/>
</div> </div>
@@ -207,7 +208,7 @@ export default Vue.extend({
font-size 15px font-size 15px
&.notifications &.notifications
width 340px width 330px
> .notifications > .notifications
padding-top 42px padding-top 42px
@@ -217,7 +218,7 @@ export default Vue.extend({
top 0 top 0
left 0 left 0
z-index 1000 z-index 1000
width 340px width 330px
line-height 42px line-height 42px
background var(--secondary) background var(--secondary)
@@ -228,6 +229,13 @@ export default Vue.extend({
line-height 42px line-height 42px
color var(--text) color var(--text)
> i
position absolute
top 0
right 16px
font-size 12px
color var(--notificationIndicator)
> .nav > .nav
> .me > .me

View File

@@ -124,7 +124,7 @@ export default Vue.extend({
position absolute position absolute
top 0 top 0
left 0 left 0
color var(--primary) color var(--notificationIndicator)
font-size 16px font-size 16px
&.post &.post

View File

@@ -308,7 +308,10 @@ export default Vue.extend({
circleIcons: { circleIcons: {
get() { return this.$store.state.settings.circleIcons; }, get() { return this.$store.state.settings.circleIcons; },
set(value) { this.$store.dispatch('settings/set', { key: 'circleIcons', value }); } set(value) {
this.$store.dispatch('settings/set', { key: 'circleIcons', value });
this.reload();
}
}, },
lineWidth: { lineWidth: {
@@ -318,12 +321,18 @@ export default Vue.extend({
contrastedAcct: { contrastedAcct: {
get() { return this.$store.state.settings.contrastedAcct; }, get() { return this.$store.state.settings.contrastedAcct; },
set(value) { this.$store.dispatch('settings/set', { key: 'contrastedAcct', value }); } set(value) {
this.$store.dispatch('settings/set', { key: 'contrastedAcct', value });
this.reload();
}
}, },
showFullAcct: { showFullAcct: {
get() { return this.$store.state.settings.showFullAcct; }, get() { return this.$store.state.settings.showFullAcct; },
set(value) { this.$store.dispatch('settings/set', { key: 'showFullAcct', value }); } set(value) {
this.$store.dispatch('settings/set', { key: 'showFullAcct', value });
this.reload();
}
}, },
showVia: { showVia: {
@@ -396,6 +405,18 @@ export default Vue.extend({
this.$root.signout(); this.$root.signout();
}, },
reload() {
this.$root.dialog({
type: 'warning',
text: this.$t('@.reload-to-apply-the-setting'),
showCancelButton: true
}).then(({ canceled }) => {
if (!canceled) {
location.reload();
}
});
},
checkForUpdate() { checkForUpdate() {
this.checkingForUpdate = true; this.checkingForUpdate = true;
checkForUpdate(this.$root, true, true).then(newer => { checkForUpdate(this.$root, true, true).then(newer => {

View File

@@ -44,7 +44,14 @@ export const meta = {
'-attachedRemoteUsers', '-attachedRemoteUsers',
]), ]),
}, },
} },
res: {
type: 'array',
items: {
type: 'Hashtag'
}
},
}; };
const sort: any = { const sort: any = {

View File

@@ -35,7 +35,14 @@ export const meta = {
'ja-JP': 'オフセット' 'ja-JP': 'オフセット'
} }
} }
} },
res: {
type: 'array',
items: {
type: 'string'
}
},
}; };
export default define(meta, async (ps) => { export default define(meta, async (ps) => {

View File

@@ -44,7 +44,14 @@ export const meta = {
]), ]),
default: 'local' default: 'local'
} }
} },
res: {
type: 'array',
items: {
type: 'User'
}
},
}; };
const sort: any = { const sort: any = {

View File

@@ -46,6 +46,13 @@ export const meta = {
}, },
}, },
res: {
type: 'array',
items: {
type: 'Reaction'
}
},
errors: { errors: {
noSuchNote: { noSuchNote: {
message: 'No such note.', message: 'No such note.',

View File

@@ -312,7 +312,7 @@ export const schemas = {
example: 'xxxxxxxxxxxxxxxxxxxxxxxx', example: 'xxxxxxxxxxxxxxxxxxxxxxxx',
}, },
parent: { parent: {
type: 'DriveFolder', $ref: '#/components/schemas/DriveFolder'
}, },
}, },
required: ['id', 'createdAt', 'name'] required: ['id', 'createdAt', 'name']
@@ -361,4 +361,86 @@ export const schemas = {
}, },
required: ['id', 'createdAt', 'blockee'] required: ['id', 'createdAt', 'blockee']
}, },
Reaction: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'id',
description: 'The unique identifier for this reaction.',
example: 'xxxxxxxxxxxxxxxxxxxxxxxx',
},
createdAt: {
type: 'string',
format: 'date-time',
description: 'The date that the reaction was created.'
},
user: {
$ref: '#/components/schemas/User',
description: 'User who performed this reaction.'
},
type: {
type: 'string',
enum: [
'like',
'love',
'laugh',
'hmm',
'surprise',
'congrats',
'angry',
'confused',
'rip',
'pudding'
],
description: 'The reaction type.'
},
},
required: ['id', 'createdAt', 'user', 'type']
},
Hashtag: {
type: 'object',
properties: {
tag: {
type: 'string',
description: 'The hashtag name. No # prefixed.',
example: 'misskey',
},
mentionedUsersCount: {
type: 'number',
description: 'Number of all users using this hashtag.'
},
mentionedLocalUsersCount: {
type: 'number',
description: 'Number of local users using this hashtag.'
},
mentionedRemoteUsersCount: {
type: 'number',
description: 'Number of remote users using this hashtag.'
},
attachedUsersCount: {
type: 'number',
description: 'Number of all users who attached this hashtag to profile.'
},
attachedLocalUsersCount: {
type: 'number',
description: 'Number of local users who attached this hashtag to profile.'
},
attachedRemoteUsersCount: {
type: 'number',
description: 'Number of remote users who attached this hashtag to profile.'
},
},
required: [
'tag',
'mentionedUsersCount',
'mentionedLocalUsersCount',
'mentionedRemoteUsersCount',
'attachedUsersCount',
'attachedLocalUsersCount',
'attachedRemoteUsersCount',
]
},
}; };

View File

@@ -2,10 +2,15 @@ import * as Koa from 'koa';
import * as request from 'request-promise-native'; import * as request from 'request-promise-native';
import summaly from 'summaly'; import summaly from 'summaly';
import fetchMeta from '../../misc/fetch-meta'; import fetchMeta from '../../misc/fetch-meta';
import Logger from '../../misc/logger';
const logger = new Logger('url-preview');
module.exports = async (ctx: Koa.BaseContext) => { module.exports = async (ctx: Koa.BaseContext) => {
const meta = await fetchMeta(); const meta = await fetchMeta();
logger.info(`Getting preview of ${ctx.query.url} ...`);
try { try {
const summary = meta.summalyProxy ? await request.get({ const summary = meta.summalyProxy ? await request.get({
url: meta.summalyProxy, url: meta.summalyProxy,
@@ -17,6 +22,8 @@ module.exports = async (ctx: Koa.BaseContext) => {
followRedirects: false followRedirects: false
}); });
logger.succ(`Got preview of ${ctx.query.url}: ${summary.title}`);
summary.icon = wrap(summary.icon); summary.icon = wrap(summary.icon);
summary.thumbnail = wrap(summary.thumbnail); summary.thumbnail = wrap(summary.thumbnail);
@@ -25,6 +32,7 @@ module.exports = async (ctx: Koa.BaseContext) => {
ctx.body = summary; ctx.body = summary;
} catch (e) { } catch (e) {
logger.error(`Failed to get preview of ${ctx.query.url}: ${e}`);
ctx.status = 200; ctx.status = 200;
ctx.set('Cache-Control', 'max-age=86400, immutable'); ctx.set('Cache-Control', 'max-age=86400, immutable');
ctx.body = '{}'; ctx.body = '{}';