mirror of
https://activitypub.software/TransFem-org/Sharkey
synced 2024-11-21 21:45:11 +00:00
parent
4c2f7c64cc
commit
dd6569a1bb
17 changed files with 131 additions and 27 deletions
|
@ -14,10 +14,11 @@ You should also include the user name that made the change.
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
- ユーザーごとにRenoteをミュートできるように
|
- ユーザーごとにRenoteをミュートできるように
|
||||||
|
- ノートごとに絵文字リアクションを受け取るか設定できるように
|
||||||
- enhance(client): DM作成時にメンションも含むように
|
- enhance(client): DM作成時にメンションも含むように
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
-
|
-
|
||||||
|
|
||||||
## 13.9.2 (2023/03/06)
|
## 13.9.2 (2023/03/06)
|
||||||
|
|
||||||
|
|
|
@ -961,6 +961,9 @@ invitationRequiredToRegister: "現在このサーバーは招待制です。招
|
||||||
emailNotSupported: "このサーバーではメール配信はサポートされていません"
|
emailNotSupported: "このサーバーではメール配信はサポートされていません"
|
||||||
postToTheChannel: "チャンネルに投稿"
|
postToTheChannel: "チャンネルに投稿"
|
||||||
cannotBeChangedLater: "後から変更できません。"
|
cannotBeChangedLater: "後から変更できません。"
|
||||||
|
reactionAcceptance: "リアクションの受け入れ"
|
||||||
|
likeOnly: "いいねのみ"
|
||||||
|
likeOnlyForRemote: "リモートからはいいねのみ"
|
||||||
|
|
||||||
_achievements:
|
_achievements:
|
||||||
earnedAt: "獲得日時"
|
earnedAt: "獲得日時"
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
export class perNoteReactionAcceptance1678164627293 {
|
||||||
|
name = 'perNoteReactionAcceptance1678164627293'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "note" ADD "reactionAcceptance" character varying(64)`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "reactionAcceptance"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -125,6 +125,7 @@ type Option = {
|
||||||
files?: DriveFile[] | null;
|
files?: DriveFile[] | null;
|
||||||
poll?: IPoll | null;
|
poll?: IPoll | null;
|
||||||
localOnly?: boolean | null;
|
localOnly?: boolean | null;
|
||||||
|
reactionAcceptance?: Note['reactionAcceptance'];
|
||||||
cw?: string | null;
|
cw?: string | null;
|
||||||
visibility?: string;
|
visibility?: string;
|
||||||
visibleUsers?: MinimumUser[] | null;
|
visibleUsers?: MinimumUser[] | null;
|
||||||
|
@ -346,6 +347,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
emojis,
|
emojis,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
localOnly: data.localOnly!,
|
localOnly: data.localOnly!,
|
||||||
|
reactionAcceptance: data.reactionAcceptance,
|
||||||
visibility: data.visibility as any,
|
visibility: data.visibility as any,
|
||||||
visibleUserIds: data.visibility === 'specified'
|
visibleUserIds: data.visibility === 'specified'
|
||||||
? data.visibleUsers
|
? data.visibleUsers
|
||||||
|
|
|
@ -99,8 +99,12 @@ export class ReactionService {
|
||||||
throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.');
|
throw new IdentifiableError('68e9d2d1-48bf-42c2-b90a-b20e09fd3d48', 'Note not accessible for you.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cache
|
if (note.reactionAcceptance === 'likeOnly' || ((note.reactionAcceptance === 'likeOnlyForRemote') && (user.host != null))) {
|
||||||
reaction = await this.toDbReaction(reaction, user.host);
|
reaction = '❤️';
|
||||||
|
} else {
|
||||||
|
// TODO: cache
|
||||||
|
reaction = await this.toDbReaction(reaction, user.host);
|
||||||
|
}
|
||||||
|
|
||||||
const record: NoteReaction = {
|
const record: NoteReaction = {
|
||||||
id: this.idService.genId(),
|
id: this.idService.genId(),
|
||||||
|
|
|
@ -314,6 +314,7 @@ export class NoteEntityService implements OnModuleInit {
|
||||||
cw: note.cw,
|
cw: note.cw,
|
||||||
visibility: note.visibility,
|
visibility: note.visibility,
|
||||||
localOnly: note.localOnly ?? undefined,
|
localOnly: note.localOnly ?? undefined,
|
||||||
|
reactionAcceptance: note.reactionAcceptance,
|
||||||
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
|
visibleUserIds: note.visibility === 'specified' ? note.visibleUserIds : undefined,
|
||||||
renoteCount: note.renoteCount,
|
renoteCount: note.renoteCount,
|
||||||
repliesCount: note.repliesCount,
|
repliesCount: note.repliesCount,
|
||||||
|
|
|
@ -95,7 +95,7 @@ export interface Schema extends OfSchema {
|
||||||
readonly example?: any;
|
readonly example?: any;
|
||||||
readonly format?: string;
|
readonly format?: string;
|
||||||
readonly ref?: keyof typeof refs;
|
readonly ref?: keyof typeof refs;
|
||||||
readonly enum?: ReadonlyArray<string>;
|
readonly enum?: ReadonlyArray<string | null>;
|
||||||
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
|
readonly default?: (this['type'] extends TypeStringef ? StringDefToType<this['type']> : any) | null;
|
||||||
readonly maxLength?: number;
|
readonly maxLength?: number;
|
||||||
readonly minLength?: number;
|
readonly minLength?: number;
|
||||||
|
@ -161,7 +161,7 @@ export type SchemaTypeDef<p extends Schema> =
|
||||||
p['type'] extends 'integer' ? number :
|
p['type'] extends 'integer' ? number :
|
||||||
p['type'] extends 'number' ? number :
|
p['type'] extends 'number' ? number :
|
||||||
p['type'] extends 'string' ? (
|
p['type'] extends 'string' ? (
|
||||||
p['enum'] extends readonly string[] ?
|
p['enum'] extends readonly (string | null)[] ?
|
||||||
p['enum'][number] :
|
p['enum'][number] :
|
||||||
p['format'] extends 'date-time' ? string : // Dateにする??
|
p['format'] extends 'date-time' ? string : // Dateにする??
|
||||||
string
|
string
|
||||||
|
|
|
@ -87,6 +87,11 @@ export class Note {
|
||||||
})
|
})
|
||||||
public localOnly: boolean;
|
public localOnly: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 64, nullable: true,
|
||||||
|
})
|
||||||
|
public reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | null;
|
||||||
|
|
||||||
@Column('smallint', {
|
@Column('smallint', {
|
||||||
default: 0,
|
default: 0,
|
||||||
})
|
})
|
||||||
|
|
|
@ -141,6 +141,10 @@ export const packedNoteSchema = {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: true, nullable: false,
|
optional: true, nullable: false,
|
||||||
},
|
},
|
||||||
|
reactionAcceptance: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
reactions: {
|
reactions: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -148,6 +148,7 @@ function serialize(favorite: NoteFavorite & { note: Note & { user: User } }, pol
|
||||||
visibility: favorite.note.visibility,
|
visibility: favorite.note.visibility,
|
||||||
visibleUserIds: favorite.note.visibleUserIds,
|
visibleUserIds: favorite.note.visibleUserIds,
|
||||||
localOnly: favorite.note.localOnly,
|
localOnly: favorite.note.localOnly,
|
||||||
|
reactionAcceptance: favorite.note.reactionAcceptance,
|
||||||
uri: favorite.note.uri,
|
uri: favorite.note.uri,
|
||||||
url: favorite.note.url,
|
url: favorite.note.url,
|
||||||
user: {
|
user: {
|
||||||
|
|
|
@ -10,10 +10,10 @@ import { DriveService } from '@/core/DriveService.js';
|
||||||
import { createTemp } from '@/misc/create-temp.js';
|
import { createTemp } from '@/misc/create-temp.js';
|
||||||
import type { Poll } from '@/models/entities/Poll.js';
|
import type { Poll } from '@/models/entities/Poll.js';
|
||||||
import type { Note } from '@/models/entities/Note.js';
|
import type { Note } from '@/models/entities/Note.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type Bull from 'bull';
|
import type Bull from 'bull';
|
||||||
import type { DbUserJobData } from '../types.js';
|
import type { DbUserJobData } from '../types.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ExportNotesProcessorService {
|
export class ExportNotesProcessorService {
|
||||||
|
@ -141,5 +141,6 @@ function serialize(note: Note, poll: Poll | null = null): Record<string, unknown
|
||||||
visibility: note.visibility,
|
visibility: note.visibility,
|
||||||
visibleUserIds: note.visibleUserIds,
|
visibleUserIds: note.visibleUserIds,
|
||||||
localOnly: note.localOnly,
|
localOnly: note.localOnly,
|
||||||
|
reactionAcceptance: note.reactionAcceptance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,7 @@ export const paramDef = {
|
||||||
} },
|
} },
|
||||||
cw: { type: 'string', nullable: true, maxLength: 100 },
|
cw: { type: 'string', nullable: true, maxLength: 100 },
|
||||||
localOnly: { type: 'boolean', default: false },
|
localOnly: { type: 'boolean', default: false },
|
||||||
|
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote'], default: null },
|
||||||
noExtractMentions: { type: 'boolean', default: false },
|
noExtractMentions: { type: 'boolean', default: false },
|
||||||
noExtractHashtags: { type: 'boolean', default: false },
|
noExtractHashtags: { type: 'boolean', default: false },
|
||||||
noExtractEmojis: { type: 'boolean', default: false },
|
noExtractEmojis: { type: 'boolean', default: false },
|
||||||
|
@ -110,7 +111,7 @@ export const paramDef = {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
maxLength: MAX_NOTE_TEXT_LENGTH,
|
maxLength: MAX_NOTE_TEXT_LENGTH,
|
||||||
nullable: false
|
nullable: false,
|
||||||
},
|
},
|
||||||
fileIds: {
|
fileIds: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@ -280,6 +281,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
renote,
|
renote,
|
||||||
cw: ps.cw,
|
cw: ps.cw,
|
||||||
localOnly: ps.localOnly,
|
localOnly: ps.localOnly,
|
||||||
|
reactionAcceptance: ps.reactionAcceptance,
|
||||||
visibility: ps.visibility,
|
visibility: ps.visibility,
|
||||||
visibleUsers,
|
visibleUsers,
|
||||||
channel,
|
channel,
|
||||||
|
|
|
@ -103,7 +103,8 @@
|
||||||
<i class="ti ti-ban"></i>
|
<i class="ti ti-ban"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
|
<button v-if="appearNote.myReaction == null" ref="reactButton" :class="$style.footerButton" class="_button" @mousedown="react()">
|
||||||
<i class="ti ti-plus"></i>
|
<i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||||
|
<i v-else class="ti ti-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
|
<button v-if="appearNote.myReaction != null" ref="reactButton" :class="$style.footerButton" class="_button" @click="undoReact(appearNote)">
|
||||||
<i class="ti ti-minus"></i>
|
<i class="ti ti-minus"></i>
|
||||||
|
@ -329,18 +330,32 @@ function reply(viaKeyboard = false): void {
|
||||||
|
|
||||||
function react(viaKeyboard = false): void {
|
function react(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
blur();
|
if (appearNote.reactionAcceptance === 'likeOnly') {
|
||||||
reactionPicker.show(reactButton.value, reaction => {
|
|
||||||
os.api('notes/reactions/create', {
|
os.api('notes/reactions/create', {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.id,
|
||||||
reaction: reaction,
|
reaction: '❤️',
|
||||||
});
|
});
|
||||||
if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) {
|
const el = reactButton.value as HTMLElement | null | undefined;
|
||||||
claimAchievement('reactWithoutRead');
|
if (el) {
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
}, () => {
|
} else {
|
||||||
focus();
|
blur();
|
||||||
});
|
reactionPicker.show(reactButton.value, reaction => {
|
||||||
|
os.api('notes/reactions/create', {
|
||||||
|
noteId: appearNote.id,
|
||||||
|
reaction: reaction,
|
||||||
|
});
|
||||||
|
if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) {
|
||||||
|
claimAchievement('reactWithoutRead');
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undoReact(note): void {
|
function undoReact(note): void {
|
||||||
|
|
|
@ -108,7 +108,8 @@
|
||||||
<i class="ti ti-ban"></i>
|
<i class="ti ti-ban"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()">
|
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()">
|
||||||
<i class="ti ti-plus"></i>
|
<i v-if="appearNote.reactionAcceptance === 'likeOnly'" class="ti ti-heart"></i>
|
||||||
|
<i v-else class="ti ti-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
||||||
<i class="ti ti-minus"></i>
|
<i class="ti ti-minus"></i>
|
||||||
|
@ -323,18 +324,32 @@ function reply(viaKeyboard = false): void {
|
||||||
|
|
||||||
function react(viaKeyboard = false): void {
|
function react(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
blur();
|
if (appearNote.reactionAcceptance === 'likeOnly') {
|
||||||
reactionPicker.show(reactButton.value, reaction => {
|
|
||||||
os.api('notes/reactions/create', {
|
os.api('notes/reactions/create', {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.id,
|
||||||
reaction: reaction,
|
reaction: '❤️',
|
||||||
});
|
});
|
||||||
if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) {
|
const el = reactButton.value as HTMLElement | null | undefined;
|
||||||
claimAchievement('reactWithoutRead');
|
if (el) {
|
||||||
|
const rect = el.getBoundingClientRect();
|
||||||
|
const x = rect.left + (el.offsetWidth / 2);
|
||||||
|
const y = rect.top + (el.offsetHeight / 2);
|
||||||
|
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
}, () => {
|
} else {
|
||||||
focus();
|
blur();
|
||||||
});
|
reactionPicker.show(reactButton.value, reaction => {
|
||||||
|
os.api('notes/reactions/create', {
|
||||||
|
noteId: appearNote.id,
|
||||||
|
reaction: reaction,
|
||||||
|
});
|
||||||
|
if (appearNote.text && appearNote.text.length > 100 && (Date.now() - new Date(appearNote.createdAt).getTime() < 1000 * 3)) {
|
||||||
|
claimAchievement('reactWithoutRead');
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
focus();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function undoReact(note): void {
|
function undoReact(note): void {
|
||||||
|
|
|
@ -53,14 +53,23 @@
|
||||||
<XPostFormAttaches v-model="files" :class="$style.attaches" @detach="detachFile" @change-sensitive="updateFileSensitive" @change-name="updateFileName"/>
|
<XPostFormAttaches v-model="files" :class="$style.attaches" @detach="detachFile" @change-sensitive="updateFileSensitive" @change-name="updateFileName"/>
|
||||||
<MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
|
<MkPollEditor v-if="poll" v-model="poll" @destroyed="poll = null"/>
|
||||||
<XNotePreview v-if="showPreview" :class="$style.preview" :text="text"/>
|
<XNotePreview v-if="showPreview" :class="$style.preview" :text="text"/>
|
||||||
|
<div v-if="showingOptions" style="padding: 0 16px;">
|
||||||
|
<MkSelect v-model="reactionAcceptance" small>
|
||||||
|
<template #label>{{ i18n.ts.reactionAcceptance }}</template>
|
||||||
|
<option :value="null">{{ i18n.ts.all }}</option>
|
||||||
|
<option value="likeOnly">{{ i18n.ts.likeOnly }}</option>
|
||||||
|
<option value="likeOnlyForRemote">{{ i18n.ts.likeOnlyForRemote }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
</div>
|
||||||
|
<button v-tooltip="i18n.ts.emoji" class="_button" :class="$style.emojiButton" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button>
|
||||||
<footer :class="$style.footer">
|
<footer :class="$style.footer">
|
||||||
<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.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.poll" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: poll }]" @click="togglePoll"><i class="ti ti-chart-arrows"></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.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.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-tooltip="i18n.ts.hashtags" class="_button" :class="[$style.footerButton, { [$style.footerButtonActive]: withHashtags }]" @click="withHashtags = !withHashtags"><i class="ti ti-hash"></i></button>
|
||||||
<button v-tooltip="i18n.ts.emoji" class="_button" :class="$style.footerButton" @click="insertEmoji"><i class="ti ti-mood-happy"></i></button>
|
|
||||||
<button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugin" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button>
|
<button v-if="postFormActions.length > 0" v-tooltip="i18n.ts.plugin" class="_button" :class="$style.footerButton" @click="showActions"><i class="ti ti-plug"></i></button>
|
||||||
|
<button v-tooltip="i18n.ts.more" class="_button" :class="$style.footerButton" @click="showingOptions = !showingOptions"><i class="ti ti-dots"></i></button>
|
||||||
</footer>
|
</footer>
|
||||||
<datalist id="hashtags">
|
<datalist id="hashtags">
|
||||||
<option v-for="hashtag in recentHashtags" :key="hashtag" :value="hashtag"/>
|
<option v-for="hashtag in recentHashtags" :key="hashtag" :value="hashtag"/>
|
||||||
|
@ -76,6 +85,7 @@ import * as misskey from 'misskey-js';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
import { toASCII } from 'punycode/';
|
import { toASCII } from 'punycode/';
|
||||||
import * as Acct from 'misskey-js/built/acct';
|
import * as Acct from 'misskey-js/built/acct';
|
||||||
|
import MkSelect from './MkSelect.vue';
|
||||||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||||
import XNotePreview from '@/components/MkNotePreview.vue';
|
import XNotePreview from '@/components/MkNotePreview.vue';
|
||||||
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
|
import XPostFormAttaches from '@/components/MkPostFormAttaches.vue';
|
||||||
|
@ -151,12 +161,14 @@ let visibleUsers = $ref([]);
|
||||||
if (props.initialVisibleUsers) {
|
if (props.initialVisibleUsers) {
|
||||||
props.initialVisibleUsers.forEach(pushVisibleUser);
|
props.initialVisibleUsers.forEach(pushVisibleUser);
|
||||||
}
|
}
|
||||||
|
let reactionAcceptance = $ref(defaultStore.state.reactionAcceptance);
|
||||||
let autocomplete = $ref(null);
|
let autocomplete = $ref(null);
|
||||||
let draghover = $ref(false);
|
let draghover = $ref(false);
|
||||||
let quoteId = $ref(null);
|
let quoteId = $ref(null);
|
||||||
let hasNotSpecifiedMentions = $ref(false);
|
let hasNotSpecifiedMentions = $ref(false);
|
||||||
let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
|
let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') ?? '[]'));
|
||||||
let imeText = $ref('');
|
let imeText = $ref('');
|
||||||
|
let showingOptions = $ref(false);
|
||||||
|
|
||||||
const draftKey = $computed((): string => {
|
const draftKey = $computed((): string => {
|
||||||
let key = props.channel ? `channel:${props.channel.id}` : '';
|
let key = props.channel ? `channel:${props.channel.id}` : '';
|
||||||
|
@ -614,6 +626,7 @@ async function post(ev?: MouseEvent) {
|
||||||
localOnly: localOnly,
|
localOnly: localOnly,
|
||||||
visibility: visibility,
|
visibility: visibility,
|
||||||
visibleUserIds: visibility === 'specified' ? visibleUsers.map(u => u.id) : undefined,
|
visibleUserIds: visibility === 'specified' ? visibleUsers.map(u => u.id) : undefined,
|
||||||
|
reactionAcceptance,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (withHashtags && hashtags && hashtags.trim() !== '') {
|
if (withHashtags && hashtags && hashtags.trim() !== '') {
|
||||||
|
@ -1030,6 +1043,18 @@ defineExpose({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emojiButton {
|
||||||
|
position: absolute;
|
||||||
|
top: 55px;
|
||||||
|
right: 13px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
@container (max-width: 500px) {
|
@container (max-width: 500px) {
|
||||||
.header {
|
.header {
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
|
|
@ -64,12 +64,19 @@
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
<MkSelect v-model="reactionAcceptance">
|
||||||
|
<template #label>{{ i18n.ts.reactionAcceptance }}</template>
|
||||||
|
<option :value="null">{{ i18n.ts.all }}</option>
|
||||||
|
<option value="likeOnly">{{ i18n.ts.likeOnly }}</option>
|
||||||
|
<option value="likeOnlyForRemote">{{ i18n.ts.likeOnlyForRemote }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
|
||||||
<MkSwitch v-model="profile.showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch>
|
<MkSwitch v-model="profile.showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, watch } from 'vue';
|
import { computed, reactive, watch } from 'vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkTextarea from '@/components/MkTextarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
@ -85,6 +92,9 @@ import { $i } from '@/account';
|
||||||
import { langmap } from '@/scripts/langmap';
|
import { langmap } from '@/scripts/langmap';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import { claimAchievement } from '@/scripts/achievements';
|
import { claimAchievement } from '@/scripts/achievements';
|
||||||
|
import { defaultStore } from '@/store';
|
||||||
|
|
||||||
|
const reactionAcceptance = computed(defaultStore.makeGetterSetter('reactionAcceptance'));
|
||||||
|
|
||||||
const profile = reactive({
|
const profile = reactive({
|
||||||
name: $i.name,
|
name: $i.name,
|
||||||
|
|
|
@ -81,6 +81,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
where: 'account',
|
where: 'account',
|
||||||
default: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'],
|
default: ['👍', '❤️', '😆', '🤔', '😮', '🎉', '💢', '😥', '😇', '🍮'],
|
||||||
},
|
},
|
||||||
|
reactionAcceptance: {
|
||||||
|
where: 'account',
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
mutedWords: {
|
mutedWords: {
|
||||||
where: 'account',
|
where: 'account',
|
||||||
default: [],
|
default: [],
|
||||||
|
|
Loading…
Reference in a new issue