diff --git a/index.html b/index.html index fda91b0f..781b0ba3 100644 --- a/index.html +++ b/index.html @@ -4,8 +4,6 @@ Akkoma - - diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 36b087a5..d45584c0 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -322,6 +322,9 @@ const getNodeInfo = async ({ store }) => { : federation.enabled }) + store.dispatch('setInstanceOption', { name: 'publicTimelineVisibility', value: metadata.publicTimelineVisibility }) + store.dispatch('setInstanceOption', { name: 'federatedTimelineAvailable', value: metadata.federatedTimelineAvailable }) + const accountActivationRequired = metadata.accountActivationRequired store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired }) @@ -396,9 +399,6 @@ const afterStoreSetup = async ({ store, i18n }) => { ]) // Start fetching things that don't need to block the UI - store.dispatch('fetchMutes') - store.dispatch('startFetchingAnnouncements') - store.dispatch('startFetchingReports') getTOS({ store }) getStickers({ store }) diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js index f4900c38..d7538f5b 100644 --- a/src/components/desktop_nav/desktop_nav.js +++ b/src/components/desktop_nav/desktop_nav.js @@ -1,6 +1,11 @@ import SearchBar from 'components/search_bar/search_bar.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' +import { + publicTimelineVisible, + federatedTimelineVisible, + bubbleTimelineVisible, +} from '../../lib/timeline_visibility' import { faSignInAlt, faSignOutAlt, @@ -19,6 +24,7 @@ import { faInfoCircle, faUserTie } from '@fortawesome/free-solid-svg-icons' +import { mapState } from 'vuex' library.add( faSignInAlt, @@ -103,7 +109,12 @@ export default { }, showBubbleTimeline () { return this.$store.state.instance.localBubbleInstances.length > 0 - } + }, + ...mapState({ + publicTimelineVisible, + federatedTimelineVisible, + bubbleTimelineVisible, + }) }, methods: { scrollToTop () { diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue index 92d3fa5b..f50d1b3e 100644 --- a/src/components/desktop_nav/desktop_nav.vue +++ b/src/components/desktop_nav/desktop_nav.vue @@ -46,6 +46,7 @@ @@ -69,6 +70,7 @@ state.users.currentUser, privateMode: state => state.instance.private, - federating: state => state.instance.federating + federating: state => state.instance.federating, }), ...mapGetters(['unreadAnnouncementCount']), followRequestCount () { diff --git a/src/components/poll/poll_form.js b/src/components/poll/poll_form.js index e30645c3..89f01eb4 100644 --- a/src/components/poll/poll_form.js +++ b/src/components/poll/poll_form.js @@ -103,9 +103,9 @@ export default { convertExpiryFromUnit (unit, amount) { // Note: we want seconds and not milliseconds switch (unit) { - case 'minutes': return 0.001 * amount * DateUtils.MINUTE - case 'hours': return 0.001 * amount * DateUtils.HOUR - case 'days': return 0.001 * amount * DateUtils.DAY + case 'minutes': return amount * DateUtils.MINUTE / 1000 + case 'hours': return amount * DateUtils.HOUR / 1000 + case 'days': return amount * DateUtils.DAY / 1000 } }, expiryAmountChange () { diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index f7fef499..5647a9eb 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -169,31 +169,33 @@ const PostStatusForm = { } } - let draftKey = 'status'; - if (this.replyTo) { - draftKey = 'reply:' + this.replyTo; - } else if (this.quoteId) { - draftKey = 'quote:' + this.quoteId; - } - - const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[draftKey]; - - if (draft) { - statusParams = { - spoilerText: draft.data.spoilerText, - status: draft.data.status, - sensitiveIfSubject, - nsfw: draft.data.nsfw, - files: draft.data.files, - poll: draft.data.poll, - mediaDescriptions: draft.data.mediaDescriptions, - visibility: draft.data.visibility, - language: draft.data.language, - contentType: draft.data.contentType + if (!this.statusId) { + let draftKey = 'status'; + if (this.replyTo) { + draftKey = 'reply:' + this.replyTo; + } else if (this.quoteId) { + draftKey = 'quote:' + this.quoteId; } - if (draft.data.poll) { - this.togglePollForm(); + const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[draftKey]; + + if (draft) { + statusParams = { + spoilerText: draft.data.spoilerText, + status: draft.data.status, + sensitiveIfSubject, + nsfw: draft.data.nsfw, + files: draft.data.files, + poll: draft.data.poll, + mediaDescriptions: draft.data.mediaDescriptions, + visibility: draft.data.visibility, + language: draft.data.language, + contentType: draft.data.contentType + } + + if (draft.data.poll) { + this.togglePollForm(); + } } } diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index c5fb1688..0da7f3de 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -188,7 +188,7 @@ export default { break } case 'span': - if (this.handleLinks && attrs['class'] && attrs['class'].includes('h-card')) { + if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) { return ['', children.map(processItem), ''] } } diff --git a/src/components/timeline_menu/timeline_menu_content.js b/src/components/timeline_menu/timeline_menu_content.js index df15030b..80cf6937 100644 --- a/src/components/timeline_menu/timeline_menu_content.js +++ b/src/components/timeline_menu/timeline_menu_content.js @@ -8,6 +8,7 @@ import { faHome, faCircle } from '@fortawesome/free-solid-svg-icons' +import { federatedTimelineVisible, publicTimelineVisible, bubbleTimelineVisible } from '../../lib/timeline_visibility' library.add( faUsers, @@ -24,7 +25,9 @@ const TimelineMenuContent = { currentUser: state => state.users.currentUser, privateMode: state => state.instance.private, federating: state => state.instance.federating, - showBubbleTimeline: state => (state.instance.localBubbleInstances.length > 0) + publicTimelineVisible, + federatedTimelineVisible, + bubbleTimelineVisible, }) } } diff --git a/src/components/timeline_menu/timeline_menu_content.vue b/src/components/timeline_menu/timeline_menu_content.vue index 27aece22..bb170b82 100644 --- a/src/components/timeline_menu/timeline_menu_content.vue +++ b/src/components/timeline_menu/timeline_menu_content.vue @@ -16,7 +16,7 @@ >{{ $t("nav.home_timeline") }} -
  • +
  • {{ $t("nav.bubble_timeline") }}
  • -
  • +
  • {{ $t("nav.public_tl") }}
  • -
  • +
  • {{ $t("nav.twkn") }} +
  • diff --git a/src/components/timeline_menu_tabs/timeline_menu_content.js b/src/components/timeline_menu_tabs/timeline_menu_content.js index 9c2ef0c9..00df2120 100644 --- a/src/components/timeline_menu_tabs/timeline_menu_content.js +++ b/src/components/timeline_menu_tabs/timeline_menu_content.js @@ -8,6 +8,7 @@ import { faHome } from '@fortawesome/free-solid-svg-icons' import { faCircle } from '@fortawesome/free-regular-svg-icons' +import { federatedTimelineVisible, publicTimelineVisible, bubbleTimelineVisible } from '../../lib/timeline_visibility' library.add( faUsers, faGlobe, @@ -22,7 +23,10 @@ const TimelineMenuContent = { ...mapState({ currentUser: state => state.users.currentUser, privateMode: state => state.instance.private, - federating: state => state.instance.federating + federating: state => state.instance.federating, + publicTimelineVisible, + federatedTimelineVisible, + bubbleTimelineVisible, }) } } diff --git a/src/components/timeline_menu_tabs/timeline_menu_content.vue b/src/components/timeline_menu_tabs/timeline_menu_content.vue index 32548c49..28e58714 100644 --- a/src/components/timeline_menu_tabs/timeline_menu_content.vue +++ b/src/components/timeline_menu_tabs/timeline_menu_content.vue @@ -16,7 +16,7 @@ >{{ $t("nav.home_timeline") }}
  • -
  • +
  • {{ $t("nav.bubble_timeline") }}
  • -
  • +
  • {{ $t("nav.public_tl") }}
  • -
  • +
  • state.users.currentUser, + publicTimelineVisible, + federatedTimelineVisible, + bubbleTimelineVisible, + }) }, methods: { timelineName () { diff --git a/src/components/timeline_menu_tabs/timeline_menu_tabs.vue b/src/components/timeline_menu_tabs/timeline_menu_tabs.vue index f017fa1f..96340508 100644 --- a/src/components/timeline_menu_tabs/timeline_menu_tabs.vue +++ b/src/components/timeline_menu_tabs/timeline_menu_tabs.vue @@ -18,6 +18,7 @@ @@ -41,6 +42,7 @@ 0 会同设置成零一样" }, - "hintV3": "对于阴影,您还可以使用 {0} 表示法来使用其它颜色插槽。", + "hintV3": "对于阴影,你还可以使用 {0} 表示法来使用其它颜色插槽。", "inset": "内阴影", "override": "覆盖", "shadow_id": "阴影 #{value}", @@ -614,24 +871,24 @@ }, "switcher": { "clear_all": "清除全部", - "clear_opacity": "清除透明度", + "clear_opacity": "清除不透明度", "help": { - "fe_downgraded": "PleromaFE 的版本回滚了。", - "fe_upgraded": "PleromaFE 的主题引擎随着版本更新升级了。", - "future_version_imported": "您导入的文件来自更高版本的 FE。", - "migration_napshot_gone": "不知出于何种原因,主题快照缺失了,一些地方可能与您印象中的不符。", - "migration_snapshot_ok": "为保万无一失,加载了主题快照。您可以试着加载主题数据。", - "older_version_imported": "您导入的文件来自旧版本的 FE。", + "fe_downgraded": "PleromaFE 的版本已回滚。", + "fe_upgraded": "PleromaFE 的主题引擎已在版本更新后升级。", + "future_version_imported": "你所导入的文件配置于更高版本的 FE。", + "migration_napshot_gone": "不知出于何种原因,主题快照缺失了,一些地方可能看起来与你记忆中的不太一样。", + "migration_snapshot_ok": "为保万无一失,主题快照已加载。你可以试着加载主题数据。", + "older_version_imported": "你所导入的文件配置于旧版 FE。", "snapshot_missing": "在文件中没有主题快照,所以网站外观可能会与原来预想的不同。", - "snapshot_present": "主题快照已加载,因此所有的值均被覆盖。您可以改为加载主题的实际数据。", - "snapshot_source_mismatch": "版本冲突:很有可能是 FE 版本回滚后再次升级了,如果您使用旧版本的 FE 更改了主题那么您可能需要使用旧版本,否则请使用新版本。", - "upgraded_from_v2": "PleromaFE 已升级,主题会与您记忆中的不太一样。", - "v2_imported": "您导入的文件是旧版 FE 的。我们尽可能保持兼容性,但还是可能出现不一致的情况。" + "snapshot_present": "主题快照已加载,因此所有的值均被覆盖。你可以改为加载主题的实际数据。", + "snapshot_source_mismatch": "版本冲突:很有可能是 FE 版本回滚后再次升级了,如果你使用旧版本的 FE 更改了主题那么你可能需要使用旧版本,否则请使用新版本。", + "upgraded_from_v2": "PleromaFE 已升级,主题可能看起来与你记忆中的不太一样。", + "v2_imported": "你所导入的文件配置于旧版 FE。我们尽可能提高兼容性,但还是可能出现不一致的情况。" }, "keep_as_is": "保持原状", "keep_color": "保留颜色", "keep_fonts": "保留字体", - "keep_opacity": "保留透明度", + "keep_opacity": "保留不透明度", "keep_roundness": "保留圆角", "keep_shadows": "保留阴影", "load_theme": "加载主题", @@ -641,27 +898,38 @@ "use_source": "新版本" } }, - "subject_input_always_show": "总是显示主题框", - "subject_line_behavior": "回复时复制主题", - "subject_line_email": "类似电子邮件: \"re: 主题\"", + "subject_input_always_show": "始终显示内容警告字段", + "subject_line_behavior": "回复时复制内容警告", + "subject_line_email": "类似电子邮件:\"re: 警告\"", "subject_line_mastodon": "类似 mastodon: 与原主题相同", "subject_line_noop": "不要复制", "text": "文本", "theme": "主题", "theme_help": "使用十六进制代码(#rrggbb)来设置主题颜色。", - "theme_help_v2_1": "您也可以通过选中复选框来覆盖某些组件的颜色和透明度。使用“清除所有”按钮来清除所有覆盖设置。", - "theme_help_v2_2": "某些条目下的图标是背景或文本对比指示器,鼠标悬停可以获取详细信息。请记住,使用透明度来显示最差的情况。", + "theme_help_v2_1": "你也可以通过选中复选框来覆盖某些组件的颜色和不透明度。使用“清除所有”按钮来清除所有覆盖设置。", + "theme_help_v2_2": "某些条目下的图标是背景或文本对比度指示器,悬停在上方以获取详细信息。请记住,当使用透明度对比指标时,显示的是最坏的情况。", + "third_column_mode": "当有足够的空间时,显示第三栏包含", + "third_column_mode_none": "完全不显示第三栏", + "third_column_mode_notifications": "通知栏", + "third_column_mode_postform": "主要的发布窗口和导航", "token": "令牌", "tooltipRadius": "提醒", - "type_domains_to_mute": "搜索需要隐藏的域名", + "translation_language": "自动翻译语言", + "tree_advanced": "显示额外的按钮来打开和关闭同主题帖文中的回复链", + "tree_fade_ancestors": "在当前帖子中以淡色文本显示其原型帖子", + "type_domains_to_mute": "搜索需要静音的域名", "upload_a_photo": "上传照片", - "useStreamingApi": "实时接收帖子和通知", - "useStreamingApiWarning": "(不推荐使用,试验性,已知会跳过一些帖子)", + "useStreamingApi": "实时接收帖文和通知", + "useStreamingApiWarning": "(不推荐使用,试验性,已知会跳过一些帖文)", + "use_at_icon": "将 {'@'} 符号显示为图标而不是文本", + "use_blurhash": "对NSFW的缩略图使用模糊处理", "use_contain_fit": "生成缩略图时不要裁剪附件", "use_one_click_nsfw": "点击一次以打开工作场所不适宜(NSFW)的附件", "user_mutes": "用户", + "user_profile_default_tab": "用户资料中的默认标签页", + "user_profiles": "用户资料", "user_settings": "用户设置", - "valid_until": "有效期至", + "valid_until": "有效期到", "values": { "false": "否", "true": "是" @@ -672,39 +940,91 @@ "title": "版本" }, "virtual_scrolling": "优化时间线渲染", - "word_filter": "词语过滤" + "word_filter": "词语过滤", + "wordfilter": "词语过滤器" + }, + "settings_profile": { + "creating": "创建新的设置配置文件 \"{profile}\" 中...", + "synchronization_error": "无法同步设置:{err}", + "synchronized": "设置已同步!", + "synchronizing": "同步新的设置配置文件 \"{profile}\" 中..." }, "status": { + "ancestor_follow": "查看此帖文下其它 {numReplies} 条回复", + "ancestor_follow_with_icon": "{icon} {text}", + "attachment_stop_flash": "停止 Flash 播放器", "bookmark": "书签", - "copy_link": "复制状态链接", - "delete": "删除状态", - "delete_confirm": "你真的想要删除这条状态吗?", + "collapse_attachments": "折起附件", + "copy_link": "复制帖文链接", + "delete": "删除帖文", + "delete_confirm": "你真的想要删除此帖文吗?", + "delete_confirm_accept_button": "是,删除它", + "delete_confirm_cancel_button": "否,保留它", + "delete_confirm_title": "确认删除", + "edit": "编辑", + "edit_history": "编辑历史", + "edit_history_modal_title": "已编辑 {historyCount} 次", + "edited_at": "编辑于 {time}", "expand": "展开", "external_source": "外部来源", "favorites": "喜欢", + "hide_attachment": "隐藏附件", "hide_content": "隐藏内容", - "hide_full_subject": "隐藏此部分标题", - "mute_conversation": "隐藏对话", + "hide_full_subject": "隐藏全部内容警告", + "many_attachments": "帖文有 {number} 个附件", + "mentions": "提及", + "move_down": "把附件右移", + "move_up": "把附件左移", + "mute_conversation": "静音对话", "nsfw": "NSFW", + "open_gallery": "打开图库", + "override_translation_source_language": "覆盖源语言", "pin": "在个人资料置顶", "pinned": "置顶", + "plus_more": "还有 {number} 个", + "redraft": "删除并改写", + "redraft_confirm": "你确定要删除并改写此帖文吗?与原帖文的互动将不会被保留。", + "redraft_confirm_accept_button": "是,删除并改写", + "redraft_confirm_cancel_button": "否,保持原样", + "redraft_confirm_title": "确认删除并改写", + "remove_attachment": "移除附件", + "repeat_confirm": "你确定要转发此帖文吗?", + "repeat_confirm_accept_button": "是,转发它", + "repeat_confirm_cancel_button": "否,不要转发", + "repeat_confirm_title": "确认转发", "repeats": "转发", "replies_list": "回复:", + "replies_list_with_others": "查看 {numReplies} 条更多回复", "reply_to": "回复", + "show_all_attachments": "显示所有附件", + "show_all_conversation": "显示完整对话(其它 {numStatus} 条帖文)", + "show_all_conversation_with_icon": "{icon} {text}", + "show_attachment_description": "预览描述(打开附件能看完整描述)", + "show_attachment_in_modal": "在窗口中显示附件", "show_content": "显示内容", - "show_full_subject": "显示全部标题", - "status_deleted": "该状态已被删除", - "status_unavailable": "状态不可取得", - "thread_muted": "此系列消息已被隐藏", + "show_full_subject": "显示全部内容警告", + "show_only_conversation_under_this": "仅显示此帖文的回复", + "status_deleted": "此帖文已被删除", + "status_unavailable": "帖文不可用", + "thread_follow": "查看 {numStatus} 条更多回复", + "thread_follow_with_icon": "{icon} {text}", + "thread_hide": "隐藏此同主题帖文", + "thread_muted": "同主题帖文已被静音", "thread_muted_and_words": ",含有过滤词:", + "thread_show": "显示这个同主题帖文", + "thread_show_full": "显示 {numStatus} 条回复 | 显示全部 {numStatus} 条回复", + "thread_show_full_with_icon": "{icon} {text}", + "translate": "翻译", + "translated_from": "翻译自 {language}", "unbookmark": "取消书签", - "unmute_conversation": "对话取消隐藏", - "unpin": "取消在个人资料置顶" + "unmute_conversation": "对话取消静音", + "unpin": "取消在个人资料置顶", + "you": "(你)" }, "time": { - "in_future": "还有 {0}", + "in_future": "{0} 之后", "in_past": "{0} 之前", - "now": "刚刚", + "now": "刚才", "now_short": "刚刚", "unit": { "days": "{0} 天", @@ -726,24 +1046,30 @@ "timeline": { "collapse": "折叠", "conversation": "对话", - "error": "取得时间轴时发生错误:{0}", - "load_older": "加载更早的状态", - "no_more_statuses": "没有更多的状态", - "no_retweet_hint": "这条内容仅关注者可见,或者是私信,因此不能转发", - "no_statuses": "没有状态更新", + "error": "获取时间线时发生错误:{0}", + "follow_tag": "关注话题标签", + "load_older": "加载更早的帖文", + "no_more_statuses": "没有更多的帖文", + "no_retweet_hint": "帖文仅关注者可见,或者是私信,因此不能转发或引用", + "no_statuses": "没有帖文更新", "reload": "重新载入", - "repeated": "转发了", - "show_new": "显示新内容", + "repeated": "已转发", + "show_new": "显示新帖文", "socket_broke": "丢失实时连接:CloseEvent code {0}", "socket_reconnected": "已建立实时连接", + "unfollow_tag": "取消关注话题标签", "up_to_date": "已是最新" }, + "toast": { + "no_translation_target_set": "没有设置翻译目标语言 - 这可能会失败。请在你的设置中设置目标语言。" + }, "tool_tip": { "accept_follow_request": "接受关注请求", "add_reaction": "添加互动", "bookmark": "书签", "favorite": "喜欢", "media_upload": "上传媒体", + "quote": "引用", "reject_follow_request": "拒绝关注请求", "repeat": "转发", "reply": "回复", @@ -751,8 +1077,8 @@ }, "upload": { "error": { - "base": "上传不成功。", - "default": "迟些再试", + "base": "上传失败。", + "default": "稍后再试", "file_too_big": "文件太大了 [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]", "message": "上传错误:{0}" }, @@ -770,31 +1096,51 @@ "deactivate_account": "关闭账号", "delete_account": "删除账号", "delete_user": "删除用户", + "delete_user_data_and_deactivate_confirmation": "这将永久删除该账号的数据并停用该账号。你完全确定吗?", "disable_any_subscription": "完全禁止关注用户", "disable_remote_subscription": "禁止从远程实例关注用户", - "force_nsfw": "标记所有的帖子都是 - 工作场合不适", - "force_unlisted": "强制帖子为不公开", - "grant_admin": "赋予管理权限", + "force_nsfw": "标记所有帖文为NSFW", + "force_unlisted": "强制帖文设为不公开", + "grant_admin": "赋予管理员权限", "grant_moderator": "赋予监察员权限", "moderation": "仲裁", - "quarantine": "从联合实例中禁止用户帖子", + "quarantine": "禁止用户贴文发送至其它实例", "revoke_admin": "撤销管理权限", "revoke_moderator": "撤销监察员权限", - "sandbox": "强制帖子为只有关注者可看", - "strip_media": "从帖子里删除媒体文件" + "sandbox": "强制帖文设为仅关注者", + "strip_media": "从帖文里删除媒体文件" }, - "approve": "核准", + "approve": "批准", + "approve_confirm": "你确定要让此用户关注你吗?", + "approve_confirm_accept_button": "是,接受", + "approve_confirm_cancel_button": "否,取消", + "approve_confirm_title": "通过关注请求", "block": "屏蔽", - "block_progress": "正在屏蔽…", + "block_confirm": "你确定要屏蔽 {user} 吗?", + "block_confirm_accept_button": "是,屏蔽", + "block_confirm_cancel_button": "否,不要屏蔽", + "block_confirm_title": "屏蔽用户", + "block_progress": "屏蔽中…", "blocked": "已屏蔽!", + "blocks_you": "屏蔽了你!", "bot": "机器人", + "deactivated": "已停用", "deny": "拒绝", + "deny_confirm": "你确定要拒绝此用户的关注请求吗?", + "deny_confirm_accept_button": "是,拒绝", + "deny_confirm_cancel_button": "否,取消", + "deny_confirm_title": "拒绝关注请求", + "domain_muted": "取消屏蔽域名", "edit_profile": "编辑个人资料", "favorites": "喜欢", "follow": "关注", + "follow_cancel": "取消请求", "follow_progress": "请求中…", "follow_sent": "请求已发送!", + "follow_tag": "关注话题标签", "follow_unfollow": "取消关注", + "followed_tags": "已关注话题标签", + "followed_users": "已关注用户", "followees": "正在关注", "followers": "关注者", "following": "正在关注!", @@ -811,37 +1157,53 @@ "media": "媒体", "mention": "提及", "message": "消息", - "mute": "隐藏", - "mute_progress": "隐藏中…", - "muted": "已隐藏", + "mute": "静音", + "mute_confirm": "你确定要静音 {user} 吗?", + "mute_confirm_accept_button": "是,静音", + "mute_confirm_cancel_button": "否,不要静音", + "mute_confirm_title": "静音用户", + "mute_domain": "屏蔽域名", + "mute_progress": "静音中…", + "muted": "已静音", + "not_following_any_hashtags": "你没有关注任何话题标签", + "note": "私有备注", "per_day": "每天", "remote_follow": "跨站关注", - "report": "报告", + "remove_follower": "移除关注者", + "replies": "和回复", + "report": "举报", + "requested_by": "已请求关注你", "show_repeats": "显示转发", - "statuses": "状态", + "statuses": "帖文", "subscribe": "订阅", "unblock": "取消屏蔽", - "unblock_progress": "正在取消屏蔽…", - "unmute": "取消隐藏", - "unmute_progress": "取消隐藏中…", + "unblock_progress": "取消屏蔽中…", + "unfollow_confirm": "你确定要取消关注 {user} 吗?", + "unfollow_confirm_accept_button": "是,取消关注", + "unfollow_confirm_cancel_button": "否,不要取消关注", + "unfollow_confirm_title": "取消关注用户", + "unfollow_tag": "取消关注话题标签", + "unmute": "取消静音", + "unmute_progress": "取消静音中…", "unsubscribe": "退订" }, "user_profile": { + "field_validated": "链接已验证", "profile_does_not_exist": "抱歉,此个人资料不存在。", "profile_loading_error": "抱歉,载入个人资料时出错。", "timeline_title": "用户时间线" }, "user_reporting": { - "add_comment_description": "此报告会发送给您的实例监察员。您可以在下面提供更多详细信息解释报告的缘由:", - "additional_comments": "其它信息", - "forward_description": "这个账号来自另一个服务器。是否同时发送一份报告副本到那里?", - "forward_to": "转发 {0}", - "generic_error": "当处理您的请求时,发生了一个错误。", + "add_comment_description": "此举报会发送给你所在实例的监察员。你可以在下面提供更多详细信息解释举报的缘由:", + "additional_comments": "补充意见", + "forward_description": "此账号来自另一个服务器。是否也发送一份举报的副本到那里?", + "forward_to": "转发到 {0}", + "generic_error": "当处理你的请求时,发生了一个错误。", "submit": "提交", - "title": "报告 {0}" + "title": "举报 {0} 中" }, "who_to_follow": { "more": "更多", "who_to_follow": "推荐关注" } -} \ No newline at end of file +} diff --git a/src/lib/timeline_visibility.js b/src/lib/timeline_visibility.js new file mode 100644 index 00000000..379f6214 --- /dev/null +++ b/src/lib/timeline_visibility.js @@ -0,0 +1,23 @@ +const timelineVisibleUnauthenticated = (state, timeline) => ( + state.instance.publicTimelineVisibility[timeline] ?? false +); + +const currentUser = (state) => state.users.currentUser; + +const currentUserOrTimelineVisibleUnauthenticated = (state, timeline) => ( + currentUser(state) || timelineVisibleUnauthenticated(state, timeline) +); + +const federatedTimelineAvailable = (state) => state.instance.federatedTimelineAvailable; + +export const federatedTimelineVisible = (state) => ( + federatedTimelineAvailable(state) && currentUserOrTimelineVisibleUnauthenticated(state, 'federated') +); + +export const publicTimelineVisible = (state) => ( + currentUserOrTimelineVisibleUnauthenticated(state, 'local') +); + +export const bubbleTimelineVisible = (state) => ( + state.instance.localBubbleInstances.length > 0 && currentUserOrTimelineVisibleUnauthenticated(state, 'bubble') +); diff --git a/src/modules/users.js b/src/modules/users.js index bc1943c8..9d81f9bc 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -637,13 +637,16 @@ const users = { // Get user mutes store.dispatch('fetchMutes') - store.dispatch('setLayoutWidth', windowWidth()) store.dispatch('setLayoutHeight', windowHeight()) store.dispatch('getSupportedTranslationlanguages') store.dispatch('getSettingsProfile') store.dispatch('listSettingsProfiles') store.dispatch('startFetchingConfig') + store.dispatch('startFetchingAnnouncements') + if (user.role === 'admin' || user.role === 'moderator') { + store.dispatch('startFetchingReports') + } // Fetch our friends store.rootState.api.backendInteractor.fetchFriends({ id: user.id })