Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

release: v2024.3.1-kakurega.1.34.0 #140

Merged
merged 5 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG_KAKUREGA.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## 1.34.0
Release: 2024/03/20
Base: 2024.3.1

### 新機能
- 投稿フォーム下部の項目をカスタマイズできる機能を実装
- 設定→全般→投稿フォームからカスタマイズできます
![image](https://media.kakurega.app/static/misskey/d20bcd3e-352d-4cee-a105-bef72bf814a7.png)
- 投稿フォームをリセットできるボタンを追加
- 設定→全般→投稿フォームから追加できます
![image](https://media.kakurega.app/static/misskey/f5408094-62dd-4169-858d-24b69984600a.png)
- チャンネル内お知らせ機能を実装
- チャンネルの[タイムライン上部にお知らせ等を表示できる](https://kakurega.app/notes/9r21hv7au0)機能です
- チャンネルの管理者・モデレーターは対象のチャンネルの設定から変更できます

## 1.33.1
Release: 2024/03/13
Base: 2024.3.1
Expand Down
16 changes: 16 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5280,6 +5280,22 @@ export interface Locale extends ILocale {
* 自分のプロフィールのアクティビティ (概要/アクティビティタブ) を他人が見れないようにします。このオプションを有効にしても、自分であればプロフィールのアクティビティタブから引き続き閲覧できます。
*/
"hideActivityDescription": string;
/**
* このお知らせはチャンネルのタイムライン上部に表示されます。最初の1行がタイトルとして表示され、2行目以降はお知らせをタップすることで表示されるようになります。
*/
"channelAnnouncementDescription": string;
/**
* 投稿フォーム
*/
"postForm": string;
/**
* 投稿フォームの下部に表示される項目の並び替えが出来ます。項目をクリックすると削除できます。
*/
"postFormBottomSettingsDescription": string;
/**
* 投稿フォームをリセット
*/
"clearPost": string;
"_bubbleGame": {
/**
* 遊び方
Expand Down
4 changes: 4 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,10 @@ scheduledNoteDelete: "ノートの自己消滅"
noteDeletationAt: "このノートは{time}に消滅します"
hideActivity: "アクティビティを非公開にする"
hideActivityDescription: "自分のプロフィールのアクティビティ (概要/アクティビティタブ) を他人が見れないようにします。このオプションを有効にしても、自分であればプロフィールのアクティビティタブから引き続き閲覧できます。"
channelAnnouncementDescription: "このお知らせはチャンネルのタイムライン上部に表示されます。最初の1行がタイトルとして表示され、2行目以降はお知らせをタップすることで表示されるようになります。"
postForm: "投稿フォーム"
postFormBottomSettingsDescription: "投稿フォームの下部に表示される項目の並び替えが出来ます。項目をクリックすると削除できます。"
clearPost: "投稿フォームをリセット"

_bubbleGame:
howToPlay: "遊び方"
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "2024.3.1-kakurega.1.33.1",
"version": "2024.3.1-kakurega.1.34.0",
"codename": "nasubi",
"repository": {
"type": "git",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class FeatChannnelAnnouncement1710854614048 {
name = 'FeatChannnelAnnouncement1710854614048'

async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "channel" ADD "announcement" character varying(2048)`);
}

async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "channel" DROP COLUMN "announcement"`);
}
}
1 change: 1 addition & 0 deletions packages/backend/src/core/entities/ChannelEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class ChannelEntityService {

...(detailed ? {
pinnedNotes: (await this.noteEntityService.packMany(pinnedNotes, me)).sort((a, b) => channel.pinnedNoteIds.indexOf(a.id) - channel.pinnedNoteIds.indexOf(b.id)),
announcement: channel.announcement,
} : {}),
};
}
Expand Down
6 changes: 6 additions & 0 deletions packages/backend/src/models/Channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ export class MiChannel {
})
public pinnedNoteIds: string[];

@Column('varchar', {
length: 2048,
nullable: true,
})
public announcement: string | null;

@Column('varchar', {
length: 16,
default: '#86b300',
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/models/json-schema/channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,9 @@ export const packedChannelSchema = {
ref: 'Note',
},
},
announcement: {
type: 'string',
optional: false, nullable: true,
},
},
} as const;
2 changes: 2 additions & 0 deletions packages/backend/src/server/api/endpoints/channels/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export const paramDef = {
properties: {
name: { type: 'string', minLength: 1, maxLength: 128 },
description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
announcement: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
bannerId: { type: 'string', format: 'misskey:id', nullable: true },
color: { type: 'string', minLength: 1, maxLength: 16 },
isSensitive: { type: 'boolean', nullable: true },
Expand Down Expand Up @@ -89,6 +90,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
isSensitive: ps.isSensitive ?? false,
...(ps.color !== undefined ? { color: ps.color } : {}),
allowRenoteToExternal: ps.allowRenoteToExternal ?? true,
announcement: ps.announcement ?? null,
} as MiChannel).then(x => this.channelsRepository.findOneByOrFail(x.identifiers[0]));

return await this.channelEntityService.pack(channel, me);
Expand Down
2 changes: 2 additions & 0 deletions packages/backend/src/server/api/endpoints/channels/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const paramDef = {
type: 'string', format: 'misskey:id',
},
},
announcement: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 },
color: { type: 'string', minLength: 1, maxLength: 16 },
isSensitive: { type: 'boolean', nullable: true },
allowRenoteToExternal: { type: 'boolean', nullable: true },
Expand Down Expand Up @@ -112,6 +113,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
...(ps.name !== undefined ? { name: ps.name } : {}),
...(ps.description !== undefined ? { description: ps.description } : {}),
...(ps.pinnedNoteIds !== undefined ? { pinnedNoteIds: ps.pinnedNoteIds } : {}),
...(ps.announcement !== undefined ? { announcement: ps.announcement } : {}),
...(ps.color !== undefined ? { color: ps.color } : {}),
...(typeof ps.isArchived === 'boolean' ? { isArchived: ps.isArchived } : {}),
...(banner ? { bannerId: banner.id } : {}),
Expand Down
58 changes: 48 additions & 10 deletions packages/frontend/src/components/MkPostForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,9 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<footer :class="$style.footer">
<div :class="$style.footerLeft">
<button v-tooltip="i18n.ts.attachFile" class="_button" :class="$style.footerButton" @click="chooseFileFrom"><i class="ti ti-photo-plus"></i></button>
<button v-tooltip="i18n.ts.poll" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: poll }]" @click="togglePoll"><i class="ti ti-chart-arrows"></i></button>
<button v-tooltip="i18n.ts.scheduledNoteDelete" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: scheduledNoteDelete }]" @click="toggleScheduledNoteDelete"><i class="ti ti-bomb"></i></button>
<button v-tooltip="i18n.ts.useCw" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: useCw }]" @click="useCw = !useCw"><i class="ti ti-eye-off"></i></button>
<button v-tooltip="i18n.ts.mention" class="_button" :class="$style.footerButton" @click="insertMention"><i class="ti ti-at"></i></button>
<button v-tooltip="i18n.ts.hashtags" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: withHashtags }]" @click="withHashtags = !withHashtags"><i class="ti ti-hash"></i></button>
<button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugins" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button>
<button v-tooltip="i18n.ts.emoji" :class="['_button', $style.footerButton]" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button>
<button v-if="showAddMfmFunction" v-tooltip="i18n.ts.addMfmFunction" :class="['_button', $style.footerButton]" @click="insertMfmFunction"><i class="ti ti-palette"></i></button>
<template v-for="item in defaultStore.state.postFormActions">
<button v-if="!bottomItemActionDef[item].hide" :key="item" v-tooltip="bottomItemDef[item].title" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: bottomItemActionDef[item].active }]" v-on="bottomItemActionDef[item].action ? { click: bottomItemActionDef[item].action } : {}"><i class="ti" :class="bottomItemDef[item].icon"></i></button>
</template>
</div>
<div :class="$style.footerRight">
<button v-tooltip="i18n.ts.previewNoteText" class="_button" :class="[$style.footerButton, { [$style.previewButtonActive]: showPreview }]" @click="showPreview = !showPreview"><i class="ti ti-eye"></i></button>
Expand All @@ -102,7 +96,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>

<script lang="ts" setup>
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed } from 'vue';
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed, reactive } from 'vue';
import * as mfm from 'mfm-js';
import * as Misskey from 'misskey-js';
import insertTextAtCursor from 'insert-text-at-cursor';
Expand Down Expand Up @@ -132,6 +126,7 @@ import { miLocalStorage } from '@/local-storage.js';
import { claimAchievement } from '@/scripts/achievements.js';
import { emojiPicker } from '@/scripts/emoji-picker.js';
import { mfmFunctionPicker } from '@/scripts/mfm-function-picker.js';
import { bottomItemDef } from '@/scripts/post-form.js';

const $i = signinRequired();

Expand Down Expand Up @@ -265,6 +260,49 @@ const canPost = computed((): boolean => {
const withHashtags = computed(defaultStore.makeGetterSetter('postFormWithHashtags'));
const hashtags = computed(defaultStore.makeGetterSetter('postFormHashtags'));

const bottomItemActionDef: Record<keyof typeof bottomItemDef, {
hide?: boolean;
active?: any;
action?: any;
}> = reactive({
attachFile: {
action: chooseFileFrom,
},
poll: {
active: poll,
action: togglePoll,
},
scheduledNoteDelete: {
active: scheduledNoteDelete,
action: toggleScheduledNoteDelete,
},
useCw: {
active: useCw,
action: () => useCw.value = !useCw.value,
},
mention: {
action: insertMention,
},
hashtags: {
active: withHashtags,
action: () => withHashtags.value = !withHashtags.value,
},
plugins: {
hide: postFormActions.length === 0,
action: showActions,
},
emoji: {
action: insertEmoji,
},
addMfmFunction: {
hide: computed(() => !showAddMfmFunction.value),
action: insertMfmFunction,
},
clearPost: {
action: clear,
},
});

watch(text, () => {
checkMissingMention();
}, { immediate: true });
Expand Down
8 changes: 8 additions & 0 deletions packages/frontend/src/pages/channel-editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.description }}</template>
</MkTextarea>

<MkTextarea v-model="announcement" mfmAutocomplete :mfmPreview="true">
<template #label>{{ i18n.ts.announcements }}<span class="_beta">{{ i18n.ts.originalFeature }}</span></template>
<template #caption>{{ i18n.ts.channelAnnouncementDescription }}</template>
</MkTextarea>

<MkColorInput v-model="color">
<template #label>{{ i18n.ts.color }}</template>
</MkColorInput>
Expand Down Expand Up @@ -101,6 +106,7 @@ const color = ref('#000');
const isSensitive = ref(false);
const allowRenoteToExternal = ref(true);
const pinnedNotes = ref<{ id: Misskey.entities.Note['id'] }[]>([]);
const announcement = ref<string | null>(null);

watch(() => bannerId.value, async () => {
if (bannerId.value == null) {
Expand All @@ -127,6 +133,7 @@ async function fetchChannel() {
pinnedNotes.value = channel.value.pinnedNoteIds.map(id => ({
id,
}));
announcement.value = channel.value.announcement;
color.value = channel.value.color;
allowRenoteToExternal.value = channel.value.allowRenoteToExternal;
}
Expand Down Expand Up @@ -156,6 +163,7 @@ function save() {
description: description.value,
bannerId: bannerId.value,
pinnedNoteIds: pinnedNotes.value.map(x => x.id),
announcement: announcement.value,
color: color.value,
isSensitive: isSensitive.value,
allowRenoteToExternal: allowRenoteToExternal.value,
Expand Down
15 changes: 15 additions & 0 deletions packages/frontend/src/pages/channel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="channel && tab === 'timeline'" key="timeline" class="_gaps">
<MkInfo v-if="channel.isArchived" warn>{{ i18n.ts.thisChannelArchived }}</MkInfo>

<MkInfo v-if="channel.announcement" :class="$style.clickable" @click="showAnnouncement">{{ channel.announcement.split('\n')[0] }} ({{ i18n.ts.clickToShow }})</MkInfo>

<!-- スマホ・タブレットの場合、キーボードが表示されると投稿が見づらくなるので、デスクトップ場合のみ自動でフォーカスを当てる -->
<MkPostForm v-if="$i && defaultStore.reactiveState.showFixedPostFormInChannel.value" :channel="channel" class="post-form _panel" fixed :autofocus="deviceKind === 'desktop'"/>

Expand Down Expand Up @@ -240,6 +242,15 @@ const headerActions = computed(() => {
}
});

function showAnnouncement() {
if (!channel.value?.announcement) return;
const announce = channel.value.announcement.split('\n');
os.alert({
title: announce.shift(),
text: announce.join('\n'),
});
}

const headerTabs = computed(() => [{
key: 'overview',
title: i18n.ts.overview,
Expand Down Expand Up @@ -338,4 +349,8 @@ definePageMetadata(() => ({
font-size: 1em;
padding: 4px 7px;
}

.clickable {
cursor: pointer;
}
</style>
7 changes: 1 addition & 6 deletions packages/frontend/src/pages/settings/general.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_s">
<MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch>
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
<MkSwitch v-model="disableNoteDrafting">
<template #caption>{{ i18n.ts.disableNoteDraftingDescription }}</template>
{{ i18n.ts.disableNoteDrafting }}
<span class="_beta">{{ i18n.ts.originalFeature }}</span>
</MkSwitch>
<FormLink to="/settings/post-form">{{ i18n.ts.postForm }}</FormLink>
<MkFolder>
<template #label>{{ i18n.ts.pinnedList }}</template>
<!-- 複数ピン止め管理できるようにしたいけどめんどいので一旦ひとつのみ -->
Expand Down Expand Up @@ -326,7 +322,6 @@ const limitWidthOfReaction = computed(defaultStore.makeGetterSetter('limitWidthO
const collapseRenotes = computed(defaultStore.makeGetterSetter('collapseRenotes'));
const collapseRenotesTrigger = computed(defaultStore.makeGetterSetter('collapseRenotesTrigger'));
const collapseSelfRenotes = computed(defaultStore.makeGetterSetter('collapseSelfRenotes'));
const disableNoteDrafting = computed(defaultStore.makeGetterSetter('disableNoteDrafting'));
const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v));
const useBlurEffectForModal = computed(defaultStore.makeGetterSetter('useBlurEffectForModal'));
const useBlurEffect = computed(defaultStore.makeGetterSetter('useBlurEffect'));
Expand Down
Loading
Loading