summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2020-03-29 17:46:31 +0900
committersyuilo <syuilotan@yahoo.co.jp>2020-03-29 17:46:31 +0900
commitcc66a1f9c7733f0ff3c23b60a8578cdb1235a3f2 (patch)
treee7e7697fcfc2ec63c642e5496030bdd46f87601b /src
parentMerge branch 'develop' (diff)
parent12.28.0 (diff)
downloadsharkey-cc66a1f9c7733f0ff3c23b60a8578cdb1235a3f2.tar.gz
sharkey-cc66a1f9c7733f0ff3c23b60a8578cdb1235a3f2.tar.bz2
sharkey-cc66a1f9c7733f0ff3c23b60a8578cdb1235a3f2.zip
Merge branch 'develop'
Diffstat (limited to 'src')
-rw-r--r--src/client/app.vue4
-rw-r--r--src/client/components/date-separated-list.vue4
-rw-r--r--src/client/pages/apps.vue6
-rw-r--r--src/client/pages/instance/federation.vue32
-rw-r--r--src/client/pages/instance/queue.vue3
-rw-r--r--src/client/pages/messaging/messaging-room.vue2
-rw-r--r--src/client/pages/miauth.vue6
-rw-r--r--src/client/theme.ts26
-rw-r--r--src/client/widgets/memo.vue17
-rw-r--r--src/db/postgre.ts6
-rw-r--r--src/docs/theme.ja-JP.md74
-rw-r--r--src/models/repositories/notification.ts4
-rw-r--r--src/server/api/define.ts6
-rw-r--r--src/server/api/endpoints/i/apps.ts1
-rw-r--r--src/server/api/endpoints/meta.ts1
-rw-r--r--src/server/api/endpoints/notifications/create.ts2
-rw-r--r--src/server/api/stream/index.ts4
17 files changed, 154 insertions, 44 deletions
diff --git a/src/client/app.vue b/src/client/app.vue
index 99268e42bf..fc40b6973a 100644
--- a/src/client/app.vue
+++ b/src/client/app.vue
@@ -975,6 +975,10 @@ export default Vue.extend({
&:not(.naked) {
background: var(--pageBg);
}
+
+ &.naked {
+ background: var(--bg);
+ }
}
}
diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue
index d41dd9d521..b80c6494ed 100644
--- a/src/client/components/date-separated-list.vue
+++ b/src/client/components/date-separated-list.vue
@@ -1,8 +1,8 @@
<template>
<component :is="$store.state.device.animation ? 'transition-group' : 'div'" class="sqadhkmv" name="list" tag="div" :data-direction="direction" :data-reversed="reversed ? 'true' : 'false'">
<template v-for="(item, i) in items">
- <slot :item="item" :i="i"></slot>
- <div class="separator" :key="item.id + '_date'" v-if="showDate(i, item)">
+ <slot :item="item"></slot>
+ <div class="separator" v-if="showDate(i, item)" :key="item.id + '_date'">
<p class="date">
<span><fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span>
<span>{{ getDateText(items[i + 1].createdAt) }}<fa class="icon" :icon="faAngleDown"/></span>
diff --git a/src/client/pages/apps.vue b/src/client/pages/apps.vue
index 03c6707f95..445bba34c8 100644
--- a/src/client/pages/apps.vue
+++ b/src/client/pages/apps.vue
@@ -27,6 +27,12 @@
<div class="actions">
<button class="_button" @click="revoke(token)"><fa :icon="faTrashAlt"/></button>
</div>
+ <details>
+ <summary>{{ $t('details') }}</summary>
+ <ul>
+ <li v-for="p in token.permission" :key="p">{{ $t(`_permissions.${p}`) }}</li>
+ </ul>
+ </details>
</div>
</div>
</template>
diff --git a/src/client/pages/instance/federation.vue b/src/client/pages/instance/federation.vue
index fa7c377720..5babc60453 100644
--- a/src/client/pages/instance/federation.vue
+++ b/src/client/pages/instance/federation.vue
@@ -1,11 +1,14 @@
<template>
<div class="mk-federation">
+ <portal to="icon"><fa :icon="faGlobe"/></portal>
+ <portal to="title">{{ $t('federation') }}</portal>
+
<section class="_card instances">
- <div class="_title"><fa :icon="faGlobe"/> {{ $t('instances') }}</div>
<div class="_content">
+ <mk-input v-model="host" :debounce="true"><span>{{ $t('host') }}</span></mk-input>
<div class="inputs" style="display: flex;">
- <mk-input v-model="host" :debounce="true" style="margin: 0; flex: 1;"><span>{{ $t('host') }}</span></mk-input>
- <mk-select v-model="state" style="margin: 0;">
+ <mk-select v-model="state" style="margin: 0; flex: 1;">
+ <template #label>{{ $t('state') }}</template>
<option value="all">{{ $t('all') }}</option>
<option value="federating">{{ $t('federating') }}</option>
<option value="subscribing">{{ $t('subscribing') }}</option>
@@ -14,11 +17,32 @@
<option value="blocked">{{ $t('blocked') }}</option>
<option value="notResponding">{{ $t('notResponding') }}</option>
</mk-select>
+ <mk-select v-model="sort" style="margin: 0; flex: 1;">
+ <template #label>{{ $t('sort') }}</template>
+ <option value="+pubSub">{{ $t('pubSub') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-pubSub">{{ $t('pubSub') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+notes">{{ $t('notes') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-notes">{{ $t('notes') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+users">{{ $t('users') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-users">{{ $t('users') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+following">{{ $t('following') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-following">{{ $t('following') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+followers">{{ $t('followers') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-followers">{{ $t('followers') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+caughtAt">{{ $t('caughtAt') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-caughtAt">{{ $t('caughtAt') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+lastCommunicatedAt">{{ $t('lastCommunicatedAt') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-lastCommunicatedAt">{{ $t('lastCommunicatedAt') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+driveUsage">{{ $t('driveUsage') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-driveUsage">{{ $t('driveUsage') }} ({{ $t('ascendingOrder') }})</option>
+ <option value="+driveFiles">{{ $t('driveFiles') }} ({{ $t('descendingOrder') }})</option>
+ <option value="-driveFiles">{{ $t('driveFiles') }} ({{ $t('ascendingOrder') }})</option>
+ </mk-select>
</div>
</div>
<div class="_content">
<mk-pagination :pagination="pagination" #default="{items}" class="instances" ref="instances" :key="host + state">
- <div class="instance" v-for="(instance, i) in items" :key="instance.id" @click="info(instance)">
+ <div class="instance" v-for="instance in items" :key="instance.id" @click="info(instance)">
<div class="host"><fa :icon="faCircle" class="indicator" :class="getStatus(instance)"/><b>{{ instance.host }}</b></div>
<div class="status">
<span class="sub" v-if="instance.followersCount > 0"><fa :icon="faCaretDown" class="icon"/>Sub</span>
diff --git a/src/client/pages/instance/queue.vue b/src/client/pages/instance/queue.vue
index 8590f9ae23..c4892e88db 100644
--- a/src/client/pages/instance/queue.vue
+++ b/src/client/pages/instance/queue.vue
@@ -1,5 +1,8 @@
<template>
<div>
+ <portal to="icon"><fa :icon="faExchangeAlt"/></portal>
+ <portal to="title">{{ $t('jobQueue') }}</portal>
+
<x-queue :connection="connection" domain="inbox">
<template #title><fa :icon="faExchangeAlt"/> In</template>
</x-queue>
diff --git a/src/client/pages/messaging/messaging-room.vue b/src/client/pages/messaging/messaging-room.vue
index 0a20c56c29..317ad087fe 100644
--- a/src/client/pages/messaging/messaging-room.vue
+++ b/src/client/pages/messaging/messaging-room.vue
@@ -19,7 +19,7 @@
<button class="more _button" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
<template v-if="fetchingMoreMessages"><fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $t('loading') : $t('loadMore') }}
</button>
- <x-list class="messages" :items="messages" v-slot="{ item: message, i }" direction="up" reversed>
+ <x-list class="messages" :items="messages" v-slot="{ item: message }" direction="up" reversed>
<x-message :message="message" :is-group="group != null" :key="message.id"/>
</x-list>
</div>
diff --git a/src/client/pages/miauth.vue b/src/client/pages/miauth.vue
index 2ee0f23479..0e170af11a 100644
--- a/src/client/pages/miauth.vue
+++ b/src/client/pages/miauth.vue
@@ -68,8 +68,8 @@ export default Vue.extend({
icon(): string {
return this.$route.query.icon;
},
- permission(): string {
- return this.$route.query.permission;
+ permission(): string[] {
+ return this.$route.query.permission ? this.$route.query.permission.split(',') : [];
},
},
methods: {
@@ -79,7 +79,7 @@ export default Vue.extend({
session: this.session,
name: this.name,
iconUrl: this.icon,
- permission: this.permission || [],
+ permission: this.permission,
});
this.state = 'accepted';
diff --git a/src/client/theme.ts b/src/client/theme.ts
index cc69ee4060..2f4920e3af 100644
--- a/src/client/theme.ts
+++ b/src/client/theme.ts
@@ -27,7 +27,7 @@ export const builtinThemes = [
require('./themes/danboard.json5'),
require('./themes/olive.json5'),
require('./themes/tweetdeck.json5'),
-];
+] as Theme[];
let timeout = null;
@@ -66,16 +66,21 @@ export function applyTheme(theme: Theme, persist = true) {
}
}
-function compile(theme: Theme): { [key: string]: string } {
- function getColor(code: string): tinycolor.Instance {
- // ref
- if (code[0] == '@') {
- return getColor(theme.props[code.substr(1)]);
+function compile(theme: Theme): Record<string, string> {
+ function getColor(val: string): tinycolor.Instance {
+ // ref (prop)
+ if (val[0] === '@') {
+ return getColor(theme.props[val.substr(1)]);
+ }
+
+ // ref (const)
+ else if (val[0] === '$') {
+ return getColor(theme.props[val]);
}
// func
- if (code[0] == ':') {
- const parts = code.split('<');
+ else if (val[0] === ':') {
+ const parts = val.split('<');
const func = parts.shift().substr(1);
const arg = parseFloat(parts.shift());
const color = getColor(parts.join('<'));
@@ -87,12 +92,15 @@ function compile(theme: Theme): { [key: string]: string } {
}
}
- return tinycolor(code);
+ // other case
+ return tinycolor(val);
}
const props = {};
for (const [k, v] of Object.entries(theme.props)) {
+ if (k.startsWith('$')) continue; // ignore const
+
props[k] = genValue(getColor(v));
}
diff --git a/src/client/widgets/memo.vue b/src/client/widgets/memo.vue
index 974c13eb0d..3c170adc4e 100644
--- a/src/client/widgets/memo.vue
+++ b/src/client/widgets/memo.vue
@@ -5,7 +5,7 @@
<div class="otgbylcu">
<textarea v-model="text" :placeholder="$t('placeholder')" @input="onChange"></textarea>
- <button @click="saveMemo" :disabled="!changed">{{ $t('save') }}</button>
+ <button @click="saveMemo" :disabled="!changed" class="_buttonPrimary">{{ $t('save') }}</button>
</div>
</mk-container>
</div>
@@ -84,6 +84,7 @@ export default define({
border: none;
border-bottom: solid var(--lineWidth) var(--faceDivider);
border-radius: 0;
+ box-sizing: border-box;
}
> button {
@@ -94,22 +95,8 @@ export default define({
margin: 0;
padding: 0 10px;
height: 28px;
- color: #fff;
- background: var(--accent) !important;
outline: none;
- border: none;
border-radius: 4px;
- transition: background 0.1s ease;
- cursor: pointer;
-
- &:hover {
- background: var(--accentLighten10) !important;
- }
-
- &:active {
- background: var(--accentDarken) !important;
- transition: background 0s ease;
- }
&:disabled {
opacity: 0.7;
diff --git a/src/db/postgre.ts b/src/db/postgre.ts
index 57703fb095..9e3eb3f7d6 100644
--- a/src/db/postgre.ts
+++ b/src/db/postgre.ts
@@ -69,7 +69,9 @@ class MyCustomLogger implements Logger {
}
public logQuery(query: string, parameters?: any[]) {
- sqlLogger.info(this.highlight(query));
+ if (program.verbose) {
+ sqlLogger.info(this.highlight(query));
+ }
}
public logQueryError(error: string, query: string, parameters?: any[]) {
@@ -158,7 +160,7 @@ export function initDb(justBorrow = false, sync = false, forceRecreate = false)
} catch (e) {}
}
- const log = program.verbose;
+ const log = process.env.NODE_ENV != 'production';
return createConnection({
type: 'postgres',
diff --git a/src/docs/theme.ja-JP.md b/src/docs/theme.ja-JP.md
new file mode 100644
index 0000000000..c9604da412
--- /dev/null
+++ b/src/docs/theme.ja-JP.md
@@ -0,0 +1,74 @@
+# テーマ
+
+テーマを設定して、Misskeyクライアントの見た目を変更できます。
+
+## テーマの設定
+設定 > テーマ
+
+## テーマを作成する
+テーマコードはJSON5で記述されたテーマオブジェクトです。
+テーマは以下のようなオブジェクトです。
+``` js
+{
+ id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
+
+ name: 'Danboard',
+ author: 'syuilo',
+
+ base: 'light',
+
+ props: {
+ accent: 'rgb(218, 141, 49)',
+ bg: 'rgb(218, 212, 190)',
+ fg: 'rgb(115, 108, 92)',
+ panel: 'rgb(236, 232, 220)',
+ renote: 'rgb(100, 152, 106)',
+ link: 'rgb(100, 152, 106)',
+ mention: '@accent',
+ hashtag: 'rgb(100, 152, 106)',
+ header: 'rgba(239, 227, 213, 0.75)',
+ navBg: 'rgb(216, 206, 182)',
+ inputBorder: 'rgba(0, 0, 0, 0.1)',
+ },
+}
+
+```
+
+* `id` ... テーマの一意なID。UUIDをおすすめします。
+* `name` ... テーマ名
+* `author` ... テーマの作者
+* `desc` ... テーマの説明(オプション)
+* `base` ... 明るいテーマか、暗いテーマか
+ * `light`にすると明るいテーマになり、`dark`にすると暗いテーマになります。
+ * テーマはここで設定されたベーステーマを継承します。
+* `props` ... テーマのスタイル定義。これから説明します。
+
+### テーマのスタイル定義
+`props`下にはテーマのスタイルを定義します。
+キーがCSSの変数名になり、バリューで中身を指定します。
+なお、この`props`オブジェクトはベーステーマから継承されます。
+ベーステーマは、このテーマの`base`が`light`なら[_light.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_light.json5)で、`dark`なら[_dark.json5](https://github.com/syuilo/misskey/blob/develop/src/client/themes/_dark.json5)です。
+つまり、このテーマ内の`props`に`panel`というキーが無くても、そこにはベーステーマの`panel`があると見なされます。
+
+#### バリューで使える構文
+* 16進数で表された色
+ * 例: `#00ff00`
+* `rgb(r, g, b)`形式で表された色
+ * 例: `rgb(0, 255, 0)`
+* `rgb(r, g, b, a)`形式で表された透明度を含む色
+ * 例: `rgba(0, 255, 0, 0.5)`
+* 他のキーの値の参照
+ * `@{キー名}`と書くと他のキーの値の参照になります。`{キー名}`は参照したいキーの名前に置き換えます。
+ * 例: `@panel`
+* 定数(後述)の参照
+ * `${定数名}`と書くと定数の参照になります。`{定数名}`は参照したい定数の名前に置き換えます。
+ * 例: `$main`
+* 関数(後述)
+ * `:{関数名}<{引数}<{色}`
+
+#### 定数
+「CSS変数として出力はしたくないが、他のCSS変数の値として使いまわしたい」値があるときは、定数を使うと便利です。
+キー名を`$`で始めると、そのキーはCSS変数として出力されません。
+
+#### 関数
+wip
diff --git a/src/models/repositories/notification.ts b/src/models/repositories/notification.ts
index a8978cc01b..b484c43c5e 100644
--- a/src/models/repositories/notification.ts
+++ b/src/models/repositories/notification.ts
@@ -46,8 +46,8 @@ export class NotificationRepository extends Repository<Notification> {
} : {}),
...(notification.type === 'app' ? {
body: notification.customBody,
- header: notification.customHeader || token!.name,
- icon: notification.customIcon || token!.iconUrl,
+ header: notification.customHeader || token?.name,
+ icon: notification.customIcon || token?.iconUrl,
} : {}),
});
}
diff --git a/src/server/api/define.ts b/src/server/api/define.ts
index 2ee0ba4868..1c7ee26479 100644
--- a/src/server/api/define.ts
+++ b/src/server/api/define.ts
@@ -15,12 +15,12 @@ type Params<T extends IEndpointMeta> = {
export type Response = Record<string, any> | void;
type executor<T extends IEndpointMeta> =
- (params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any, cleanup?: Function) =>
+ (params: Params<T>, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any, cleanup?: Function) =>
Promise<T['res'] extends undefined ? Response : SchemaType<NonNullable<T['res']>>>;
export default function <T extends IEndpointMeta>(meta: T, cb: executor<T>)
- : (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any) => Promise<any> {
- return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken, file?: any) => {
+ : (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => Promise<any> {
+ return (params: any, user: T['requireCredential'] extends true ? ILocalUser : ILocalUser | null, token: AccessToken | null, file?: any) => {
function cleanup() {
fs.unlink(file.path, () => {});
}
diff --git a/src/server/api/endpoints/i/apps.ts b/src/server/api/endpoints/i/apps.ts
index dc74123ce3..3b5cd21a79 100644
--- a/src/server/api/endpoints/i/apps.ts
+++ b/src/server/api/endpoints/i/apps.ts
@@ -38,5 +38,6 @@ export default define(meta, async (ps, user) => {
name: token.name,
createdAt: token.createdAt,
lastUsedAt: token.lastUsedAt,
+ permission: token.permission,
})));
});
diff --git a/src/server/api/endpoints/meta.ts b/src/server/api/endpoints/meta.ts
index 8eaa65a2c6..41adc855d2 100644
--- a/src/server/api/endpoints/meta.ts
+++ b/src/server/api/endpoints/meta.ts
@@ -159,6 +159,7 @@ export default define(meta, async (ps, me) => {
github: instance.enableGithubIntegration,
discord: instance.enableDiscordIntegration,
serviceWorker: instance.enableServiceWorker,
+ miauth: true,
};
}
diff --git a/src/server/api/endpoints/notifications/create.ts b/src/server/api/endpoints/notifications/create.ts
index fed422b645..6267699e90 100644
--- a/src/server/api/endpoints/notifications/create.ts
+++ b/src/server/api/endpoints/notifications/create.ts
@@ -29,7 +29,7 @@ export const meta = {
export default define(meta, async (ps, user, token) => {
createNotification(user.id, 'app', {
- appAccessTokenId: token.id,
+ appAccessTokenId: token ? token.id : null,
customBody: ps.body,
customHeader: ps.header,
customIcon: ps.icon,
diff --git a/src/server/api/stream/index.ts b/src/server/api/stream/index.ts
index 05594ac722..2781d14bd9 100644
--- a/src/server/api/stream/index.ts
+++ b/src/server/api/stream/index.ts
@@ -18,7 +18,7 @@ export default class Connection {
public user?: User;
public following: User['id'][] = [];
public muting: User['id'][] = [];
- public token: AccessToken;
+ public token?: AccessToken;
private wsConnection: websocket.connection;
public subscriber: EventEmitter;
private channels: Channel[] = [];
@@ -117,7 +117,7 @@ export default class Connection {
this.subscribingNotes[payload.id]++;
- if (this.subscribingNotes[payload.id] == 1) {
+ if (this.subscribingNotes[payload.id] === 1) {
this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage);
}