parent
d586d1e6f8
commit
2f99c7e9dc
27 changed files with 387 additions and 4 deletions
|
@ -117,6 +117,12 @@ function connectChannel() {
|
|||
withFiles: props.onlyFiles ? true : undefined,
|
||||
withBots: props.withBots,
|
||||
});
|
||||
} else if (props.src === 'bubble') {
|
||||
connection = stream.useChannel('bubbleTimeline', {
|
||||
withRenotes: props.withRenotes,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
withBots: props.withBots,
|
||||
});
|
||||
} else if (props.src === 'global') {
|
||||
connection = stream.useChannel('globalTimeline', {
|
||||
withRenotes: props.withRenotes,
|
||||
|
@ -188,6 +194,13 @@ function updatePaginationQuery() {
|
|||
withFiles: props.onlyFiles ? true : undefined,
|
||||
withBots: props.withBots,
|
||||
};
|
||||
} else if (props.src === 'bubble') {
|
||||
endpoint = 'notes/bubble-timeline';
|
||||
query = {
|
||||
withRenotes: props.withRenotes,
|
||||
withFiles: props.onlyFiles ? true : undefined,
|
||||
withBots: props.withBots,
|
||||
};
|
||||
} else if (props.src === 'global') {
|
||||
endpoint = 'notes/global-timeline';
|
||||
query = {
|
||||
|
|
|
@ -111,6 +111,7 @@ export const obsoleteNotificationTypes = ['pollVote', 'groupInvited'] as const;
|
|||
export const ROLE_POLICIES = [
|
||||
'gtlAvailable',
|
||||
'ltlAvailable',
|
||||
'btlAvailable',
|
||||
'canPublicNote',
|
||||
'canImportNotes',
|
||||
'canInvite',
|
||||
|
|
|
@ -34,6 +34,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template #label>{{ i18n.ts.privacyPolicyUrl }}</template>
|
||||
</MkInput>
|
||||
|
||||
<MkTextarea v-if="bubbleTimelineEnabled" v-model="bubbleTimeline">
|
||||
<template #label>Bubble timeline</template>
|
||||
<template #caption>Choose which instances should be displayed in the bubble.</template>
|
||||
</MkTextarea>
|
||||
|
||||
<MkTextarea v-model="preservedUsernames">
|
||||
<template #label>{{ i18n.ts.preservedUsernames }}</template>
|
||||
<template #caption>{{ i18n.ts.preservedUsernamesDescription }}</template>
|
||||
|
@ -76,8 +81,10 @@ import FormLink from '@/components/form/link.vue';
|
|||
let enableRegistration: boolean = $ref(false);
|
||||
let emailRequiredForSignup: boolean = $ref(false);
|
||||
let approvalRequiredForSignup: boolean = $ref(false);
|
||||
let bubbleTimelineEnabled: boolean = $ref(false);
|
||||
let sensitiveWords: string = $ref('');
|
||||
let preservedUsernames: string = $ref('');
|
||||
let bubbleTimeline: string = $ref('');
|
||||
let tosUrl: string | null = $ref(null);
|
||||
let privacyPolicyUrl: string | null = $ref(null);
|
||||
|
||||
|
@ -90,6 +97,8 @@ async function init() {
|
|||
preservedUsernames = meta.preservedUsernames.join('\n');
|
||||
tosUrl = meta.tosUrl;
|
||||
privacyPolicyUrl = meta.privacyPolicyUrl;
|
||||
bubbleTimeline = meta.bubbleInstances.join('\n');
|
||||
bubbleTimelineEnabled = meta.policies.btlAvailable;
|
||||
}
|
||||
|
||||
function save() {
|
||||
|
@ -101,6 +110,7 @@ function save() {
|
|||
privacyPolicyUrl,
|
||||
sensitiveWords: sensitiveWords.split('\n'),
|
||||
preservedUsernames: preservedUsernames.split('\n'),
|
||||
bubbleInstances: bubbleTimeline.split('\n'),
|
||||
}).then(() => {
|
||||
fetchInstance();
|
||||
});
|
||||
|
|
|
@ -120,6 +120,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.btlAvailable, 'btlAvailable'])">
|
||||
<template #label>{{ i18n.ts._role._options.btlAvailable }}</template>
|
||||
<template #suffix>
|
||||
<span v-if="role.policies.btlAvailable.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
||||
<span v-else>{{ role.policies.btlAvailable.value ? i18n.ts.yes : i18n.ts.no }}</span>
|
||||
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.btlAvailable)"></i></span>
|
||||
</template>
|
||||
<div class="_gaps">
|
||||
<MkSwitch v-model="role.policies.btlAvailable.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||
</MkSwitch>
|
||||
<MkSwitch v-model="role.policies.btlAvailable.value" :disabled="role.policies.btlAvailable.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange v-model="role.policies.btlAvailable.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
||||
</MkRange>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.ltlAvailable, 'ltlAvailable'])">
|
||||
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
||||
<template #suffix>
|
||||
|
|
|
@ -32,6 +32,17 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkSwitch>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.btlAvailable, 'btlAvailable'])">
|
||||
<template #label>{{ i18n.ts._role._options.btlAvailable }}</template>
|
||||
<template #suffix>{{ policies.btlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
<div class="_gaps_s">
|
||||
<MkInfo :warn="true">After enabling this option navigate to the Moderation section to configure which instances should be shown.</MkInfo>
|
||||
<MkSwitch v-model="policies.btlAvailable">
|
||||
<template #label>{{ i18n.ts.enable }}</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.ltlAvailable, 'ltlAvailable'])">
|
||||
<template #label>{{ i18n.ts._role._options.ltlAvailable }}</template>
|
||||
<template #suffix>{{ policies.ltlAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||
|
@ -232,6 +243,7 @@ import MkFolder from '@/components/MkFolder.vue';
|
|||
import MkSwitch from '@/components/MkSwitch.vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import MkRange from '@/components/MkRange.vue';
|
||||
import MkInfo from '@/components/MkInfo.vue';
|
||||
import MkRolePreview from '@/components/MkRolePreview.vue';
|
||||
import * as os from '@/os.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
|
|
|
@ -54,6 +54,7 @@ provide('shouldOmitHeaderTitle', true);
|
|||
|
||||
const isLocalTimelineAvailable = ($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable);
|
||||
const isGlobalTimelineAvailable = ($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable);
|
||||
const isBubbleTimelineAvailable = ($i == null && instance.policies.btlAvailable) || ($i != null && $i.policies.btlAvailable);
|
||||
const keymap = {
|
||||
't': focus,
|
||||
};
|
||||
|
@ -207,6 +208,11 @@ const headerTabs = $computed(() => [...(defaultStore.reactiveState.pinnedUserLis
|
|||
title: i18n.ts._timelines.social,
|
||||
icon: 'ph-rocket-launch ph-bold ph-lg',
|
||||
iconOnly: true,
|
||||
}] : []), ...(isBubbleTimelineAvailable ? [{
|
||||
key: 'bubble',
|
||||
title: 'Bubble',
|
||||
icon: 'ph-drop ph-bold ph-lg',
|
||||
iconOnly: true,
|
||||
}] : []), ...(isGlobalTimelineAvailable ? [{
|
||||
key: 'global',
|
||||
title: i18n.ts._timelines.global,
|
||||
|
|
|
@ -29,7 +29,7 @@ export type Column = {
|
|||
channelId?: string;
|
||||
roleId?: string;
|
||||
excludeTypes?: typeof notificationTypes[number][];
|
||||
tl?: 'home' | 'local' | 'social' | 'global';
|
||||
tl?: 'home' | 'local' | 'social' | 'global' | 'bubble';
|
||||
withRenotes?: boolean;
|
||||
withReplies?: boolean;
|
||||
onlyFiles?: boolean;
|
||||
|
|
|
@ -9,11 +9,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<i v-if="column.tl === 'home'" class="ph-house ph-bold ph-lg"></i>
|
||||
<i v-else-if="column.tl === 'local'" class="ph-planet ph-bold ph-lg"></i>
|
||||
<i v-else-if="column.tl === 'social'" class="ph-rocket-launch ph-bold ph-lg"></i>
|
||||
<i v-else-if="column.tl === 'bubble'" class="ph-thumb-up ph-bold ph-lg"></i>
|
||||
<i v-else-if="column.tl === 'global'" class="ph-globe-hemisphere-west ph-bold ph-lg"></i>
|
||||
<span style="margin-left: 8px;">{{ column.name }}</span>
|
||||
</template>
|
||||
|
||||
<div v-if="(((column.tl === 'local' || column.tl === 'social') && !isLocalTimelineAvailable) || (column.tl === 'global' && !isGlobalTimelineAvailable))" :class="$style.disabled">
|
||||
<div v-if="(((column.tl === 'local' || column.tl === 'social') && !isLocalTimelineAvailable) || (column.tl === 'bubble' && !isBubbleTimelineAvailable)) || (column.tl === 'global' && !isGlobalTimelineAvailable))" :class="$style.disabled">
|
||||
<p :class="$style.disabledTitle">
|
||||
<i class="ph-minus-circle ph-bold ph-lg"></i>
|
||||
{{ i18n.ts._disabledTimeline.title }}
|
||||
|
@ -52,6 +53,7 @@ let timeline = $shallowRef<InstanceType<typeof MkTimeline>>();
|
|||
|
||||
const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
|
||||
const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
|
||||
const isBubbleTimelineAvailable = ($i == null && instance.policies.btlAvailable) || ($i != null && $i.policies.btlAvailable);
|
||||
const withRenotes = $ref(props.column.withRenotes ?? true);
|
||||
const withReplies = $ref(props.column.withReplies ?? false);
|
||||
const onlyFiles = $ref(props.column.onlyFiles ?? false);
|
||||
|
@ -80,7 +82,8 @@ onMounted(() => {
|
|||
} else if ($i) {
|
||||
disabled = (
|
||||
(!((instance.policies.ltlAvailable) || ($i.policies.ltlAvailable)) && ['local', 'social'].includes(props.column.tl)) ||
|
||||
(!((instance.policies.gtlAvailable) || ($i.policies.gtlAvailable)) && ['global'].includes(props.column.tl)));
|
||||
(!((instance.policies.gtlAvailable) || ($i.policies.gtlAvailable)) && ['global'].includes(props.column.tl)) ||
|
||||
(!((instance.policies.btlAvailable) || ($i.policies.btlAvailable)) && ['bubble'].includes(props.column.tl)));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -93,6 +96,8 @@ async function setType() {
|
|||
value: 'local' as const, text: i18n.ts._timelines.local,
|
||||
}, {
|
||||
value: 'social' as const, text: i18n.ts._timelines.social,
|
||||
}, {
|
||||
value: 'bubble' as const, text: 'Bubble',
|
||||
}, {
|
||||
value: 'global' as const, text: i18n.ts._timelines.global,
|
||||
}],
|
||||
|
|
|
@ -9,6 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<i v-if="widgetProps.src === 'home'" class="ph-house ph-bold ph-lg"></i>
|
||||
<i v-else-if="widgetProps.src === 'local'" class="ph-planet ph-bold ph-lg"></i>
|
||||
<i v-else-if="widgetProps.src === 'social'" class="ph-rocket-launch ph-bold ph-lg"></i>
|
||||
<i v-else-if="widgetProps.src === 'bubble'" class="ph-drop ph-bold ph-lg"></i>
|
||||
<i v-else-if="widgetProps.src === 'global'" class="ph-globe-hemisphere-west ph-bold ph-lg"></i>
|
||||
<i v-else-if="widgetProps.src === 'list'" class="ph-list ph-bold ph-lg"></i>
|
||||
<i v-else-if="widgetProps.src === 'antenna'" class="ph-flying-saucer ph-bold ph-lg"></i>
|
||||
|
@ -20,7 +21,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</button>
|
||||
</template>
|
||||
|
||||
<div v-if="(((widgetProps.src === 'local' || widgetProps.src === 'social') && !isLocalTimelineAvailable) || (widgetProps.src === 'global' && !isGlobalTimelineAvailable))" :class="$style.disabled">
|
||||
<div v-if="(((widgetProps.src === 'local' || widgetProps.src === 'social') && !isLocalTimelineAvailable) || (widgetProps.src === 'bubble' && !isBubbleTimelineAvailable) || (widgetProps.src === 'global' && !isGlobalTimelineAvailable))" :class="$style.disabled">
|
||||
<p :class="$style.disabledTitle">
|
||||
<i class="ph-minus ph-bold ph-lg"></i>
|
||||
{{ i18n.ts._disabledTimeline.title }}
|
||||
|
@ -47,6 +48,7 @@ import { instance } from '@/instance.js';
|
|||
const name = 'timeline';
|
||||
const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
|
||||
const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
|
||||
const isBubbleTimelineAvailable = (($i == null && instance.policies.btlAvailable) || ($i != null && $i.policies.btlAvailable));
|
||||
|
||||
const widgetPropsDef = {
|
||||
showHeader: {
|
||||
|
@ -126,6 +128,10 @@ const choose = async (ev) => {
|
|||
text: i18n.ts._timelines.social,
|
||||
icon: 'ph-rocket-launch ph-bold ph-lg',
|
||||
action: () => { setSrc('social'); },
|
||||
}, {
|
||||
text: 'Bubble',
|
||||
icon: 'ph-drop ph-bold ph-lg',
|
||||
action: () => { setSrc('bubble'); },
|
||||
}, {
|
||||
text: i18n.ts._timelines.global,
|
||||
icon: 'ph-globe-hemisphere-west ph-bold ph-lg',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue