wip
This commit is contained in:
parent
6634727d83
commit
ad752a8931
|
@ -1101,6 +1101,8 @@ export interface Locale {
|
||||||
"dialog": string;
|
"dialog": string;
|
||||||
"icon": string;
|
"icon": string;
|
||||||
"forYou": string;
|
"forYou": string;
|
||||||
|
"currentAnnouncements": string;
|
||||||
|
"pastAnnouncements": string;
|
||||||
"_announcement": {
|
"_announcement": {
|
||||||
"forExistingUsers": string;
|
"forExistingUsers": string;
|
||||||
"forExistingUsersDescription": string;
|
"forExistingUsersDescription": string;
|
||||||
|
|
|
@ -1098,6 +1098,8 @@ iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意しま
|
||||||
dialog: "ダイアログ"
|
dialog: "ダイアログ"
|
||||||
icon: "アイコン"
|
icon: "アイコン"
|
||||||
forYou: "あなたへ"
|
forYou: "あなたへ"
|
||||||
|
currentAnnouncements: "現在のお知らせ"
|
||||||
|
pastAnnouncements: "過去のお知らせ"
|
||||||
|
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "既存ユーザーのみ"
|
forExistingUsers: "既存ユーザーのみ"
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const paramDef = {
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
|
isActive: { type: 'boolean', default: true },
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -52,7 +53,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
||||||
.where('announcement.isActive = true')
|
.where('announcement.isActive = :isActive', { isActive: ps.isActive })
|
||||||
.andWhere(new Brackets(qb => {
|
.andWhere(new Brackets(qb => {
|
||||||
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });
|
if (me) qb.orWhere('announcement.userId = :meId', { meId: me.id });
|
||||||
qb.orWhere('announcement.userId IS NULL');
|
qb.orWhere('announcement.userId IS NULL');
|
||||||
|
|
|
@ -15,7 +15,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<XButton :checked="checked" :disabled="disabled" @toggle="toggle"/>
|
<XButton :checked="checked" :disabled="disabled" @toggle="toggle"/>
|
||||||
<span :class="$style.body">
|
<span :class="$style.body">
|
||||||
<!-- TODO: 無名slotの方は廃止 -->
|
<!-- TODO: 無名slotの方は廃止 -->
|
||||||
<span :class="$style.label" @click="toggle"><slot name="label"></slot><slot></slot></span>
|
<span :class="$style.label">
|
||||||
|
<span @click="toggle">
|
||||||
|
<slot name="label"></slot><slot></slot>
|
||||||
|
</span>
|
||||||
|
<span v-if="helpText" v-tooltip:dialog="helpText" class="_button _help" :class="$style.help"><i class="ti ti-help-circle"></i></span>
|
||||||
|
</span>
|
||||||
<p :class="$style.caption"><slot name="caption"></slot></p>
|
<p :class="$style.caption"><slot name="caption"></slot></p>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,6 +33,7 @@ import XButton from '@/components/MkSwitch.button.vue';
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelValue: boolean | Ref<boolean>;
|
modelValue: boolean | Ref<boolean>;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
helpText?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
|
@ -38,10 +44,6 @@ const checked = toRefs(props).modelValue;
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
if (props.disabled) return;
|
if (props.disabled) return;
|
||||||
emit('update:modelValue', !checked.value);
|
emit('update:modelValue', !checked.value);
|
||||||
|
|
||||||
if (!checked.value) {
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -98,4 +100,10 @@ const toggle = () => {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.help {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
font-size: 85%;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -32,13 +32,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<option value="banner">{{ i18n.ts.banner }}</option>
|
<option value="banner">{{ i18n.ts.banner }}</option>
|
||||||
<option value="dialog">{{ i18n.ts.dialog }}</option>
|
<option value="dialog">{{ i18n.ts.dialog }}</option>
|
||||||
</MkRadios>
|
</MkRadios>
|
||||||
<MkSwitch v-model="announcement.forExistingUsers">
|
<MkSwitch v-model="announcement.forExistingUsers" :helpText="i18n.ts._announcement.forExistingUsersDescription">
|
||||||
{{ i18n.ts._announcement.forExistingUsers }}
|
{{ i18n.ts._announcement.forExistingUsers }}
|
||||||
<template #caption>{{ i18n.ts._announcement.forExistingUsersDescription }}</template>
|
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<MkSwitch v-model="announcement.needConfirmationToRead">
|
<MkSwitch v-model="announcement.needConfirmationToRead" :helpText="i18n.ts._announcement.needConfirmationToReadDescription">
|
||||||
{{ i18n.ts._announcement.needConfirmationToRead }}
|
{{ i18n.ts._announcement.needConfirmationToRead }}
|
||||||
<template #caption>{{ i18n.ts._announcement.needConfirmationToReadDescription }}</template>
|
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
<p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p>
|
<p v-if="announcement.reads">{{ i18n.t('nUsersRead', { n: announcement.reads }) }}</p>
|
||||||
<div class="buttons _buttons">
|
<div class="buttons _buttons">
|
||||||
|
|
|
@ -5,9 +5,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :contentMax="800">
|
<MkSpacer :contentMax="800">
|
||||||
<MkPagination ref="paginationEl" v-slot="{items}" :pagination="pagination" class="_gaps_m">
|
<MkPagination ref="paginationEl" :key="tab" v-slot="{items}" :pagination="tab === 'current' ? paginationCurrent : paginationPast" class="_gaps_m">
|
||||||
<section v-for="announcement in items" :key="announcement.id" class="_panel" :class="$style.announcement">
|
<section v-for="announcement in items" :key="announcement.id" class="_panel" :class="$style.announcement">
|
||||||
<div v-if="announcement.forYou" :class="$style.forYou"><i class="ti ti-pin"></i> {{ i18n.ts.forYou }}</div>
|
<div v-if="announcement.forYou" :class="$style.forYou"><i class="ti ti-pin"></i> {{ i18n.ts.forYou }}</div>
|
||||||
<div :class="$style.header">
|
<div :class="$style.header">
|
||||||
|
@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkTime :time="announcement.updatedAt ?? announcement.createdAt" mode="detail"/>
|
<MkTime :time="announcement.updatedAt ?? announcement.createdAt" mode="detail"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="$i && !announcement.isRead" :class="$style.footer">
|
<div v-if="tab !== 'past' && $i && !announcement.isRead" :class="$style.footer">
|
||||||
<MkButton primary @click="read(announcement.id)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
|
<MkButton primary @click="read(announcement.id)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@ -45,13 +45,26 @@ import { i18n } from '@/i18n';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import { $i, updateAccount } from '@/account';
|
import { $i, updateAccount } from '@/account';
|
||||||
|
|
||||||
const pagination = {
|
const paginationCurrent = {
|
||||||
endpoint: 'announcements' as const,
|
endpoint: 'announcements' as const,
|
||||||
limit: 10,
|
limit: 10,
|
||||||
|
params: {
|
||||||
|
isActive: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginationPast = {
|
||||||
|
endpoint: 'announcements' as const,
|
||||||
|
limit: 10,
|
||||||
|
params: {
|
||||||
|
isActive: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const paginationEl = ref<InstanceType<typeof MkPagination>>();
|
const paginationEl = ref<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
|
const tab = ref('current');
|
||||||
|
|
||||||
function read(id: string) {
|
function read(id: string) {
|
||||||
if (!paginationEl.value) return;
|
if (!paginationEl.value) return;
|
||||||
paginationEl.value.updateItem(id, announcement => {
|
paginationEl.value.updateItem(id, announcement => {
|
||||||
|
@ -66,7 +79,15 @@ function read(id: string) {
|
||||||
|
|
||||||
const headerActions = $computed(() => []);
|
const headerActions = $computed(() => []);
|
||||||
|
|
||||||
const headerTabs = $computed(() => []);
|
const headerTabs = $computed(() => [{
|
||||||
|
key: 'current',
|
||||||
|
title: i18n.ts.currentAnnouncements,
|
||||||
|
icon: 'ti ti-flare',
|
||||||
|
}, {
|
||||||
|
key: 'past',
|
||||||
|
title: i18n.ts.pastAnnouncements,
|
||||||
|
icon: 'ti ti-point',
|
||||||
|
}]);
|
||||||
|
|
||||||
definePageMetadata({
|
definePageMetadata({
|
||||||
title: i18n.ts.announcements,
|
title: i18n.ts.announcements,
|
||||||
|
|
|
@ -86,7 +86,7 @@ const tagUsersPagination = $computed(() => ({
|
||||||
endpoint: 'hashtags/users' as const,
|
endpoint: 'hashtags/users' as const,
|
||||||
limit: 30,
|
limit: 30,
|
||||||
params: {
|
params: {
|
||||||
tag: this.tag,
|
tag: props.tag,
|
||||||
origin: 'combined',
|
origin: 'combined',
|
||||||
sort: '+follower',
|
sort: '+follower',
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue