feat (client): add private visibility
This commit is contained in:
parent
f04bf9f78e
commit
fa0e65cc1b
10 changed files with 75 additions and 9 deletions
|
@ -6,6 +6,8 @@ Critical security updates are indicated by the :warning: icon.
|
||||||
|
|
||||||
- Add the ability to give regular (non-moderator) users permission to manage custom emojis
|
- Add the ability to give regular (non-moderator) users permission to manage custom emojis
|
||||||
- Fix a bug that made impossible to update user profiles under some conditions
|
- Fix a bug that made impossible to update user profiles under some conditions
|
||||||
|
- Add "private" (only me) post visibility
|
||||||
|
- It's just a paraphrase of DMs without recipients
|
||||||
|
|
||||||
## :warning: v20240217-1
|
## :warning: v20240217-1
|
||||||
|
|
||||||
|
|
|
@ -1172,12 +1172,14 @@ postSearch: "Post search on this server"
|
||||||
showBigPostButton: "Show a huge post button on the posting form"
|
showBigPostButton: "Show a huge post button on the posting form"
|
||||||
emojiModPerm: "Custom emoji management permission"
|
emojiModPerm: "Custom emoji management permission"
|
||||||
emojiModPermDescription: "Add: Allow this user to add new custom emojis and to set tag/category/license to newly added custom emojis.\nAdd and Edit: \"Add\" Permission + Allow this user to edit the name/category/tag/license of the existing custom emojis.\nAllow All: \"Add and Edit\" Permission + Allow this user to delete existing custom emojis."
|
emojiModPermDescription: "Add: Allow this user to add new custom emojis and to set tag/category/license to newly added custom emojis.\nAdd and Edit: \"Add\" Permission + Allow this user to edit the name/category/tag/license of the existing custom emojis.\nAllow All: \"Add and Edit\" Permission + Allow this user to delete existing custom emojis."
|
||||||
|
private: "Private"
|
||||||
|
privateDescription: "Make visible for you only"
|
||||||
|
|
||||||
_emojiModPerm:
|
_emojiModPerm:
|
||||||
unauthorized: "None"
|
unauthorized: "None"
|
||||||
add: "Add"
|
add: "Add"
|
||||||
mod: "Add and Edit"
|
mod: "Add and Edit"
|
||||||
full: "Allow All"
|
full: "Allow All"
|
||||||
|
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduces the effort of server moderation through automatically recognizing
|
description: "Reduces the effort of server moderation through automatically recognizing
|
||||||
NSFW media via Machine Learning. This will slightly increase the load on the server."
|
NSFW media via Machine Learning. This will slightly increase the load on the server."
|
||||||
|
|
|
@ -2026,3 +2026,5 @@ _emojiModPerm:
|
||||||
add: "追加"
|
add: "追加"
|
||||||
mod: "追加と変更"
|
mod: "追加と変更"
|
||||||
full: "全て許可"
|
full: "全て許可"
|
||||||
|
private: "秘密"
|
||||||
|
privateDescription: "あなた以外には非公開"
|
||||||
|
|
|
@ -1995,3 +1995,5 @@ languageForTranslation: 帖子翻译语言
|
||||||
vibrate: 播放振动
|
vibrate: 播放振动
|
||||||
openServerInfo: 点击帖子上的服务器滚动条时显示服务器信息
|
openServerInfo: 点击帖子上的服务器滚动条时显示服务器信息
|
||||||
clickToShowPatterns: 点击显示模块模式
|
clickToShowPatterns: 点击显示模块模式
|
||||||
|
private: "秘密"
|
||||||
|
privateDescription: "仅你可见"
|
||||||
|
|
|
@ -2012,3 +2012,5 @@ moreUrlsDescription: "請以下列形式輸入欲釘選在左下角幫助選單
|
||||||
showPreviewByDefault: "自動開啟發文介面中的預覽顯示"
|
showPreviewByDefault: "自動開啟發文介面中的預覽顯示"
|
||||||
preventMisclick: "預防誤觸"
|
preventMisclick: "預防誤觸"
|
||||||
hideFollowButtons: "隱藏會誤觸的追隨按鈕"
|
hideFollowButtons: "隱藏會誤觸的追隨按鈕"
|
||||||
|
private: "祕密"
|
||||||
|
privateDescription: "僅你可見"
|
||||||
|
|
|
@ -50,6 +50,9 @@
|
||||||
<span v-if="visibility === 'specified'"
|
<span v-if="visibility === 'specified'"
|
||||||
><i :class="icon('ph-envelope-simple-open')"></i
|
><i :class="icon('ph-envelope-simple-open')"></i
|
||||||
></span>
|
></span>
|
||||||
|
<span v-if="visibility === 'private'"
|
||||||
|
><i :class="icon('ph-eye-slash')"></i
|
||||||
|
></span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
ref="languageButton"
|
ref="languageButton"
|
||||||
|
@ -557,6 +560,8 @@ if (
|
||||||
}).then((users) => {
|
}).then((users) => {
|
||||||
users.forEach(pushVisibleUser);
|
users.forEach(pushVisibleUser);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
visibility.value = "private";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.reply.userId !== $i.id) {
|
if (props.reply.userId !== $i.id) {
|
||||||
|
@ -1015,9 +1020,12 @@ async function post() {
|
||||||
cw: useCw.value ? cw.value || "" : undefined,
|
cw: useCw.value ? cw.value || "" : undefined,
|
||||||
lang: language.value ? language.value : undefined,
|
lang: language.value ? language.value : undefined,
|
||||||
localOnly: localOnly.value,
|
localOnly: localOnly.value,
|
||||||
visibility: visibility.value,
|
visibility:
|
||||||
|
visibility.value === "private" ? "specified" : visibility.value,
|
||||||
visibleUserIds:
|
visibleUserIds:
|
||||||
visibility.value === "specified"
|
visibility.value === "private"
|
||||||
|
? []
|
||||||
|
: visibility.value === "specified"
|
||||||
? visibleUsers.value.map((u) => u.id)
|
? visibleUsers.value.map((u) => u.id)
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,10 +11,20 @@
|
||||||
:class="icon('ph-lock')"
|
:class="icon('ph-lock')"
|
||||||
></i>
|
></i>
|
||||||
<i
|
<i
|
||||||
v-else-if="note.visibility === 'specified'"
|
v-else-if="
|
||||||
|
note.visibility === 'specified' &&
|
||||||
|
note.visibleUserIds != null &&
|
||||||
|
note.visibleUserIds.length > 0
|
||||||
|
"
|
||||||
ref="specified"
|
ref="specified"
|
||||||
:class="icon('ph-envelope-simple-open')"
|
:class="icon('ph-envelope-simple-open')"
|
||||||
></i>
|
></i>
|
||||||
|
<i
|
||||||
|
v-else-if="note.visibility === 'specified'"
|
||||||
|
v-tooltip="i18n.ts._visibility.private"
|
||||||
|
ref="specified"
|
||||||
|
:class="icon('ph-eye-slash')"
|
||||||
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="note.localOnly" :class="$style.localOnly"
|
<span v-if="note.localOnly" :class="$style.localOnly"
|
||||||
><i
|
><i
|
||||||
|
@ -42,7 +52,11 @@ const props = defineProps<{
|
||||||
|
|
||||||
const specified = ref<HTMLElement>();
|
const specified = ref<HTMLElement>();
|
||||||
|
|
||||||
if (props.note.visibility === "specified") {
|
if (
|
||||||
|
props.note.visibility === "specified" &&
|
||||||
|
props.note.visibleUserIds != null &&
|
||||||
|
props.note.visibleUserIds.length > 0
|
||||||
|
) {
|
||||||
useTooltip(specified, async (showing) => {
|
useTooltip(specified, async (showing) => {
|
||||||
const users = await os.api("users/show", {
|
const users = await os.api("users/show", {
|
||||||
userIds: props.note.visibleUserIds,
|
userIds: props.note.visibleUserIds,
|
||||||
|
|
|
@ -84,6 +84,25 @@
|
||||||
}}</span>
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
key="private"
|
||||||
|
class="_button"
|
||||||
|
:class="[$style.item, { [$style.active]: v === 'private' }]"
|
||||||
|
data-index="5"
|
||||||
|
@click="choose('private')"
|
||||||
|
>
|
||||||
|
<div :class="$style.icon">
|
||||||
|
<i :class="icon('ph-eye-slash')"></i>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.body">
|
||||||
|
<span :class="$style.itemTitle">{{
|
||||||
|
i18n.ts._visibility.private
|
||||||
|
}}</span>
|
||||||
|
<span :class="$style.itemDescription">{{
|
||||||
|
i18n.ts._visibility.privateDescription
|
||||||
|
}}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
<div :class="$style.divider"></div>
|
<div :class="$style.divider"></div>
|
||||||
<button
|
<button
|
||||||
key="localOnly"
|
key="localOnly"
|
||||||
|
@ -154,7 +173,9 @@ watch(localOnly, () => {
|
||||||
emit("changeLocalOnly", localOnly.value);
|
emit("changeLocalOnly", localOnly.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
function choose(visibility: (typeof noteVisibilities)[number]): void {
|
function choose(
|
||||||
|
visibility: (typeof noteVisibilities)[number] | "private",
|
||||||
|
): void {
|
||||||
v.value = visibility;
|
v.value = visibility;
|
||||||
emit("changeVisibility", visibility);
|
emit("changeVisibility", visibility);
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|
|
@ -113,6 +113,11 @@
|
||||||
#suffix
|
#suffix
|
||||||
>{{ i18n.ts._visibility.specified }}</template
|
>{{ i18n.ts._visibility.specified }}</template
|
||||||
>
|
>
|
||||||
|
<template
|
||||||
|
v-else-if="defaultNoteVisibility === 'private'"
|
||||||
|
#suffix
|
||||||
|
>{{ i18n.ts._visibility.private }}</template
|
||||||
|
>
|
||||||
|
|
||||||
<FormSelect v-model="defaultNoteVisibility" class="_formBlock">
|
<FormSelect v-model="defaultNoteVisibility" class="_formBlock">
|
||||||
<option value="public">
|
<option value="public">
|
||||||
|
@ -125,6 +130,9 @@
|
||||||
<option value="specified">
|
<option value="specified">
|
||||||
{{ i18n.ts._visibility.specified }}
|
{{ i18n.ts._visibility.specified }}
|
||||||
</option>
|
</option>
|
||||||
|
<option value="private">
|
||||||
|
{{ i18n.ts._visibility.private }}
|
||||||
|
</option>
|
||||||
</FormSelect>
|
</FormSelect>
|
||||||
<FormSwitch v-model="defaultNoteLocalOnly" class="_formBlock">{{
|
<FormSwitch v-model="defaultNoteLocalOnly" class="_formBlock">{{
|
||||||
i18n.ts._visibility.localOnly
|
i18n.ts._visibility.localOnly
|
||||||
|
|
|
@ -122,7 +122,12 @@ export const defaultStore = markRaw(
|
||||||
},
|
},
|
||||||
visibility: {
|
visibility: {
|
||||||
where: "deviceAccount",
|
where: "deviceAccount",
|
||||||
default: "public" as "public" | "home" | "followers" | "specified",
|
default: "public" as
|
||||||
|
| "public"
|
||||||
|
| "home"
|
||||||
|
| "followers"
|
||||||
|
| "specified"
|
||||||
|
| "private",
|
||||||
},
|
},
|
||||||
localOnly: {
|
localOnly: {
|
||||||
where: "deviceAccount",
|
where: "deviceAccount",
|
||||||
|
|
Loading…
Reference in a new issue