forked from FoundKeyGang/FoundKey
nanka iroiro (#6847)
* wip * wip * wip * wip * Update ja-JP.yml * wip * wip * wip
This commit is contained in:
parent
50e917d232
commit
0044d83801
30 changed files with 558 additions and 183 deletions
|
@ -316,6 +316,8 @@ bannerUrl: "バナー画像のURL"
|
||||||
basicInfo: "基本情報"
|
basicInfo: "基本情報"
|
||||||
pinnedUsers: "ピン留めユーザー"
|
pinnedUsers: "ピン留めユーザー"
|
||||||
pinnedUsersDescription: "「みつける」ページなどにピン留めしたいユーザーを改行で区切って記述します。"
|
pinnedUsersDescription: "「みつける」ページなどにピン留めしたいユーザーを改行で区切って記述します。"
|
||||||
|
pinnedPages: "ピン留めページ"
|
||||||
|
pinnedPagesDescription: "インスタンスのトップページにピン留めしたいページのパスを改行で区切って記述します。"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "hCaptchaを有効にする"
|
enableHcaptcha: "hCaptchaを有効にする"
|
||||||
hcaptchaSiteKey: "サイトキー"
|
hcaptchaSiteKey: "サイトキー"
|
||||||
|
@ -1117,6 +1119,7 @@ _pages:
|
||||||
unlike: "いいね解除"
|
unlike: "いいね解除"
|
||||||
my: "自分のページ"
|
my: "自分のページ"
|
||||||
liked: "いいねしたページ"
|
liked: "いいねしたページ"
|
||||||
|
featured: "人気"
|
||||||
inspector: "インスペクター"
|
inspector: "インスペクター"
|
||||||
contents: "コンテンツ"
|
contents: "コンテンツ"
|
||||||
content: "ページブロック"
|
content: "ページブロック"
|
||||||
|
|
14
migration/1605585339718-instance-pinned-pages.ts
Normal file
14
migration/1605585339718-instance-pinned-pages.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class instancePinnedPages1605585339718 implements MigrationInterface {
|
||||||
|
name = 'instancePinnedPages1605585339718'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "pinnedPages" character varying(512) array NOT NULL DEFAULT '{"/announcements", "/featured", "/channels", "/pages", "/explore", "/games/reversi", "/about-misskey"}'::varchar[]`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "pinnedPages"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
<MkError v-if="error" @retry="init()"/>
|
<MkError v-if="error" @retry="init()"/>
|
||||||
|
|
||||||
<div v-show="more && reversed" style="margin-bottom: var(--margin);">
|
<div v-show="more && reversed" style="margin-bottom: var(--margin);">
|
||||||
<button class="_loadMore" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
<button class="_loadMore" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
|
||||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||||
<template v-if="moreFetching"><MkLoading inline/></template>
|
<template v-if="moreFetching"><MkLoading inline/></template>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,26 +1,32 @@
|
||||||
<template>
|
|
||||||
<div class="pxhvhrfw" v-size="{ max: [500] }">
|
|
||||||
<button v-for="item in items" class="_button" @click="$emit('update:value', item.value)" :class="{ active: value === item.value }" :disabled="value === item.value" :key="item.value"><Fa v-if="item.icon" :icon="item.icon" class="icon"/>{{ item.label }}</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, h, resolveDirective, withDirectives } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
items: {
|
|
||||||
type: Array,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
value: {
|
value: {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
render() {
|
||||||
|
const options = this.$slots.default();
|
||||||
|
|
||||||
|
return withDirectives(h('div', {
|
||||||
|
class: 'pxhvhrfw',
|
||||||
|
}, options.map(option => h('button', {
|
||||||
|
class: ['_button', { active: this.value === option.props.value }],
|
||||||
|
key: option.props.value,
|
||||||
|
disabled: this.value === option.props.value,
|
||||||
|
onClick: () => {
|
||||||
|
this.$emit('update:value', option.props.value);
|
||||||
|
}
|
||||||
|
}, option.children))), [
|
||||||
|
[resolveDirective('size'), { max: [500] }]
|
||||||
|
]);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
.pxhvhrfw {
|
.pxhvhrfw {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,10 @@
|
||||||
<template #header>Req Viewer</template>
|
<template #header>Req Viewer</template>
|
||||||
|
|
||||||
<div class="rlkneywz">
|
<div class="rlkneywz">
|
||||||
<MkTab v-model:value="tab" :items="[{ label: 'Request', value: 'req', }, { label: 'Response', value: 'res', }]" style="border-bottom: solid 1px var(--divider);"/>
|
<MkTab v-model:value="tab" style="border-bottom: solid 1px var(--divider);">
|
||||||
|
<option value="req">Request</option>
|
||||||
|
<option value="res">Response</option>
|
||||||
|
</MkTab>
|
||||||
|
|
||||||
<code v-if="tab === 'req'">{{ reqStr }}</code>
|
<code v-if="tab === 'req'">{{ reqStr }}</code>
|
||||||
<code v-if="tab === 'res'">{{ resStr }}</code>
|
<code v-if="tab === 'res'">{{ resStr }}</code>
|
||||||
|
|
|
@ -4,7 +4,12 @@
|
||||||
<Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager
|
<Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager
|
||||||
</template>
|
</template>
|
||||||
<div class="qljqmnzj">
|
<div class="qljqmnzj">
|
||||||
<MkTab v-model:value="tab" :items="[{ label: 'Windows', value: 'windows', }, { label: 'Stream', value: 'stream', }, { label: 'Stream (Pool)', value: 'streamPool', }, { label: 'API', value: 'api', }]" style="border-bottom: solid 1px var(--divider);"/>
|
<MkTab v-model:value="tab" style="border-bottom: solid 1px var(--divider);">
|
||||||
|
<option value="windows">Windows</option>
|
||||||
|
<option value="stream">Stream</option>
|
||||||
|
<option value="streamPool">Stream (Pool)</option>
|
||||||
|
<option value="api">API</option>
|
||||||
|
</MkTab>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div v-if="tab === 'windows'" class="windows" v-follow>
|
<div v-if="tab === 'windows'" class="windows" v-follow>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<XPostForm :channel="channel" class="post-form _content _panel _vMargin" fixed/>
|
<XPostForm :channel="channel" class="post-form _content _panel _vMargin" fixed v-if="this.$store.getters.isSignedIn"/>
|
||||||
|
|
||||||
<XTimeline class="_content _vMargin" src="channel" :channel="channelId" @before="before" @after="after"/>
|
<XTimeline class="_content _vMargin" src="channel" :channel="channelId" @before="before" @after="after"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,26 +1,30 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="_section" style="padding: 0;">
|
<div class="_section" style="padding: 0;" v-if="this.$store.getters.isSignedIn">
|
||||||
<MkTab class="_content" v-model:value="tab" :items="[{ label: $t('_channel.featured'), value: 'featured', icon: faFireAlt }, { label: $t('_channel.following'), value: 'following', icon: faHeart }, { label: $t('_channel.owned'), value: 'owned', icon: faEdit }]"/>
|
<MkTab class="_content" v-model:value="tab">
|
||||||
|
<option value="featured"><Fa :icon="faFireAlt"/> {{ $t('_channel.featured') }}</option>
|
||||||
|
<option value="following"><Fa :icon="faHeart"/> {{ $t('_channel.following') }}</option>
|
||||||
|
<option value="owned"><Fa :icon="faEdit"/> {{ $t('_channel.owned') }}</option>
|
||||||
|
</MkTab>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<div class="_content grwlizim featured" v-if="tab === 'featured'">
|
<div class="_content grwlizim featured" v-if="tab === 'featured'">
|
||||||
<MkPagination :pagination="featuredPagination" #default="{items}">
|
<MkPagination :pagination="featuredPagination" #default="{items}">
|
||||||
<MkChannelPreview v-for="channel in items" class="uveselbe" :channel="channel" :key="channel.id"/>
|
<MkChannelPreview v-for="channel in items" class="_vMargin" :channel="channel" :key="channel.id"/>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_content grwlizim following" v-if="tab === 'following'">
|
<div class="_content grwlizim following" v-if="tab === 'following'">
|
||||||
<MkPagination :pagination="followingPagination" #default="{items}">
|
<MkPagination :pagination="followingPagination" #default="{items}">
|
||||||
<MkChannelPreview v-for="channel in items" class="uveselbe" :channel="channel" :key="channel.id"/>
|
<MkChannelPreview v-for="channel in items" class="_vMargin" :channel="channel" :key="channel.id"/>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_content grwlizim owned" v-if="tab === 'owned'">
|
<div class="_content grwlizim owned" v-if="tab === 'owned'">
|
||||||
<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
|
<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
|
||||||
<MkPagination :pagination="ownedPagination" #default="{items}">
|
<MkPagination :pagination="ownedPagination" #default="{items}">
|
||||||
<MkChannelPreview v-for="channel in items" class="uveselbe" :channel="channel" :key="channel.id"/>
|
<MkChannelPreview v-for="channel in items" class="_vMargin" :channel="channel" :key="channel.id"/>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,7 +48,11 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
title: this.$t('channel'),
|
title: this.$t('channel'),
|
||||||
icon: faSatelliteDish
|
icon: faSatelliteDish,
|
||||||
|
action: {
|
||||||
|
icon: faPlus,
|
||||||
|
handler: this.create
|
||||||
|
}
|
||||||
},
|
},
|
||||||
tab: 'featured',
|
tab: 'featured',
|
||||||
featuredPagination: {
|
featuredPagination: {
|
||||||
|
@ -69,23 +77,3 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.grwlizim {
|
|
||||||
padding: 16px 0;
|
|
||||||
|
|
||||||
&.my .uveselbe:first-child {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.uveselbe:not(:last-child) {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 500px) {
|
|
||||||
.uveselbe:not(:last-child) {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-instance-emojis">
|
<div class="mk-instance-emojis">
|
||||||
<div class="_section" style="padding: 0;">
|
<div class="_section" style="padding: 0;">
|
||||||
<MkTab v-model:value="tab" :items="[{ label: $t('local'), value: 'local' }, { label: $t('remote'), value: 'remote' }]"/>
|
<MkTab v-model:value="tab">
|
||||||
|
<option value="local">{{ $t('local') }}</option>
|
||||||
|
<option value="remote">{{ $t('remote') }}</option>
|
||||||
|
</MkTab>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="meta">
|
<div v-if="meta" class="_section">
|
||||||
<section class="_section info">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faInfoCircle"/> {{ $t('basicInfo') }}</div>
|
<div class="_title"><Fa :icon="faInfoCircle"/> {{ $t('basicInfo') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkInput v-model:value="name">{{ $t('instanceName') }}</MkInput>
|
<MkInput v-model:value="name">{{ $t('instanceName') }}</MkInput>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section info">
|
<section class="_card _vMargin">
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkInput v-model:value="maxNoteTextLength" type="number" :save="() => save()"><template #icon><Fa :icon="faPencilAlt"/></template>{{ $t('maxNoteTextLength') }}</MkInput>
|
<MkInput v-model:value="maxNoteTextLength" type="number" :save="() => save()"><template #icon><Fa :icon="faPencilAlt"/></template>{{ $t('maxNoteTextLength') }}</MkInput>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section info">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faUser"/> {{ $t('registration') }}</div>
|
<div class="_title"><Fa :icon="faUser"/> {{ $t('registration') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="enableRegistration" @update:value="save()">{{ $t('enableRegistration') }}</MkSwitch>
|
<MkSwitch v-model:value="enableRegistration" @update:value="save()">{{ $t('enableRegistration') }}</MkSwitch>
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faShieldAlt"/> {{ $t('hcaptcha') }}</div>
|
<div class="_title"><Fa :icon="faShieldAlt"/> {{ $t('hcaptcha') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="enableHcaptcha">{{ $t('enableHcaptcha') }}</MkSwitch>
|
<MkSwitch v-model:value="enableHcaptcha">{{ $t('enableHcaptcha') }}</MkSwitch>
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faShieldAlt"/> {{ $t('recaptcha') }}</div>
|
<div class="_title"><Fa :icon="faShieldAlt"/> {{ $t('recaptcha') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="enableRecaptcha" ref="enableRecaptcha">{{ $t('enableRecaptcha') }}</MkSwitch>
|
<MkSwitch v-model:value="enableRecaptcha" ref="enableRecaptcha">{{ $t('enableRecaptcha') }}</MkSwitch>
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faEnvelope" /> {{ $t('emailConfig') }}</div>
|
<div class="_title"><Fa :icon="faEnvelope" /> {{ $t('emailConfig') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="enableEmail" @update:value="save()">{{ $t('enableEmail') }}<template #desc>{{ $t('emailConfigInfo') }}</template></MkSwitch>
|
<MkSwitch v-model:value="enableEmail" @update:value="save()">{{ $t('enableEmail') }}<template #desc>{{ $t('emailConfigInfo') }}</template></MkSwitch>
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faBolt"/> {{ $t('serviceworker') }}</div>
|
<div class="_title"><Fa :icon="faBolt"/> {{ $t('serviceworker') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="enableServiceWorker">{{ $t('enableServiceworker') }}<template #desc>{{ $t('serviceworkerInfo') }}</template></MkSwitch>
|
<MkSwitch v-model:value="enableServiceWorker">{{ $t('enableServiceworker') }}<template #desc>{{ $t('serviceworkerInfo') }}</template></MkSwitch>
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faThumbtack"/> {{ $t('pinnedUsers') }}</div>
|
<div class="_title"><Fa :icon="faThumbtack"/> {{ $t('pinnedUsers') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkTextarea v-model:value="pinnedUsers">
|
<MkTextarea v-model:value="pinnedUsers">
|
||||||
|
@ -125,7 +125,19 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
|
<div class="_title"><Fa :icon="faThumbtack"/> {{ $t('pinnedPages') }}</div>
|
||||||
|
<div class="_content">
|
||||||
|
<MkTextarea v-model:value="pinnedPages">
|
||||||
|
<template #desc>{{ $t('pinnedPagesDescription') }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
</div>
|
||||||
|
<div class="_footer">
|
||||||
|
<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faCloud"/> {{ $t('files') }}</div>
|
<div class="_title"><Fa :icon="faCloud"/> {{ $t('files') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="cacheRemoteFiles">{{ $t('cacheRemoteFiles') }}<template #desc>{{ $t('cacheRemoteFilesDescription') }}</template></MkSwitch>
|
<MkSwitch v-model:value="cacheRemoteFiles">{{ $t('cacheRemoteFiles') }}<template #desc>{{ $t('cacheRemoteFilesDescription') }}</template></MkSwitch>
|
||||||
|
@ -138,7 +150,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faCloud"/> {{ $t('objectStorage') }}</div>
|
<div class="_title"><Fa :icon="faCloud"/> {{ $t('objectStorage') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="useObjectStorage">{{ $t('useObjectStorage') }}</MkSwitch>
|
<MkSwitch v-model:value="useObjectStorage">{{ $t('useObjectStorage') }}</MkSwitch>
|
||||||
|
@ -166,7 +178,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faGhost"/> {{ $t('proxyAccount') }}</div>
|
<div class="_title"><Fa :icon="faGhost"/> {{ $t('proxyAccount') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkInput :value="proxyAccount ? proxyAccount.username : null" disabled><template #prefix>@</template>{{ $t('proxyAccount') }}<template #desc>{{ $t('proxyAccountDescription') }}</template></MkInput>
|
<MkInput :value="proxyAccount ? proxyAccount.username : null" disabled><template #prefix>@</template>{{ $t('proxyAccount') }}<template #desc>{{ $t('proxyAccountDescription') }}</template></MkInput>
|
||||||
|
@ -174,7 +186,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faBan"/> {{ $t('blockedInstances') }}</div>
|
<div class="_title"><Fa :icon="faBan"/> {{ $t('blockedInstances') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkTextarea v-model:value="blockedHosts">
|
<MkTextarea v-model:value="blockedHosts">
|
||||||
|
@ -186,7 +198,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faShareAlt"/> {{ $t('integration') }}</div>
|
<div class="_title"><Fa :icon="faShareAlt"/> {{ $t('integration') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<header><Fa :icon="faTwitter"/> Twitter</header>
|
<header><Fa :icon="faTwitter"/> Twitter</header>
|
||||||
|
@ -220,7 +232,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="_section">
|
<section class="_card _vMargin">
|
||||||
<div class="_title"><Fa :icon="faArchway" /> Summaly Proxy</div>
|
<div class="_title"><Fa :icon="faArchway" /> Summaly Proxy</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkInput v-model:value="summalyProxy">URL</MkInput>
|
<MkInput v-model:value="summalyProxy">URL</MkInput>
|
||||||
|
@ -260,6 +272,7 @@ export default defineComponent({
|
||||||
title: this.$t('instance'),
|
title: this.$t('instance'),
|
||||||
icon: faCog,
|
icon: faCog,
|
||||||
},
|
},
|
||||||
|
meta: null,
|
||||||
url,
|
url,
|
||||||
proxyAccount: null,
|
proxyAccount: null,
|
||||||
proxyAccountId: null,
|
proxyAccountId: null,
|
||||||
|
@ -269,6 +282,7 @@ export default defineComponent({
|
||||||
remoteDriveCapacityMb: 0,
|
remoteDriveCapacityMb: 0,
|
||||||
blockedHosts: '',
|
blockedHosts: '',
|
||||||
pinnedUsers: '',
|
pinnedUsers: '',
|
||||||
|
pinnedPages: '',
|
||||||
maintainerName: null,
|
maintainerName: null,
|
||||||
maintainerEmail: null,
|
maintainerEmail: null,
|
||||||
name: null,
|
name: null,
|
||||||
|
@ -323,13 +337,9 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
async created() {
|
||||||
meta() {
|
this.meta = await os.api('meta', { detail: true });
|
||||||
return this.$store.state.instance.meta;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.name = this.meta.name;
|
this.name = this.meta.name;
|
||||||
this.description = this.meta.description;
|
this.description = this.meta.description;
|
||||||
this.tosUrl = this.meta.tosUrl;
|
this.tosUrl = this.meta.tosUrl;
|
||||||
|
@ -356,6 +366,7 @@ export default defineComponent({
|
||||||
this.remoteDriveCapacityMb = this.meta.driveCapacityPerRemoteUserMb;
|
this.remoteDriveCapacityMb = this.meta.driveCapacityPerRemoteUserMb;
|
||||||
this.blockedHosts = this.meta.blockedHosts.join('\n');
|
this.blockedHosts = this.meta.blockedHosts.join('\n');
|
||||||
this.pinnedUsers = this.meta.pinnedUsers.join('\n');
|
this.pinnedUsers = this.meta.pinnedUsers.join('\n');
|
||||||
|
this.pinnedPages = this.meta.pinnedPages.join('\n');
|
||||||
this.enableServiceWorker = this.meta.enableServiceWorker;
|
this.enableServiceWorker = this.meta.enableServiceWorker;
|
||||||
this.swPublicKey = this.meta.swPublickey;
|
this.swPublicKey = this.meta.swPublickey;
|
||||||
this.swPrivateKey = this.meta.swPrivateKey;
|
this.swPrivateKey = this.meta.swPrivateKey;
|
||||||
|
@ -506,6 +517,7 @@ export default defineComponent({
|
||||||
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
|
remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
|
||||||
blockedHosts: this.blockedHosts.split('\n') || [],
|
blockedHosts: this.blockedHosts.split('\n') || [],
|
||||||
pinnedUsers: this.pinnedUsers ? this.pinnedUsers.split('\n') : [],
|
pinnedUsers: this.pinnedUsers ? this.pinnedUsers.split('\n') : [],
|
||||||
|
pinnedPages: this.pinnedPages ? this.pinnedPages.split('\n') : [],
|
||||||
enableServiceWorker: this.enableServiceWorker,
|
enableServiceWorker: this.enableServiceWorker,
|
||||||
swPublicKey: this.swPublicKey,
|
swPublicKey: this.swPublicKey,
|
||||||
swPrivateKey: this.swPrivateKey,
|
swPrivateKey: this.swPrivateKey,
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="">
|
<div class="">
|
||||||
<div class="_section" style="padding: 0;">
|
<div class="_section" style="padding: 0;">
|
||||||
<MkTab v-model:value="tab" :items="[{ label: $t('ownedGroups'), value: 'owned' }, { label: $t('joinedGroups'), value: 'joined' }, { label: $t('invites'), icon: faEnvelopeOpenText, value: 'invites' }]"/>
|
<MkTab v-model:value="tab">
|
||||||
|
<option value="owned">{{ $t('ownedGroups') }}</option>
|
||||||
|
<option value="joined">{{ $t('joinedGroups') }}</option>
|
||||||
|
<option value="invites"><Fa :icon="faEnvelopeOpenText"/> {{ $t('invites') }}</option>
|
||||||
|
</MkTab>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
|
|
|
@ -1,21 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="fcuexfpr">
|
<div class="fcuexfpr">
|
||||||
<div v-if="note" class="note">
|
<div v-if="note" class="note">
|
||||||
<div class="_section">
|
<div class="_section" v-if="showNext">
|
||||||
<XNotes v-if="showNext" class="_content" :pagination="next"/>
|
<XNotes class="_content" :pagination="next"/>
|
||||||
<MkButton v-else-if="hasNext" class="load _content" @click="showNext = true"><Fa :icon="faChevronUp"/></MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section main">
|
||||||
<div class="_content">
|
<MkButton v-if="!showNext && hasNext" class="load next _content" @click="showNext = true"><Fa :icon="faChevronUp"/></MkButton>
|
||||||
|
<div class="_content _vMargin">
|
||||||
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_vMargin"/>
|
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_vMargin"/>
|
||||||
<XNote v-model:note="note" :key="note.id" :detail="true" class="_vMargin"/>
|
<XNote v-model:note="note" :key="note.id" :detail="true" class="_vMargin"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="_content clips _vMargin" v-if="clips && clips.length > 0">
|
||||||
|
<div class="title">{{ $t('clip') }}</div>
|
||||||
|
<MkA v-for="item in clips" :key="item.id" :to="`/clips/${item.id}`" class="item _panel _vMargin">
|
||||||
|
<b>{{ item.name }}</b>
|
||||||
|
<div v-if="item.description" class="description">{{ item.description }}</div>
|
||||||
|
<div class="user">
|
||||||
|
<MkAvatar :user="item.user" class="avatar"/> <MkUserName :user="item.user" :nowrap="false"/>
|
||||||
|
</div>
|
||||||
|
</MkA>
|
||||||
|
</div>
|
||||||
|
<MkButton v-if="!showPrev && hasPrev" class="load prev _content" @click="showPrev = true"><Fa :icon="faChevronDown"/></MkButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section" v-if="showPrev">
|
||||||
<XNotes v-if="showPrev" class="_content" :pagination="prev"/>
|
<XNotes class="_content" :pagination="prev"/>
|
||||||
<MkButton v-else-if="hasPrev" class="load _content" @click="showPrev = true"><Fa :icon="faChevronDown"/></MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -28,7 +38,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from 'vue';
|
import { computed, defineComponent } from 'vue';
|
||||||
import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||||
import Progress from '@/scripts/loading';
|
|
||||||
import XNote from '@/components/note.vue';
|
import XNote from '@/components/note.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import MkRemoteCaution from '@/components/remote-caution.vue';
|
import MkRemoteCaution from '@/components/remote-caution.vue';
|
||||||
|
@ -55,6 +64,7 @@ export default defineComponent({
|
||||||
avatar: this.note.user,
|
avatar: this.note.user,
|
||||||
} : null),
|
} : null),
|
||||||
note: null,
|
note: null,
|
||||||
|
clips: null,
|
||||||
hasPrev: false,
|
hasPrev: false,
|
||||||
hasNext: false,
|
hasNext: false,
|
||||||
showPrev: false,
|
showPrev: false,
|
||||||
|
@ -88,11 +98,13 @@ export default defineComponent({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
fetch() {
|
fetch() {
|
||||||
Progress.start();
|
|
||||||
os.api('notes/show', {
|
os.api('notes/show', {
|
||||||
noteId: this.noteId
|
noteId: this.noteId
|
||||||
}).then(note => {
|
}).then(note => {
|
||||||
Promise.all([
|
Promise.all([
|
||||||
|
os.api('notes/clips', {
|
||||||
|
noteId: note.id,
|
||||||
|
}),
|
||||||
os.api('users/notes', {
|
os.api('users/notes', {
|
||||||
userId: note.userId,
|
userId: note.userId,
|
||||||
untilId: note.id,
|
untilId: note.id,
|
||||||
|
@ -103,15 +115,14 @@ export default defineComponent({
|
||||||
sinceId: note.id,
|
sinceId: note.id,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
}),
|
}),
|
||||||
]).then(([prev, next]) => {
|
]).then(([clips, prev, next]) => {
|
||||||
|
this.clips = clips;
|
||||||
this.hasPrev = prev.length !== 0;
|
this.hasPrev = prev.length !== 0;
|
||||||
this.hasNext = next.length !== 0;
|
this.hasNext = next.length !== 0;
|
||||||
this.note = note;
|
this.note = note;
|
||||||
});
|
});
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
this.error = e;
|
this.error = e;
|
||||||
}).finally(() => {
|
|
||||||
Progress.done();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,10 +132,46 @@ export default defineComponent({
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.fcuexfpr {
|
.fcuexfpr {
|
||||||
> .note {
|
> .note {
|
||||||
> ._section {
|
> .main {
|
||||||
> .load {
|
> .load {
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border-radius: 999px;
|
border-radius: 999px;
|
||||||
|
|
||||||
|
&.next {
|
||||||
|
margin-bottom: var(--margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.prev {
|
||||||
|
margin-top: var(--margin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .clips {
|
||||||
|
> .title {
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .item {
|
||||||
|
display: block;
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
> .description {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .user {
|
||||||
|
$height: 32px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: solid 1px var(--divider);
|
||||||
|
line-height: $height;
|
||||||
|
|
||||||
|
> .avatar {
|
||||||
|
width: $height;
|
||||||
|
height: $height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ export default defineComponent({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
text: this.$t('_pages.created')
|
text: this.$t('_pages.created')
|
||||||
});
|
});
|
||||||
this.$router.push(`/my/pages/edit/${this.pageId}`);
|
this.$router.push(`/pages/edit/${this.pageId}`);
|
||||||
}).catch(onError);
|
}).catch(onError);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -296,7 +296,7 @@ export default defineComponent({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
text: this.$t('_pages.deleted')
|
text: this.$t('_pages.deleted')
|
||||||
});
|
});
|
||||||
this.$router.push(`/my/pages`);
|
this.$router.push(`/pages`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkA :to="`./${page.name}/view-source`" class="link">{{ $t('_pages.viewSource') }}</MkA>
|
<MkA :to="`./${page.name}/view-source`" class="link">{{ $t('_pages.viewSource') }}</MkA>
|
||||||
<template v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId">
|
<template v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId">
|
||||||
<MkA :to="`/my/pages/edit/${page.id}`" class="link">{{ $t('_pages.editThisPage') }}</MkA>
|
<MkA :to="`/pages/edit/${page.id}`" class="link">{{ $t('_pages.editThisPage') }}</MkA>
|
||||||
<button v-if="$store.state.i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $t('unpin') }}</button>
|
<button v-if="$store.state.i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $t('unpin') }}</button>
|
||||||
<button v-else @click="pin(true)" class="link _textButton">{{ $t('pin') }}</button>
|
<button v-else @click="pin(true)" class="link _textButton">{{ $t('pin') }}</button>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<MkTab v-model:value="tab" :items="[{ label: $t('_pages.my'), value: 'my', icon: faEdit }, { label: $t('_pages.liked'), value: 'liked', icon: faHeart }]"/>
|
<MkTab v-model:value="tab" v-if="this.$store.getters.isSignedIn">
|
||||||
|
<option value="featured"><Fa :icon="faFireAlt"/> {{ $t('_pages.featured') }}</option>
|
||||||
|
<option value="my"><Fa :icon="faEdit"/> {{ $t('_pages.my') }}</option>
|
||||||
|
<option value="liked"><Fa :icon="faHeart"/> {{ $t('_pages.liked') }}</option>
|
||||||
|
</MkTab>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
|
<div class="rknalgpo _content" v-if="tab === 'featured'">
|
||||||
|
<MkPagination :pagination="featuredPagesPagination" #default="{items}">
|
||||||
|
<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
|
||||||
|
</MkPagination>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="rknalgpo _content my" v-if="tab === 'my'">
|
<div class="rknalgpo _content my" v-if="tab === 'my'">
|
||||||
<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
|
<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
|
||||||
<MkPagination :pagination="myPagesPagination" #default="{items}">
|
<MkPagination :pagination="myPagesPagination" #default="{items}">
|
||||||
|
@ -21,7 +31,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faPlus, faEdit } from '@fortawesome/free-solid-svg-icons';
|
import { faPlus, faEdit, faFireAlt } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faStickyNote, faHeart } from '@fortawesome/free-regular-svg-icons';
|
import { faStickyNote, faHeart } from '@fortawesome/free-regular-svg-icons';
|
||||||
import MkPagePreview from '@/components/page-preview.vue';
|
import MkPagePreview from '@/components/page-preview.vue';
|
||||||
import MkPagination from '@/components/ui/pagination.vue';
|
import MkPagination from '@/components/ui/pagination.vue';
|
||||||
|
@ -42,7 +52,11 @@ export default defineComponent({
|
||||||
handler: this.create
|
handler: this.create
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tab: 'my',
|
tab: 'featured',
|
||||||
|
featuredPagesPagination: {
|
||||||
|
endpoint: 'pages/featured',
|
||||||
|
noPaging: true,
|
||||||
|
},
|
||||||
myPagesPagination: {
|
myPagesPagination: {
|
||||||
endpoint: 'i/pages',
|
endpoint: 'i/pages',
|
||||||
limit: 5,
|
limit: 5,
|
||||||
|
@ -51,12 +65,12 @@ export default defineComponent({
|
||||||
endpoint: 'i/page-likes',
|
endpoint: 'i/page-likes',
|
||||||
limit: 5,
|
limit: 5,
|
||||||
},
|
},
|
||||||
faStickyNote, faPlus, faEdit, faHeart
|
faStickyNote, faPlus, faEdit, faHeart, faFireAlt
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
create() {
|
create() {
|
||||||
this.$router.push(`/my/pages/new`);
|
this.$router.push(`/pages/new`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<section class="rrfwjxfl _section">
|
<section class="rrfwjxfl _section">
|
||||||
<MkTab v-model:value="tab" :items="[{ label: $t('mutedUsers'), value: 'mute' }, { label: $t('blockedUsers'), value: 'block' }]" style="margin-bottom: var(--margin);"/>
|
<MkTab v-model:value="tab" style="margin-bottom: var(--margin);">
|
||||||
|
<option value="mute">{{ $t('mutedUsers') }}</option>
|
||||||
|
<option value="block">{{ $t('blockedUsers') }}</option>
|
||||||
|
</MkTab>
|
||||||
<div class="_content" v-if="tab === 'mute'">
|
<div class="_content" v-if="tab === 'mute'">
|
||||||
<MkPagination :pagination="mutingPagination" class="muting">
|
<MkPagination :pagination="mutingPagination" class="muting">
|
||||||
<template #empty><MkInfo>{{ $t('noUsers') }}</MkInfo></template>
|
<template #empty><MkInfo>{{ $t('noUsers') }}</MkInfo></template>
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<div class="_card">
|
<div class="_card">
|
||||||
<MkTab v-model:value="tab" :items="[{ label: $t('_wordMute.soft'), value: 'soft' }, { label: $t('_wordMute.hard'), value: 'hard' }]"/>
|
<MkTab v-model:value="tab">
|
||||||
|
<option value="soft">{{ $t('_wordMute.soft') }}</option>
|
||||||
|
<option value="hard">{{ $t('_wordMute.hard') }}</option>
|
||||||
|
</MkTab>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<div v-show="tab === 'soft'">
|
<div v-show="tab === 'soft'">
|
||||||
<MkInfo>{{ $t('_wordMute.softDescription') }}</MkInfo>
|
<MkInfo>{{ $t('_wordMute.softDescription') }}</MkInfo>
|
||||||
|
|
141
src/client/pages/welcome.entrance.block.vue
Normal file
141
src/client/pages/welcome.entrance.block.vue
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
<template>
|
||||||
|
<div class="xyeqzsjl _panel">
|
||||||
|
<header>
|
||||||
|
<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
|
||||||
|
<XHeader class="title" :info="pageInfo" :with-back="false"/>
|
||||||
|
</header>
|
||||||
|
<div>
|
||||||
|
<component :is="component" v-bind="props" :ref="changePage"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { faChevronLeft } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import XWindow from '@/components/ui/window.vue';
|
||||||
|
import XHeader from '@/ui/_common_/header.vue';
|
||||||
|
import { popout } from '@/scripts/popout';
|
||||||
|
import { resolve } from '@/router';
|
||||||
|
import { url } from '@/config';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XWindow,
|
||||||
|
XHeader,
|
||||||
|
},
|
||||||
|
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
navHook: (path) => {
|
||||||
|
this.navigate(path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
initialPath: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageInfo: null,
|
||||||
|
path: this.initialPath,
|
||||||
|
component: null,
|
||||||
|
props: null,
|
||||||
|
history: [],
|
||||||
|
faChevronLeft,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
url(): string {
|
||||||
|
return url + this.path;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
const { component, props } = resolve(this.initialPath);
|
||||||
|
this.component = component;
|
||||||
|
this.props = props;
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
changePage(page) {
|
||||||
|
if (page == null) return;
|
||||||
|
if (page.INFO) {
|
||||||
|
this.pageInfo = page.INFO;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
navigate(path, record = true) {
|
||||||
|
if (record) this.history.push(this.path);
|
||||||
|
this.path = path;
|
||||||
|
const { component, props } = resolve(path);
|
||||||
|
this.component = component;
|
||||||
|
this.props = props;
|
||||||
|
},
|
||||||
|
|
||||||
|
back() {
|
||||||
|
this.navigate(this.history.pop(), false);
|
||||||
|
},
|
||||||
|
|
||||||
|
expand() {
|
||||||
|
this.$router.push(this.path);
|
||||||
|
this.$refs.window.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
popout() {
|
||||||
|
popout(this.path, this.$el);
|
||||||
|
this.$refs.window.close();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.xyeqzsjl {
|
||||||
|
--section-padding: 16px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
contain: content;
|
||||||
|
|
||||||
|
> header {
|
||||||
|
$height: 50px;
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
height: $height;
|
||||||
|
line-height: $height;
|
||||||
|
box-shadow: 0px 1px var(--divider);
|
||||||
|
|
||||||
|
> button {
|
||||||
|
height: $height;
|
||||||
|
width: $height;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--fgHighlighted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
line-height: $height;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> div {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,18 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="rsqzvsbo">
|
<div class="rsqzvsbo _section" v-if="meta">
|
||||||
<div class="_section">
|
<div class="about">
|
||||||
<div class="_content _panel about" v-if="meta">
|
<h1>{{ instanceName }}</h1>
|
||||||
<div class="body">
|
|
||||||
<div class="desc" v-html="meta.description || $t('introMisskey')"></div>
|
<div class="desc" v-html="meta.description || $t('introMisskey')"></div>
|
||||||
<MkButton @click="signup()" style="display: inline-block; margin-right: 16px;" primary>{{ $t('signup') }}</MkButton>
|
<MkButton @click="signup()" style="display: inline-block; margin-right: 16px;" primary>{{ $t('signup') }}</MkButton>
|
||||||
<MkButton @click="signin()" style="display: inline-block;">{{ $t('login') }}</MkButton>
|
<MkButton @click="signin()" style="display: inline-block;">{{ $t('login') }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="blocks">
|
||||||
</div>
|
<XBlock class="block" v-for="path in meta.pinnedPages" :initial-path="path" :key="path"/>
|
||||||
<div class="_section">
|
|
||||||
<div class="_content">
|
|
||||||
<XNotes :pagination="featuredPagination"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -24,33 +19,30 @@ import XSigninDialog from '@/components/signin-dialog.vue';
|
||||||
import XSignupDialog from '@/components/signup-dialog.vue';
|
import XSignupDialog from '@/components/signup-dialog.vue';
|
||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import XNotes from '@/components/notes.vue';
|
import XNotes from '@/components/notes.vue';
|
||||||
import { host } from '@/config';
|
import XBlock from './welcome.entrance.block.vue';
|
||||||
|
import { host, instanceName } from '@/config';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
MkButton,
|
MkButton,
|
||||||
XNotes,
|
XNotes,
|
||||||
|
XBlock,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
featuredPagination: {
|
|
||||||
endpoint: 'notes/featured',
|
|
||||||
limit: 10,
|
|
||||||
noPaging: true,
|
|
||||||
},
|
|
||||||
host: toUnicode(host),
|
host: toUnicode(host),
|
||||||
|
instanceName,
|
||||||
|
meta: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
|
||||||
meta() {
|
|
||||||
return this.$store.state.instance.meta;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
|
os.api('meta', { detail: true }).then(meta => {
|
||||||
|
this.meta = meta;
|
||||||
|
});
|
||||||
|
|
||||||
os.api('stats').then(stats => {
|
os.api('stats').then(stats => {
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
});
|
});
|
||||||
|
@ -74,15 +66,42 @@ export default defineComponent({
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.rsqzvsbo {
|
.rsqzvsbo {
|
||||||
> ._section {
|
text-align: center;
|
||||||
> .about {
|
|
||||||
> .body {
|
|
||||||
padding: 32px;
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
> .about {
|
||||||
padding: 16px;
|
display: inline-block;
|
||||||
|
padding: 24px;
|
||||||
|
margin-bottom: var(--margin);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
min-width: 300px;
|
||||||
|
max-width: 800px;
|
||||||
|
|
||||||
|
&, * {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
> h1 {
|
||||||
|
margin: 0 0 16px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .blocks {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
|
||||||
|
grid-gap: var(--margin);
|
||||||
|
text-align: left;
|
||||||
|
|
||||||
|
> .block {
|
||||||
|
height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 800px) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { defineComponent } from 'vue';
|
||||||
import XSetup from './welcome.setup.vue';
|
import XSetup from './welcome.setup.vue';
|
||||||
import XEntrance from './welcome.entrance.vue';
|
import XEntrance from './welcome.entrance.vue';
|
||||||
import { instanceName } from '@/config';
|
import { instanceName } from '@/config';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@ -20,16 +21,17 @@ export default defineComponent({
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
title: instanceName || 'Misskey',
|
title: instanceName,
|
||||||
icon: null
|
icon: null
|
||||||
},
|
},
|
||||||
|
meta: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
created() {
|
||||||
meta() {
|
os.api('meta', { detail: true }).then(meta => {
|
||||||
return this.$store.state.instance.meta;
|
this.meta = meta;
|
||||||
},
|
});
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -33,6 +33,9 @@ export const router = createRouter({
|
||||||
{ path: '/explore', component: page('explore') },
|
{ path: '/explore', component: page('explore') },
|
||||||
{ path: '/explore/tags/:tag', props: true, component: page('explore') },
|
{ path: '/explore/tags/:tag', props: true, component: page('explore') },
|
||||||
{ path: '/search', component: page('search') },
|
{ path: '/search', component: page('search') },
|
||||||
|
{ path: '/pages', name: 'pages', component: page('pages') },
|
||||||
|
{ path: '/pages/new', component: page('page-editor/page-editor') },
|
||||||
|
{ path: '/pages/edit/:pageId', component: page('page-editor/page-editor'), props: route => ({ initPageId: route.params.pageId }) },
|
||||||
{ path: '/channels', component: page('channels') },
|
{ path: '/channels', component: page('channels') },
|
||||||
{ path: '/channels/new', component: page('channel-editor') },
|
{ path: '/channels/new', component: page('channel-editor') },
|
||||||
{ path: '/channels/:channelId/edit', component: page('channel-editor'), props: true },
|
{ path: '/channels/:channelId/edit', component: page('channel-editor'), props: true },
|
||||||
|
@ -47,9 +50,6 @@ export const router = createRouter({
|
||||||
{ path: '/my/messaging/group/:group', component: page('messaging/messaging-room'), props: route => ({ groupId: route.params.group }) },
|
{ path: '/my/messaging/group/:group', component: page('messaging/messaging-room'), props: route => ({ groupId: route.params.group }) },
|
||||||
{ path: '/my/drive', name: 'drive', component: page('drive') },
|
{ path: '/my/drive', name: 'drive', component: page('drive') },
|
||||||
{ path: '/my/drive/folder/:folder', component: page('drive') },
|
{ path: '/my/drive/folder/:folder', component: page('drive') },
|
||||||
{ path: '/my/pages', name: 'pages', component: page('pages') },
|
|
||||||
{ path: '/my/pages/new', component: page('page-editor/page-editor') },
|
|
||||||
{ path: '/my/pages/edit/:pageId', component: page('page-editor/page-editor'), props: route => ({ initPageId: route.params.pageId }) },
|
|
||||||
{ path: '/my/follow-requests', component: page('follow-requests') },
|
{ path: '/my/follow-requests', component: page('follow-requests') },
|
||||||
{ path: '/my/lists', component: page('my-lists/index') },
|
{ path: '/my/lists', component: page('my-lists/index') },
|
||||||
{ path: '/my/lists/:list', component: page('my-lists/list') },
|
{ path: '/my/lists/:list', component: page('my-lists/list') },
|
||||||
|
|
|
@ -96,8 +96,7 @@ export const sidebarDef = {
|
||||||
pages: {
|
pages: {
|
||||||
title: 'pages',
|
title: 'pages',
|
||||||
icon: faFileAlt,
|
icon: faFileAlt,
|
||||||
show: computed(() => store.getters.isSignedIn),
|
to: '/pages',
|
||||||
to: '/my/pages',
|
|
||||||
},
|
},
|
||||||
clips: {
|
clips: {
|
||||||
title: 'clip',
|
title: 'clip',
|
||||||
|
|
|
@ -7,12 +7,12 @@
|
||||||
<MkA class="link" to="/about">{{ $t('aboutX', { x: instanceName }) }}</MkA>
|
<MkA class="link" to="/about">{{ $t('aboutX', { x: instanceName }) }}</MkA>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="banner" :style="{ backgroundImage: `url(${ $store.state.instance.meta.bannerUrl })` }">
|
<div class="banner" :class="{ asBg: $route.path === '/' }" :style="{ backgroundImage: `url(${ $store.state.instance.meta.bannerUrl })` }">
|
||||||
<h1>{{ instanceName }}</h1>
|
<h1 v-if="$route.path !== '/'">{{ instanceName }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="contents" ref="contents" :class="{ wallpaper }">
|
<div class="contents" ref="contents" :class="{ wallpaper }">
|
||||||
<header class="header" ref="header">
|
<header class="header" ref="header" v-show="$route.path !== '/'">
|
||||||
<XHeader :info="pageInfo"/>
|
<XHeader :info="pageInfo"/>
|
||||||
</header>
|
</header>
|
||||||
<main ref="main">
|
<main ref="main">
|
||||||
|
@ -116,11 +116,10 @@ export default defineComponent({
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.mk-app {
|
.mk-app {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
max-width: 1300px;
|
|
||||||
margin: 0 auto;
|
|
||||||
box-shadow: 1px 0 var(--divider), -1px 0 var(--divider);
|
|
||||||
|
|
||||||
> header {
|
> header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -145,6 +144,12 @@ export default defineComponent({
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
|
|
||||||
|
&.asBg {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
height: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -166,6 +171,9 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
> .contents {
|
> .contents {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
> .header {
|
> .header {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -76,6 +76,11 @@ export class Meta {
|
||||||
})
|
})
|
||||||
public blockedHosts: string[];
|
public blockedHosts: string[];
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 512, array: true, default: '{"/announcements", "/featured", "/channels", "/explore", "/games/reversi", "/about-misskey"}'
|
||||||
|
})
|
||||||
|
public pinnedPages: string[];
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 512,
|
length: 512,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -85,8 +85,9 @@ export class PageRepository extends Repository<Page> {
|
||||||
|
|
||||||
public packMany(
|
public packMany(
|
||||||
pages: Page[],
|
pages: Page[],
|
||||||
|
me?: User['id'] | User | null | undefined,
|
||||||
) {
|
) {
|
||||||
return Promise.all(pages.map(x => this.pack(x)));
|
return Promise.all(pages.map(x => this.pack(x, me)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,6 +208,10 @@ export const meta = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pinnedPages: {
|
||||||
|
validator: $.optional.arr($.str),
|
||||||
|
},
|
||||||
|
|
||||||
langs: {
|
langs: {
|
||||||
validator: $.optional.arr($.str),
|
validator: $.optional.arr($.str),
|
||||||
desc: {
|
desc: {
|
||||||
|
@ -537,6 +541,10 @@ export default define(meta, async (ps, me) => {
|
||||||
set.langs = ps.langs.filter(Boolean);
|
set.langs = ps.langs.filter(Boolean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(ps.pinnedPages)) {
|
||||||
|
set.pinnedPages = ps.pinnedPages.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.summalyProxy !== undefined) {
|
if (ps.summalyProxy !== undefined) {
|
||||||
set.summalyProxy = ps.summalyProxy;
|
set.summalyProxy = ps.summalyProxy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,8 +99,6 @@ export default define(meta, async (ps, me) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const proxyAccount = instance.proxyAccountId ? await Users.pack(instance.proxyAccountId).catch(() => null) : null;
|
|
||||||
|
|
||||||
const response: any = {
|
const response: any = {
|
||||||
maintainerName: instance.maintainerName,
|
maintainerName: instance.maintainerName,
|
||||||
maintainerEmail: instance.maintainerEmail,
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
@ -122,8 +120,6 @@ export default define(meta, async (ps, me) => {
|
||||||
disableGlobalTimeline: instance.disableGlobalTimeline,
|
disableGlobalTimeline: instance.disableGlobalTimeline,
|
||||||
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
|
driveCapacityPerLocalUserMb: instance.localDriveCapacityMb,
|
||||||
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
|
driveCapacityPerRemoteUserMb: instance.remoteDriveCapacityMb,
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
|
||||||
proxyRemoteFiles: instance.proxyRemoteFiles,
|
|
||||||
enableHcaptcha: instance.enableHcaptcha,
|
enableHcaptcha: instance.enableHcaptcha,
|
||||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||||
enableRecaptcha: instance.enableRecaptcha,
|
enableRecaptcha: instance.enableRecaptcha,
|
||||||
|
@ -135,9 +131,6 @@ export default define(meta, async (ps, me) => {
|
||||||
iconUrl: instance.iconUrl,
|
iconUrl: instance.iconUrl,
|
||||||
maxNoteTextLength: Math.min(instance.maxNoteTextLength, DB_MAX_NOTE_TEXT_LENGTH),
|
maxNoteTextLength: Math.min(instance.maxNoteTextLength, DB_MAX_NOTE_TEXT_LENGTH),
|
||||||
emojis: await Emojis.packMany(emojis),
|
emojis: await Emojis.packMany(emojis),
|
||||||
requireSetup: (await Users.count({
|
|
||||||
host: null,
|
|
||||||
})) === 0,
|
|
||||||
enableEmail: instance.enableEmail,
|
enableEmail: instance.enableEmail,
|
||||||
|
|
||||||
enableTwitterIntegration: instance.enableTwitterIntegration,
|
enableTwitterIntegration: instance.enableTwitterIntegration,
|
||||||
|
@ -146,10 +139,20 @@ export default define(meta, async (ps, me) => {
|
||||||
|
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
enableServiceWorker: instance.enableServiceWorker,
|
||||||
|
|
||||||
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
...(ps.detail ? {
|
||||||
|
pinnedPages: instance.pinnedPages,
|
||||||
|
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||||
|
proxyRemoteFiles: instance.proxyRemoteFiles,
|
||||||
|
requireSetup: (await Users.count({
|
||||||
|
host: null,
|
||||||
|
})) === 0,
|
||||||
|
} : {})
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ps.detail) {
|
if (ps.detail) {
|
||||||
|
const proxyAccount = instance.proxyAccountId ? await Users.pack(instance.proxyAccountId).catch(() => null) : null;
|
||||||
|
|
||||||
|
response.proxyAccountName = proxyAccount ? proxyAccount.username : null;
|
||||||
response.features = {
|
response.features = {
|
||||||
registration: !instance.disableRegistration,
|
registration: !instance.disableRegistration,
|
||||||
localTimeLine: !instance.disableLocalTimeline,
|
localTimeLine: !instance.disableLocalTimeline,
|
||||||
|
@ -164,7 +167,6 @@ export default define(meta, async (ps, me) => {
|
||||||
serviceWorker: instance.enableServiceWorker,
|
serviceWorker: instance.enableServiceWorker,
|
||||||
miauth: true,
|
miauth: true,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
if (me && me.isAdmin) {
|
if (me && me.isAdmin) {
|
||||||
response.useStarForReactionFallback = instance.useStarForReactionFallback;
|
response.useStarForReactionFallback = instance.useStarForReactionFallback;
|
||||||
|
@ -201,6 +203,7 @@ export default define(meta, async (ps, me) => {
|
||||||
response.objectStorageUseProxy = instance.objectStorageUseProxy;
|
response.objectStorageUseProxy = instance.objectStorageUseProxy;
|
||||||
response.objectStorageSetPublicRead = instance.objectStorageSetPublicRead;
|
response.objectStorageSetPublicRead = instance.objectStorageSetPublicRead;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
|
|
54
src/server/api/endpoints/notes/clips.ts
Normal file
54
src/server/api/endpoints/notes/clips.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import $ from 'cafy';
|
||||||
|
import { ID } from '../../../../misc/cafy-id';
|
||||||
|
import define from '../../define';
|
||||||
|
import { ClipNotes, Clips } from '../../../../models';
|
||||||
|
import { getNote } from '../../common/getters';
|
||||||
|
import { ApiError } from '../../error';
|
||||||
|
import { In } from 'typeorm';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['clips', 'notes'],
|
||||||
|
|
||||||
|
requireCredential: false as const,
|
||||||
|
|
||||||
|
params: {
|
||||||
|
noteId: {
|
||||||
|
validator: $.type(ID),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
items: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
ref: 'Note',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
noSuchNote: {
|
||||||
|
message: 'No such note.',
|
||||||
|
code: 'NO_SUCH_NOTE',
|
||||||
|
id: '47db1a1c-b0af-458d-8fb4-986e4efafe1e'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, async (ps, me) => {
|
||||||
|
const note = await getNote(ps.noteId).catch(e => {
|
||||||
|
if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote);
|
||||||
|
throw e;
|
||||||
|
});
|
||||||
|
|
||||||
|
const clipNotes = await ClipNotes.find({
|
||||||
|
noteId: note.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
const clips = await Clips.find({
|
||||||
|
id: In(clipNotes.map(x => x.clipId)),
|
||||||
|
});
|
||||||
|
|
||||||
|
return await Promise.all(clips.map(x => Clips.pack(x)));
|
||||||
|
});
|
29
src/server/api/endpoints/pages/featured.ts
Normal file
29
src/server/api/endpoints/pages/featured.ts
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import define from '../../define';
|
||||||
|
import { Pages } from '../../../../models';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['pages'],
|
||||||
|
|
||||||
|
requireCredential: false as const,
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'array' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
items: {
|
||||||
|
type: 'object' as const,
|
||||||
|
optional: false as const, nullable: false as const,
|
||||||
|
ref: 'Page',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default define(meta, async (ps, me) => {
|
||||||
|
const query = Pages.createQueryBuilder('page')
|
||||||
|
.where('page.visibility = \'public\'')
|
||||||
|
.andWhere('page.likedCount > 0')
|
||||||
|
.orderBy('page.likedCount', 'DESC');
|
||||||
|
|
||||||
|
const pages = await query.take(10).getMany();
|
||||||
|
|
||||||
|
return await Pages.packMany(pages, me);
|
||||||
|
});
|
|
@ -299,6 +299,7 @@ router.get('/@:user/pages/:page', async ctx => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Clip
|
// Clip
|
||||||
|
// TODO: 非publicなclipのハンドリング
|
||||||
router.get('/clips/:clip', async ctx => {
|
router.get('/clips/:clip', async ctx => {
|
||||||
const clip = await Clips.findOne({
|
const clip = await Clips.findOne({
|
||||||
id: ctx.params.clip,
|
id: ctx.params.clip,
|
||||||
|
|
Loading…
Reference in a new issue