Merge branch 'develop' into use-interval
This commit is contained in:
commit
5e6f4e5d03
|
@ -46,8 +46,10 @@ Please include errors from the developer console and/or server log files if you
|
||||||
<!-- Example: Chrome 113.0.5672.126 -->
|
<!-- Example: Chrome 113.0.5672.126 -->
|
||||||
* Server URL:
|
* Server URL:
|
||||||
<!-- Example: misskey.io -->
|
<!-- Example: misskey.io -->
|
||||||
|
* Misskey:
|
||||||
|
13.x.x
|
||||||
|
|
||||||
### 🛰 Backend (for instance admin)
|
### 🛰 Backend (for server admin)
|
||||||
<!-- If you are using a managed service, put that after the version. -->
|
<!-- If you are using a managed service, put that after the version. -->
|
||||||
|
|
||||||
* Installation Method or Hosting Service: <!-- Example: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment -->
|
* Installation Method or Hosting Service: <!-- Example: docker compose, k8s/docker, systemd, "Misskey install shell script", development environment -->
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
### Client
|
### Client
|
||||||
- Fix: タブがアクティブな間はstreamが切断されないように
|
- Fix: タブがアクティブな間はstreamが切断されないように
|
||||||
|
|
||||||
|
### General
|
||||||
|
- エラー時や項目が存在しないときなどのアイコン画像をサーバー管理者が設定できるようになりました
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正
|
- Fix: api/metaで`TypeError: JSON5.parse is not a function`エラーが発生する問題を修正
|
||||||
|
|
||||||
|
|
|
@ -1065,6 +1065,7 @@ export interface Locale {
|
||||||
"goToMisskey": string;
|
"goToMisskey": string;
|
||||||
"additionalEmojiDictionary": string;
|
"additionalEmojiDictionary": string;
|
||||||
"installed": string;
|
"installed": string;
|
||||||
|
"branding": string;
|
||||||
"_initialAccountSetting": {
|
"_initialAccountSetting": {
|
||||||
"accountCreated": string;
|
"accountCreated": string;
|
||||||
"letsStartAccountSetup": string;
|
"letsStartAccountSetup": string;
|
||||||
|
|
|
@ -1062,6 +1062,7 @@ later: "あとで"
|
||||||
goToMisskey: "Misskeyへ"
|
goToMisskey: "Misskeyへ"
|
||||||
additionalEmojiDictionary: "絵文字の追加辞書"
|
additionalEmojiDictionary: "絵文字の追加辞書"
|
||||||
installed: "インストール済み"
|
installed: "インストール済み"
|
||||||
|
branding: "ブランディング"
|
||||||
|
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "アカウントの作成が完了しました!"
|
accountCreated: "アカウントの作成が完了しました!"
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
export class ErrorImageUrl1685973839966 {
|
||||||
|
name = 'ErrorImageUrl1685973839966'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "errorImageUrl"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "serverErrorImageUrl" character varying(1024)`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "notFoundImageUrl" character varying(1024)`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "infoImageUrl" character varying(1024)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "infoImageUrl"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "notFoundImageUrl"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "serverErrorImageUrl"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "errorImageUrl" character varying(1024) DEFAULT 'https://xn--931a.moe/aiart/yubitun.png'`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,13 +101,25 @@ export class Meta {
|
||||||
length: 1024,
|
length: 1024,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public errorImageUrl: string | null;
|
public iconUrl: string | null;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 1024,
|
length: 1024,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public iconUrl: string | null;
|
public serverErrorImageUrl: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public notFoundImageUrl: string | null;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 1024,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
public infoImageUrl: string | null;
|
||||||
|
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: true,
|
default: true,
|
||||||
|
|
|
@ -128,26 +128,27 @@ export class StreamingApiServerService {
|
||||||
ev.removeAllListeners();
|
ev.removeAllListeners();
|
||||||
stream.dispose();
|
stream.dispose();
|
||||||
this.redisForSub.off('message', onRedisMessage);
|
this.redisForSub.off('message', onRedisMessage);
|
||||||
|
this.#connections.delete(connection);
|
||||||
if (userUpdateIntervalId) clearInterval(userUpdateIntervalId);
|
if (userUpdateIntervalId) clearInterval(userUpdateIntervalId);
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.on('message', async (data) => {
|
connection.on('pong', () => {
|
||||||
this.#connections.set(connection, Date.now());
|
this.#connections.set(connection, Date.now());
|
||||||
if (data.toString() === 'ping') {
|
|
||||||
connection.send('pong');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 一定期間通信が無いコネクションは実際には切断されている可能性があるため定期的にterminateする
|
||||||
this.#cleanConnectionsIntervalId = setInterval(() => {
|
this.#cleanConnectionsIntervalId = setInterval(() => {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
for (const [connection, lastActive] of this.#connections.entries()) {
|
for (const [connection, lastActive] of this.#connections.entries()) {
|
||||||
if (now - lastActive > 1000 * 60 * 5) {
|
if (now - lastActive > 1000 * 60 * 2) {
|
||||||
connection.terminate();
|
connection.terminate();
|
||||||
this.#connections.delete(connection);
|
this.#connections.delete(connection);
|
||||||
|
} else {
|
||||||
|
connection.ping();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 1000 * 60 * 5);
|
}, 1000 * 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -61,10 +61,17 @@ export const meta = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
},
|
},
|
||||||
errorImageUrl: {
|
serverErrorImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
infoImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
notFoundImageUrl: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
default: 'https://xn--931a.moe/aiart/yubitun.png',
|
|
||||||
},
|
},
|
||||||
iconUrl: {
|
iconUrl: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -305,7 +312,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
themeColor: instance.themeColor,
|
themeColor: instance.themeColor,
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
mascotImageUrl: instance.mascotImageUrl,
|
||||||
bannerUrl: instance.bannerUrl,
|
bannerUrl: instance.bannerUrl,
|
||||||
errorImageUrl: instance.errorImageUrl,
|
serverErrorImageUrl: instance.serverErrorImageUrl,
|
||||||
|
notFoundImageUrl: instance.notFoundImageUrl,
|
||||||
|
infoImageUrl: instance.infoImageUrl,
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instance.iconUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instance.logoImageUrl,
|
||||||
|
|
|
@ -32,7 +32,9 @@ export const paramDef = {
|
||||||
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
|
themeColor: { type: 'string', nullable: true, pattern: '^#[0-9a-fA-F]{6}$' },
|
||||||
mascotImageUrl: { type: 'string', nullable: true },
|
mascotImageUrl: { type: 'string', nullable: true },
|
||||||
bannerUrl: { type: 'string', nullable: true },
|
bannerUrl: { type: 'string', nullable: true },
|
||||||
errorImageUrl: { type: 'string', nullable: true },
|
serverErrorImageUrl: { type: 'string', nullable: true },
|
||||||
|
infoImageUrl: { type: 'string', nullable: true },
|
||||||
|
notFoundImageUrl: { type: 'string', nullable: true },
|
||||||
iconUrl: { type: 'string', nullable: true },
|
iconUrl: { type: 'string', nullable: true },
|
||||||
backgroundImageUrl: { type: 'string', nullable: true },
|
backgroundImageUrl: { type: 'string', nullable: true },
|
||||||
logoImageUrl: { type: 'string', nullable: true },
|
logoImageUrl: { type: 'string', nullable: true },
|
||||||
|
@ -149,6 +151,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
set.iconUrl = ps.iconUrl;
|
set.iconUrl = ps.iconUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.serverErrorImageUrl !== undefined) {
|
||||||
|
set.serverErrorImageUrl = ps.serverErrorImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.infoImageUrl !== undefined) {
|
||||||
|
set.infoImageUrl = ps.infoImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.notFoundImageUrl !== undefined) {
|
||||||
|
set.notFoundImageUrl = ps.notFoundImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.backgroundImageUrl !== undefined) {
|
if (ps.backgroundImageUrl !== undefined) {
|
||||||
set.backgroundImageUrl = ps.backgroundImageUrl;
|
set.backgroundImageUrl = ps.backgroundImageUrl;
|
||||||
}
|
}
|
||||||
|
@ -281,10 +295,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
set.smtpPass = ps.smtpPass;
|
set.smtpPass = ps.smtpPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.errorImageUrl !== undefined) {
|
|
||||||
set.errorImageUrl = ps.errorImageUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ps.enableServiceWorker !== undefined) {
|
if (ps.enableServiceWorker !== undefined) {
|
||||||
set.enableServiceWorker = ps.enableServiceWorker;
|
set.enableServiceWorker = ps.enableServiceWorker;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,10 +124,17 @@ export const meta = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
errorImageUrl: {
|
serverErrorImageUrl: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: true,
|
||||||
default: 'https://xn--931a.moe/aiart/yubitun.png',
|
},
|
||||||
|
infoImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
notFoundImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
},
|
},
|
||||||
iconUrl: {
|
iconUrl: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -288,7 +295,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
themeColor: instance.themeColor,
|
themeColor: instance.themeColor,
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
mascotImageUrl: instance.mascotImageUrl,
|
||||||
bannerUrl: instance.bannerUrl,
|
bannerUrl: instance.bannerUrl,
|
||||||
errorImageUrl: instance.errorImageUrl,
|
infoImageUrl: instance.infoImageUrl,
|
||||||
|
serverErrorImageUrl: instance.serverErrorImageUrl,
|
||||||
|
notFoundImageUrl: instance.notFoundImageUrl,
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instance.iconUrl,
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
logoImageUrl: instance.logoImageUrl,
|
logoImageUrl: instance.logoImageUrl,
|
||||||
|
|
|
@ -26,7 +26,7 @@ import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
||||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||||
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
|
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, Meta, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { deepClone } from '@/misc/clone.js';
|
import { deepClone } from '@/misc/clone.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
@ -117,6 +117,18 @@ export class ClientServerService {
|
||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
private generateCommonPugData(meta: Meta) {
|
||||||
|
return {
|
||||||
|
instanceName: meta.name ?? 'Misskey',
|
||||||
|
icon: meta.iconUrl,
|
||||||
|
themeColor: meta.themeColor,
|
||||||
|
serverErrorImageUrl: meta.serverErrorImageUrl ?? 'https://xn--931a.moe/assets/error.jpg',
|
||||||
|
infoImageUrl: meta.infoImageUrl ?? 'https://xn--931a.moe/assets/info.jpg',
|
||||||
|
notFoundImageUrl: meta.notFoundImageUrl ?? 'https://xn--931a.moe/assets/not-found.jpg',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
|
||||||
fastify.register(fastifyCookie, {});
|
fastify.register(fastifyCookie, {});
|
||||||
|
@ -341,12 +353,10 @@ export class ClientServerService {
|
||||||
reply.header('Cache-Control', 'public, max-age=30');
|
reply.header('Cache-Control', 'public, max-age=30');
|
||||||
return await reply.view('base', {
|
return await reply.view('base', {
|
||||||
img: meta.bannerUrl,
|
img: meta.bannerUrl,
|
||||||
title: meta.name ?? 'Misskey',
|
|
||||||
instanceName: meta.name ?? 'Misskey',
|
|
||||||
url: this.config.url,
|
url: this.config.url,
|
||||||
|
title: meta.name ?? 'Misskey',
|
||||||
desc: meta.description,
|
desc: meta.description,
|
||||||
icon: meta.iconUrl,
|
...this.generateCommonPugData(meta),
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -431,9 +441,7 @@ export class ClientServerService {
|
||||||
user, profile, me,
|
user, profile, me,
|
||||||
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
||||||
sub: request.params.sub,
|
sub: request.params.sub,
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// リモートユーザーなので
|
// リモートユーザーなので
|
||||||
|
@ -481,9 +489,7 @@ export class ClientServerService {
|
||||||
avatarUrl: _note.user.avatarUrl,
|
avatarUrl: _note.user.avatarUrl,
|
||||||
// TODO: Let locale changeable by instance setting
|
// TODO: Let locale changeable by instance setting
|
||||||
summary: getNoteSummary(_note),
|
summary: getNoteSummary(_note),
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -522,9 +528,7 @@ export class ClientServerService {
|
||||||
page: _page,
|
page: _page,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _page.user.avatarUrl,
|
avatarUrl: _page.user.avatarUrl,
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -550,9 +554,7 @@ export class ClientServerService {
|
||||||
flash: _flash,
|
flash: _flash,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _flash.user.avatarUrl,
|
avatarUrl: _flash.user.avatarUrl,
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -578,9 +580,7 @@ export class ClientServerService {
|
||||||
clip: _clip,
|
clip: _clip,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _clip.user.avatarUrl,
|
avatarUrl: _clip.user.avatarUrl,
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -604,9 +604,7 @@ export class ClientServerService {
|
||||||
post: _post,
|
post: _post,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _post.user.avatarUrl,
|
avatarUrl: _post.user.avatarUrl,
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -625,9 +623,7 @@ export class ClientServerService {
|
||||||
reply.header('Cache-Control', 'public, max-age=15');
|
reply.header('Cache-Control', 'public, max-age=15');
|
||||||
return await reply.view('channel', {
|
return await reply.view('channel', {
|
||||||
channel: _channel,
|
channel: _channel,
|
||||||
instanceName: meta.name ?? 'Misskey',
|
...this.generateCommonPugData(meta),
|
||||||
icon: meta.iconUrl,
|
|
||||||
themeColor: meta.themeColor,
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
|
|
@ -31,9 +31,9 @@ html
|
||||||
link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png')
|
link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png')
|
||||||
link(rel='manifest' href='/manifest.json')
|
link(rel='manifest' href='/manifest.json')
|
||||||
link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${url}/opensearch.xml`)
|
link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${url}/opensearch.xml`)
|
||||||
link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
|
link(rel='prefetch' href=serverErrorImageUrl)
|
||||||
link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
|
link(rel='prefetch' href=infoImageUrl)
|
||||||
link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
|
link(rel='prefetch' href=notFoundImageUrl)
|
||||||
//- https://github.com/misskey-dev/misskey/issues/9842
|
//- https://github.com/misskey-dev/misskey/issues/9842
|
||||||
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.21.0')
|
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.21.0')
|
||||||
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
|
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.notFound }}</div>
|
<div>{{ i18n.ts.notFound }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
import MkChannelPreview from '@/components/MkChannelPreview.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MkPagination ref="pagingComponent" :pagination="pagination">
|
<MkPagination ref="pagingComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
<div>{{ i18n.ts.noNotes }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -32,6 +32,7 @@ import MkNote from '@/components/MkNote.vue';
|
||||||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MkPagination ref="pagingComponent" :pagination="pagination">
|
<MkPagination ref="pagingComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotifications }}</div>
|
<div>{{ i18n.ts.noNotifications }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -26,6 +26,7 @@ import { useStream } from '@/stream';
|
||||||
import { $i } from '@/account';
|
import { $i } from '@/account';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { notificationTypes } from '@/const';
|
import { notificationTypes } from '@/const';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
includeTypes?: typeof notificationTypes[number][];
|
includeTypes?: typeof notificationTypes[number][];
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<div v-else-if="empty" key="_empty_" class="empty">
|
<div v-else-if="empty" key="_empty_" class="empty">
|
||||||
<slot name="empty">
|
<slot name="empty">
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -73,6 +73,8 @@ export type Paging<E extends keyof misskey.Endpoints = keyof misskey.Endpoints>
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
disableAutoLoad?: boolean;
|
disableAutoLoad?: boolean;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<MkSpacer :marginMin="20" :marginMax="28">
|
<MkSpacer :marginMin="20" :marginMax="28">
|
||||||
<div v-if="note" class="_gaps">
|
<div v-if="note" class="_gaps">
|
||||||
<div v-if="reactions.length === 0" class="_fullinfo">
|
<div v-if="reactions.length === 0" class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
@ -42,6 +42,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import { userPage } from '@/filters/user';
|
import { userPage } from '@/filters/user';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'closed'): void,
|
(ev: 'closed'): void,
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<MkSpacer :marginMin="20" :marginMax="28">
|
<MkSpacer :marginMin="20" :marginMax="28">
|
||||||
<div v-if="renotes" class="_gaps">
|
<div v-if="renotes" class="_gaps">
|
||||||
<div v-if="renotes.length === 0" class="_fullinfo">
|
<div v-if="renotes.length === 0" class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
@ -35,6 +35,7 @@ import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import { userPage } from '@/filters/user';
|
import { userPage } from '@/filters/user';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'closed'): void,
|
(ev: 'closed'): void,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
import MkUserInfo from '@/components/MkUserInfo.vue';
|
import MkUserInfo from '@/components/MkUserInfo.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
|
<img :class="$style.img" :src="infoImageUrl" class="_ghost"/>
|
||||||
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
|
<p :class="$style.text"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.somethingHappened }}</p>
|
||||||
<MkButton :class="$style.button" @click="() => emit('retry')">{{ i18n.ts.retry }}</MkButton>
|
<MkButton :class="$style.button" @click="() => emit('retry')">{{ i18n.ts.retry }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'retry'): void;
|
(ev: 'retry'): void;
|
||||||
|
|
|
@ -78,3 +78,7 @@ export const ROLE_POLICIES = [
|
||||||
//export const CURRENT_STICKY_BOTTOM = Symbol('CURRENT_STICKY_BOTTOM');
|
//export const CURRENT_STICKY_BOTTOM = Symbol('CURRENT_STICKY_BOTTOM');
|
||||||
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
export const CURRENT_STICKY_TOP = 'CURRENT_STICKY_TOP';
|
||||||
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
export const CURRENT_STICKY_BOTTOM = 'CURRENT_STICKY_BOTTOM';
|
||||||
|
|
||||||
|
export const DEFAULT_SERVER_ERROR_IMAGE_URL = 'https://xn--931a.moe/assets/error.jpg';
|
||||||
|
export const DEFAULT_NOT_FOUND_IMAGE_URL = 'https://xn--931a.moe/assets/not-found.jpg';
|
||||||
|
export const DEFAULT_INFO_IMAGE_URL = 'https://xn--931a.moe/assets/info.jpg';
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { reactive } from 'vue';
|
import { computed, reactive } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { api } from './os';
|
import { api } from './os';
|
||||||
import { miLocalStorage } from './local-storage';
|
import { miLocalStorage } from './local-storage';
|
||||||
|
import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERROR_IMAGE_URL } from '@/const';
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
|
@ -13,6 +14,12 @@ export const instance: Misskey.entities.InstanceMetadata = reactive(cached ? JSO
|
||||||
// TODO: set default values
|
// TODO: set default values
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
|
||||||
|
|
||||||
|
export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO_IMAGE_URL);
|
||||||
|
|
||||||
|
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
||||||
|
|
||||||
export async function fetchInstance() {
|
export async function fetchInstance() {
|
||||||
const meta = await api('meta', {
|
const meta = await api('meta', {
|
||||||
detail: false,
|
detail: false,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<MkLoading v-if="!loaded"/>
|
<MkLoading v-if="!loaded"/>
|
||||||
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
<Transition :name="defaultStore.state.animation ? '_transition_zoom' : ''" appear>
|
||||||
<div v-show="loaded" :class="$style.root">
|
<div v-show="loaded" :class="$style.root">
|
||||||
<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost" :class="$style.img"/>
|
<img :src="serverErrorImageUrl" class="_ghost" :class="$style.img"/>
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p>
|
<p><b><i class="ti ti-alert-triangle"></i> {{ i18n.ts.pageLoadError }}</b></p>
|
||||||
<p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p>
|
<p v-if="meta && (version === meta.version)">{{ i18n.ts.pageLoadErrorDescription }}</p>
|
||||||
|
@ -30,6 +30,7 @@ import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import { miLocalStorage } from '@/local-storage';
|
import { miLocalStorage } from '@/local-storage';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
|
import { serverErrorImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
error?: Error;
|
error?: Error;
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<MkStickyContainer>
|
||||||
|
<template #header><XHeader :tabs="headerTabs"/></template>
|
||||||
|
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="32">
|
||||||
|
<FormSuspense :p="init">
|
||||||
|
<div class="_gaps_m">
|
||||||
|
<MkInput v-model="iconUrl">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.iconUrl }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkInput v-model="bannerUrl">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.bannerUrl }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkInput v-model="backgroundImageUrl">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.backgroundImageUrl }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkInput v-model="notFoundImageUrl">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.notFoundDescription }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkInput v-model="infoImageUrl">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.nothing }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkInput v-model="serverErrorImageUrl">
|
||||||
|
<template #prefix><i class="ti ti-link"></i></template>
|
||||||
|
<template #label>{{ i18n.ts.somethingHappened }}</template>
|
||||||
|
</MkInput>
|
||||||
|
|
||||||
|
<MkColorInput v-model="themeColor">
|
||||||
|
<template #label>{{ i18n.ts.themeColor }}</template>
|
||||||
|
</MkColorInput>
|
||||||
|
|
||||||
|
<MkTextarea v-model="defaultLightTheme">
|
||||||
|
<template #label>{{ i18n.ts.instanceDefaultLightTheme }}</template>
|
||||||
|
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
|
||||||
|
<MkTextarea v-model="defaultDarkTheme">
|
||||||
|
<template #label>{{ i18n.ts.instanceDefaultDarkTheme }}</template>
|
||||||
|
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
</div>
|
||||||
|
</FormSuspense>
|
||||||
|
</MkSpacer>
|
||||||
|
<template #footer>
|
||||||
|
<div :class="$style.footer">
|
||||||
|
<MkSpacer :contentMax="700" :marginMin="16" :marginMax="16">
|
||||||
|
<MkButton primary rounded @click="save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||||
|
</MkSpacer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</MkStickyContainer>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { } from 'vue';
|
||||||
|
import XHeader from './_header_.vue';
|
||||||
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
|
import MkInput from '@/components/MkInput.vue';
|
||||||
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
import FormSection from '@/components/form/section.vue';
|
||||||
|
import FormSplit from '@/components/form/split.vue';
|
||||||
|
import FormSuspense from '@/components/form/suspense.vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import { fetchInstance } from '@/instance';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import MkColorInput from '@/components/MkColorInput.vue';
|
||||||
|
|
||||||
|
let iconUrl: string | null = $ref(null);
|
||||||
|
let bannerUrl: string | null = $ref(null);
|
||||||
|
let backgroundImageUrl: string | null = $ref(null);
|
||||||
|
let themeColor: any = $ref(null);
|
||||||
|
let defaultLightTheme: any = $ref(null);
|
||||||
|
let defaultDarkTheme: any = $ref(null);
|
||||||
|
let serverErrorImageUrl: string | null = $ref(null);
|
||||||
|
let infoImageUrl: string | null = $ref(null);
|
||||||
|
let notFoundImageUrl: string | null = $ref(null);
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
const meta = await os.api('admin/meta');
|
||||||
|
iconUrl = meta.iconUrl;
|
||||||
|
bannerUrl = meta.bannerUrl;
|
||||||
|
backgroundImageUrl = meta.backgroundImageUrl;
|
||||||
|
themeColor = meta.themeColor;
|
||||||
|
defaultLightTheme = meta.defaultLightTheme;
|
||||||
|
defaultDarkTheme = meta.defaultDarkTheme;
|
||||||
|
serverErrorImageUrl = meta.serverErrorImageUrl;
|
||||||
|
infoImageUrl = meta.infoImageUrl;
|
||||||
|
notFoundImageUrl = meta.notFoundImageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
os.apiWithDialog('admin/update-meta', {
|
||||||
|
iconUrl,
|
||||||
|
bannerUrl,
|
||||||
|
backgroundImageUrl,
|
||||||
|
themeColor: themeColor === '' ? null : themeColor,
|
||||||
|
defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme,
|
||||||
|
defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme,
|
||||||
|
infoImageUrl,
|
||||||
|
notFoundImageUrl,
|
||||||
|
serverErrorImageUrl,
|
||||||
|
}).then(() => {
|
||||||
|
fetchInstance();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerTabs = $computed(() => []);
|
||||||
|
|
||||||
|
definePageMetadata({
|
||||||
|
title: i18n.ts.branding,
|
||||||
|
icon: 'ti ti-paint',
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.footer {
|
||||||
|
-webkit-backdrop-filter: var(--blur, blur(15px));
|
||||||
|
backdrop-filter: var(--blur, blur(15px));
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -143,6 +143,11 @@ const menuDef = $computed(() => [{
|
||||||
text: i18n.ts.general,
|
text: i18n.ts.general,
|
||||||
to: '/admin/settings',
|
to: '/admin/settings',
|
||||||
active: currentPage?.route.name === 'settings',
|
active: currentPage?.route.name === 'settings',
|
||||||
|
}, {
|
||||||
|
icon: 'ti ti-paint',
|
||||||
|
text: i18n.ts.branding,
|
||||||
|
to: '/admin/branding',
|
||||||
|
active: currentPage?.route.name === 'branding',
|
||||||
}, {
|
}, {
|
||||||
icon: 'ti ti-shield',
|
icon: 'ti ti-shield',
|
||||||
text: i18n.ts.moderation,
|
text: i18n.ts.moderation,
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<MkPagination :pagination="usersPagination">
|
<MkPagination :pagination="usersPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -69,6 +69,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
import MkPagination, { Paging } from '@/components/MkPagination.vue';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -29,41 +29,6 @@
|
||||||
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
|
<template #caption>{{ i18n.ts.pinnedUsersDescription }}</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
|
|
||||||
<FormSection>
|
|
||||||
<template #label>{{ i18n.ts.theme }}</template>
|
|
||||||
|
|
||||||
<div class="_gaps_m">
|
|
||||||
<MkInput v-model="iconUrl">
|
|
||||||
<template #prefix><i class="ti ti-link"></i></template>
|
|
||||||
<template #label>{{ i18n.ts.iconUrl }}</template>
|
|
||||||
</MkInput>
|
|
||||||
|
|
||||||
<MkInput v-model="bannerUrl">
|
|
||||||
<template #prefix><i class="ti ti-link"></i></template>
|
|
||||||
<template #label>{{ i18n.ts.bannerUrl }}</template>
|
|
||||||
</MkInput>
|
|
||||||
|
|
||||||
<MkInput v-model="backgroundImageUrl">
|
|
||||||
<template #prefix><i class="ti ti-link"></i></template>
|
|
||||||
<template #label>{{ i18n.ts.backgroundImageUrl }}</template>
|
|
||||||
</MkInput>
|
|
||||||
|
|
||||||
<MkColorInput v-model="themeColor">
|
|
||||||
<template #label>{{ i18n.ts.themeColor }}</template>
|
|
||||||
</MkColorInput>
|
|
||||||
|
|
||||||
<MkTextarea v-model="defaultLightTheme">
|
|
||||||
<template #label>{{ i18n.ts.instanceDefaultLightTheme }}</template>
|
|
||||||
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
|
|
||||||
</MkTextarea>
|
|
||||||
|
|
||||||
<MkTextarea v-model="defaultDarkTheme">
|
|
||||||
<template #label>{{ i18n.ts.instanceDefaultDarkTheme }}</template>
|
|
||||||
<template #caption>{{ i18n.ts.instanceDefaultThemeDescription }}</template>
|
|
||||||
</MkTextarea>
|
|
||||||
</div>
|
|
||||||
</FormSection>
|
|
||||||
|
|
||||||
<FormSection>
|
<FormSection>
|
||||||
<template #label>{{ i18n.ts.files }}</template>
|
<template #label>{{ i18n.ts.files }}</template>
|
||||||
|
|
||||||
|
@ -145,12 +110,6 @@ let name: string | null = $ref(null);
|
||||||
let description: string | null = $ref(null);
|
let description: string | null = $ref(null);
|
||||||
let maintainerName: string | null = $ref(null);
|
let maintainerName: string | null = $ref(null);
|
||||||
let maintainerEmail: string | null = $ref(null);
|
let maintainerEmail: string | null = $ref(null);
|
||||||
let iconUrl: string | null = $ref(null);
|
|
||||||
let bannerUrl: string | null = $ref(null);
|
|
||||||
let backgroundImageUrl: string | null = $ref(null);
|
|
||||||
let themeColor: any = $ref(null);
|
|
||||||
let defaultLightTheme: any = $ref(null);
|
|
||||||
let defaultDarkTheme: any = $ref(null);
|
|
||||||
let pinnedUsers: string = $ref('');
|
let pinnedUsers: string = $ref('');
|
||||||
let cacheRemoteFiles: boolean = $ref(false);
|
let cacheRemoteFiles: boolean = $ref(false);
|
||||||
let enableServiceWorker: boolean = $ref(false);
|
let enableServiceWorker: boolean = $ref(false);
|
||||||
|
@ -163,12 +122,6 @@ async function init() {
|
||||||
const meta = await os.api('admin/meta');
|
const meta = await os.api('admin/meta');
|
||||||
name = meta.name;
|
name = meta.name;
|
||||||
description = meta.description;
|
description = meta.description;
|
||||||
iconUrl = meta.iconUrl;
|
|
||||||
bannerUrl = meta.bannerUrl;
|
|
||||||
backgroundImageUrl = meta.backgroundImageUrl;
|
|
||||||
themeColor = meta.themeColor;
|
|
||||||
defaultLightTheme = meta.defaultLightTheme;
|
|
||||||
defaultDarkTheme = meta.defaultDarkTheme;
|
|
||||||
maintainerName = meta.maintainerName;
|
maintainerName = meta.maintainerName;
|
||||||
maintainerEmail = meta.maintainerEmail;
|
maintainerEmail = meta.maintainerEmail;
|
||||||
pinnedUsers = meta.pinnedUsers.join('\n');
|
pinnedUsers = meta.pinnedUsers.join('\n');
|
||||||
|
@ -184,12 +137,6 @@ function save() {
|
||||||
os.apiWithDialog('admin/update-meta', {
|
os.apiWithDialog('admin/update-meta', {
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
iconUrl,
|
|
||||||
bannerUrl,
|
|
||||||
backgroundImageUrl,
|
|
||||||
themeColor: themeColor === '' ? null : themeColor,
|
|
||||||
defaultLightTheme: defaultLightTheme === '' ? null : defaultLightTheme,
|
|
||||||
defaultDarkTheme: defaultDarkTheme === '' ? null : defaultDarkTheme,
|
|
||||||
maintainerName,
|
maintainerName,
|
||||||
maintainerEmail,
|
maintainerEmail,
|
||||||
pinnedUsers: pinnedUsers.split('\n'),
|
pinnedUsers: pinnedUsers.split('\n'),
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<MkPagination :pagination="pagination">
|
<MkPagination :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noNotes }}</div>
|
<div>{{ i18n.ts.noNotes }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -26,6 +26,7 @@ import MkNote from '@/components/MkNote.vue';
|
||||||
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
import MkDateSeparatedList from '@/components/MkDateSeparatedList.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const pagination = {
|
const pagination = {
|
||||||
endpoint: 'i/favorites' as const,
|
endpoint: 'i/favorites' as const,
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<MkPagination ref="paginationComponent" :pagination="pagination">
|
<MkPagination ref="paginationComponent" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noFollowRequests }}</div>
|
<div>{{ i18n.ts.noFollowRequests }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -39,6 +39,7 @@ import { userPage, acct } from '@/filters/user';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
const paginationComponent = shallowRef<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
|
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||||
<p :class="$style.text">
|
<p :class="$style.text">
|
||||||
<i class="ti ti-alert-triangle"></i>
|
<i class="ti ti-alert-triangle"></i>
|
||||||
{{ i18n.ts.nothing }}
|
{{ i18n.ts.nothing }}
|
||||||
|
@ -36,6 +36,7 @@ import { i18n } from '@/i18n';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
import { serverErrorImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/not-found.jpg" class="_ghost"/>
|
<img :src="notFoundImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.notFoundDescription }}</div>
|
<div>{{ i18n.ts.notFoundDescription }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
|
import { notFoundImageUrl } from '@/instance';
|
||||||
|
|
||||||
const headerActions = $computed(() => []);
|
const headerActions = $computed(() => []);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader v-model:tab="tab" :tabs="headerTabs"/></template>
|
||||||
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
<MKSpacer v-if="!(typeof error === 'undefined')" :contentMax="1200">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<img :class="$style.img" src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
|
<img :class="$style.img" :src="serverErrorImageUrl" class="_ghost"/>
|
||||||
<p :class="$style.text">
|
<p :class="$style.text">
|
||||||
<i class="ti ti-alert-triangle"></i>
|
<i class="ti ti-alert-triangle"></i>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
|
@ -30,6 +30,7 @@ import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import { instanceName } from '@/config';
|
import { instanceName } from '@/config';
|
||||||
|
import { serverErrorImageUrl } from '@/instance';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
role: string;
|
role: string;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<FormPagination ref="list" :pagination="pagination">
|
<FormPagination ref="list" :pagination="pagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -47,6 +47,7 @@ import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const list = ref<any>(null);
|
const list = ref<any>(null);
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<MkPagination :pagination="renoteMutingPagination">
|
<MkPagination :pagination="renoteMutingPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
<MkPagination :pagination="mutingPagination">
|
<MkPagination :pagination="mutingPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
<MkPagination :pagination="blockingPagination">
|
<MkPagination :pagination="blockingPagination">
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<div class="_fullinfo">
|
<div class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.noUsers }}</div>
|
<div>{{ i18n.ts.noUsers }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -107,6 +107,7 @@ import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
let tab = $ref('renoteMute');
|
let tab = $ref('renoteMute');
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,6 @@ const profile = reactive({
|
||||||
lang: $i.lang,
|
lang: $i.lang,
|
||||||
isBot: $i.isBot,
|
isBot: $i.isBot,
|
||||||
isCat: $i.isCat,
|
isCat: $i.isCat,
|
||||||
showTimelineReplies: $i.showTimelineReplies,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => profile, () => {
|
watch(() => profile, () => {
|
||||||
|
@ -151,7 +150,7 @@ while (fields.value.length < 4) {
|
||||||
addField();
|
addField();
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteField(index: number) {
|
function deleteField(index: number) {
|
||||||
fields.value.splice(index, 1);
|
fields.value.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +175,6 @@ function save() {
|
||||||
lang: profile.lang || null,
|
lang: profile.lang || null,
|
||||||
isBot: !!profile.isBot,
|
isBot: !!profile.isBot,
|
||||||
isCat: !!profile.isCat,
|
isCat: !!profile.isCat,
|
||||||
showTimelineReplies: !!profile.showTimelineReplies,
|
|
||||||
});
|
});
|
||||||
claimAchievement('profileFilled');
|
claimAchievement('profileFilled');
|
||||||
if (profile.name === 'syuilo' || profile.name === 'しゅいろ') {
|
if (profile.name === 'syuilo' || profile.name === 'しゅいろ') {
|
||||||
|
|
|
@ -392,6 +392,10 @@ export const routes = [{
|
||||||
path: '/settings',
|
path: '/settings',
|
||||||
name: 'settings',
|
name: 'settings',
|
||||||
component: page(() => import('./pages/admin/settings.vue')),
|
component: page(() => import('./pages/admin/settings.vue')),
|
||||||
|
}, {
|
||||||
|
path: '/branding',
|
||||||
|
name: 'branding',
|
||||||
|
component: page(() => import('./pages/admin/branding.vue')),
|
||||||
}, {
|
}, {
|
||||||
path: '/moderation',
|
path: '/moderation',
|
||||||
name: 'moderation',
|
name: 'moderation',
|
||||||
|
|
|
@ -254,6 +254,28 @@ async function deleteProfile() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: clip;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
overscroll-behavior: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#misskey_app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: clip;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.transition_menuDrawerBg_enterActive,
|
.transition_menuDrawerBg_enterActive,
|
||||||
.transition_menuDrawerBg_leaveActive {
|
.transition_menuDrawerBg_leaveActive {
|
||||||
|
|
|
@ -215,6 +215,28 @@ watch($$(navFooter), () => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: clip;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
overscroll-behavior: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#misskey_app {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: clip;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
$ui-font-size: 1em; // TODO: どこかに集約したい
|
$ui-font-size: 1em; // TODO: どこかに集約したい
|
||||||
$widgets-hide-threshold: 1090px;
|
$widgets-hide-threshold: 1090px;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<div class="ekmkgxbj">
|
<div class="ekmkgxbj">
|
||||||
<MkLoading v-if="fetching"/>
|
<MkLoading v-if="fetching"/>
|
||||||
<div v-else-if="(!items || items.length === 0) && widgetProps.showHeader" class="_fullinfo">
|
<div v-else-if="(!items || items.length === 0) && widgetProps.showHeader" class="_fullinfo">
|
||||||
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
|
<img :src="infoImageUrl" class="_ghost"/>
|
||||||
<div>{{ i18n.ts.nothing }}</div>
|
<div>{{ i18n.ts.nothing }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else :class="$style.feed">
|
<div v-else :class="$style.feed">
|
||||||
|
@ -25,6 +25,7 @@ import MkContainer from '@/components/MkContainer.vue';
|
||||||
import { url as base } from '@/config';
|
import { url as base } from '@/config';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { useInterval } from '@/scripts/use-interval';
|
import { useInterval } from '@/scripts/use-interval';
|
||||||
|
import { infoImageUrl } from '@/instance';
|
||||||
|
|
||||||
const name = 'rss';
|
const name = 'rss';
|
||||||
|
|
||||||
|
|
|
@ -294,7 +294,9 @@ export type LiteInstanceMetadata = {
|
||||||
themeColor: string | null;
|
themeColor: string | null;
|
||||||
mascotImageUrl: string | null;
|
mascotImageUrl: string | null;
|
||||||
bannerUrl: string | null;
|
bannerUrl: string | null;
|
||||||
errorImageUrl: string | null;
|
serverErrorImageUrl: string | null;
|
||||||
|
infoImageUrl: string | null;
|
||||||
|
notFoundImageUrl: string | null;
|
||||||
iconUrl: string | null;
|
iconUrl: string | null;
|
||||||
backgroundImageUrl: string | null;
|
backgroundImageUrl: string | null;
|
||||||
logoImageUrl: string | null;
|
logoImageUrl: string | null;
|
||||||
|
|
Loading…
Reference in New Issue