@@ -244,6 +247,12 @@ const maxTextLength = computed((): number => {
return instance ? instance.maxNoteTextLength : 1000;
});
+const cwTextLength = computed((): number => {
+ return cw.value?.length ?? 0;
+});
+
+const maxCwTextLength = 100;
+
const canPost = computed((): boolean => {
return !props.mock && !posting.value && !posted.value &&
(
@@ -254,6 +263,7 @@ const canPost = computed((): boolean => {
quoteId.value != null
) &&
(textLength.value <= maxTextLength.value) &&
+ (cwTextLength.value <= maxCwTextLength) &&
(files.value.length <= 16) &&
(!poll.value || poll.value.choices.length >= 2);
});
@@ -1273,12 +1283,34 @@ html[data-color-scheme=light] .preview {
}
}
+.cwOuter {
+ width: 100%;
+ position: relative;
+}
+
.cw {
z-index: 1;
padding-bottom: 8px;
border-bottom: solid 0.5px var(--MI_THEME-divider);
}
+.cwTextCount {
+ position: absolute;
+ top: 0;
+ right: 2px;
+ padding: 2px 6px;
+ font-size: .9em;
+ color: var(--MI_THEME-warn);
+ border-radius: 6px;
+ max-width: 100%;
+ min-width: 1.6em;
+ text-align: center;
+
+ &.cwTextOver {
+ color: #ff2a2a;
+ }
+}
+
.hashtags {
z-index: 1;
padding-top: 8px;
diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
index b65038aadc..41e475eade 100644
--- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
@@ -90,6 +90,15 @@ async function toggleReaction() {
}
});
} else {
+ if (defaultStore.state.confirmOnReact) {
+ const confirm = await os.confirm({
+ type: 'question',
+ text: i18n.tsx.reactAreYouSure({ emoji: props.reaction.replace('@.', '') }),
+ });
+
+ if (confirm.canceled) return;
+ }
+
sound.playMisskeySfx('reaction');
if (mock) {
diff --git a/packages/frontend/src/components/MkRemoteCaution.vue b/packages/frontend/src/components/MkRemoteCaution.vue
index a56a4b1671..2d3b7d107d 100644
--- a/packages/frontend/src/components/MkRemoteCaution.vue
+++ b/packages/frontend/src/components/MkRemoteCaution.vue
@@ -4,14 +4,14 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
-
+
diff --git a/packages/frontend/src/components/MkSelect.vue b/packages/frontend/src/components/MkSelect.vue
index 83a79d0c9f..15717802ec 100644
--- a/packages/frontend/src/components/MkSelect.vue
+++ b/packages/frontend/src/components/MkSelect.vue
@@ -41,11 +41,28 @@ SPDX-License-Identifier: AGPL-3.0-only
diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue
index 91f41166e9..a312ecce12 100644
--- a/packages/frontend/src/pages/admin/external-services.vue
+++ b/packages/frontend/src/pages/admin/external-services.vue
@@ -8,20 +8,34 @@ SPDX-License-Identifier: AGPL-3.0-only
-
- DeepL Translation
+
+
+ Google Analytics{{ i18n.ts.beta }}
-
-
-
- DeepL Auth Key
-
-
- Pro account
-
- Save
-
-
+
+
+
+ Measurement ID
+
+ Save
+
+
+
+
+ DeepL Translation
+
+
+
+
+ DeepL Auth Key
+
+
+ Pro account
+
+ Save
+
+
+
@@ -44,10 +58,13 @@ import MkFolder from '@/components/MkFolder.vue';
const deeplAuthKey = ref
('');
const deeplIsPro = ref(false);
+const googleAnalyticsMeasurementId = ref('');
+
async function init() {
const meta = await misskeyApi('admin/meta');
- deeplAuthKey.value = meta.deeplAuthKey;
+ deeplAuthKey.value = meta.deeplAuthKey ?? '';
deeplIsPro.value = meta.deeplIsPro;
+ googleAnalyticsMeasurementId.value = meta.googleAnalyticsMeasurementId ?? '';
}
function save_deepl() {
@@ -59,6 +76,14 @@ function save_deepl() {
});
}
+function save_googleAnalytics() {
+ os.apiWithDialog('admin/update-meta', {
+ googleAnalyticsMeasurementId: googleAnalyticsMeasurementId.value,
+ }).then(() => {
+ fetchInstance(true);
+ });
+}
+
const headerActions = computed(() => []);
const headerTabs = computed(() => []);
diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue
index 870c3ce88b..91104b676d 100644
--- a/packages/frontend/src/pages/admin/users.vue
+++ b/packages/frontend/src/pages/admin/users.vue
@@ -9,6 +9,9 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+ {{ i18n.ts.reset }}
+
{{ i18n.ts.sort }}
@@ -57,8 +60,10 @@ SPDX-License-Identifier: AGPL-3.0-only
diff --git a/packages/frontend/src/pages/search.user.vue b/packages/frontend/src/pages/search.user.vue
index e8bc4cd6d3..2b8faf5465 100644
--- a/packages/frontend/src/pages/search.user.vue
+++ b/packages/frontend/src/pages/search.user.vue
@@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.searchResult }}
-
+
@@ -49,14 +49,16 @@ const props = withDefaults(defineProps<{
const router = useRouter();
-const key = ref('');
+const key = ref(0);
+const userPagination = ref
>();
+
const searchQuery = ref(toRef(props, 'query').value);
const searchOrigin = ref(toRef(props, 'origin').value);
-const userPagination = ref();
async function search() {
const query = searchQuery.value.toString().trim();
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (query == null || query === '') return;
//#region AP lookup
@@ -76,6 +78,7 @@ async function search() {
if (res.type === 'User') {
router.push(`/@${res.object.username}@${res.object.host}`);
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
} else if (res.type === 'Note') {
router.push(`/notes/${res.object.id}`);
}
@@ -118,6 +121,6 @@ async function search() {
},
};
- key.value = query;
+ key.value++;
}
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 1ee7909aa8..4449d6169f 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -170,6 +170,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ i18n.ts.enableHorizontalSwipe }}
{{ i18n.ts.alwaysConfirmFollow }}
{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}
+ {{ i18n.ts.confirmOnReact }}
{{ i18n.ts.whenServerDisconnected }}
@@ -320,6 +321,7 @@ const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHori
const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
const confirmWhenRevealingSensitiveMedia = computed(defaultStore.makeGetterSetter('confirmWhenRevealingSensitiveMedia'));
+const confirmOnReact = computed(defaultStore.makeGetterSetter('confirmOnReact'));
const contextMenu = computed(defaultStore.makeGetterSetter('contextMenu'));
watch(lang, () => {
diff --git a/packages/frontend/src/pages/settings/theme.vue b/packages/frontend/src/pages/settings/theme.vue
index f1ec231588..fcf5b3cd9b 100644
--- a/packages/frontend/src/pages/settings/theme.vue
+++ b/packages/frontend/src/pages/settings/theme.vue
@@ -32,27 +32,13 @@ SPDX-License-Identifier: AGPL-3.0-only