Skip to content

Commit

Permalink
Fix(frontend):AdvancedSearch (yojo-art#302)
Browse files Browse the repository at this point in the history
  • Loading branch information
penginn-net authored Aug 12, 2024
1 parent 39c4c28 commit fad299c
Show file tree
Hide file tree
Showing 2 changed files with 320 additions and 317 deletions.
291 changes: 147 additions & 144 deletions packages/frontend/src/pages/search.anote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,184 +4,187 @@ SPDX-License-Identifier: AGPL-3.0-only
-->

<template>
<div class="_gaps">
<div class="_gaps">
<div class="_gaps">
<MkSearchInput v-model="searchQuery" :autofocus="true" :large="true" type="search" @enter="search">
<template #prefix><i class="ti ti-search"></i></template>
</MkSearchInput>
<MkFoldableSection :expanded="true">
<template #header>{{ i18n.ts.options }}</template>
<div class="_gaps_m">
<MkRadios v-model="searchOrigin" @update:modelValue="search()">
<template #label>{{ i18n.ts.host }}</template>
<option value="combined" default>{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option v-if="noteSearchableScope === 'global'" value="remote">{{ i18n.ts.remote }}</option>
<option v-if="noteSearchableScope === 'global'" value="specified">{{ i18n.ts.specifyHost }}</option>
</MkRadios>
<MkSearchInput v-if="noteSearchableScope === 'global'" v-model="hostInput" :disabled="searchOrigin !== 'specified'" :large="true" type="search">
<template #prefix><i class="ti ti-server"></i></template>
</MkSearchInput>
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts.options }}</template>
<template v-if="user" #suffix>@{{ user.username }}{{ user.host ? `@${user.host}` : "" }}</template>
<div class="_gaps">
<div :class="$style.userItem">
<MkUserCardMini v-if="user" :class="$style.userCard" :user="user" :withChart="false"/>
<MkSearchInput v-model="searchQuery" :autofocus="true" :large="true" type="search" @enter="search">
<template #prefix><i class="ti ti-search"></i></template>
</MkSearchInput>
<MkFoldableSection :expanded="true">
<template #header>{{ i18n.ts.options }}</template>
<div class="_gaps_m">
<MkRadios v-model="searchOrigin" @update:modelValue="search()">
<template #label>{{ i18n.ts.host }}</template>
<option value="combined" default>{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option v-if="noteSearchableScope == 'global'" value="remote">{{ i18n.ts.remote }}</option>
<option v-if="noteSearchableScope == 'global'" value="specified">{{ i18n.ts.specifyHost }}</option>
</MkRadios>
<MkSearchInput v-if="noteSearchableScope === 'global'" v-model="hostInput" :disabled="user != null || searchOrigin == 'combined' || searchOrigin == 'local' || searchOrigin === 'remote'" :large="true" type="search">
<template #prefix><i class="ti ti-server"></i></template>
</MkSearchInput>
<MkFolder :defaultOpen="true">
<template #label>{{ i18n.ts.options }}</template>
<template v-if="user" #suffix>@{{ user.username }}{{ user.host ? `@${user.host}` : "" }}</template>
<div class="_gaps">
<div :class="$style.userItem">
<MkUserCardMini v-if="user" :class="$style.userCard" :user="user" :withChart="false"/>
<MkButton v-if="user == null && $i != null" transparent :class="$style.addMeButton" @click="selectSelf"><div :class="$style.addUserButtonInner"><span><i class="ti ti-plus"></i><i class="ti ti-user"></i></span><span>{{ i18n.ts.selectSelf }}</span></div></MkButton>
<MkButton v-if="user == null" transparent :class="$style.addUserButton" @click="selectUser"><div :class="$style.addUserButtonInner"><i class="ti ti-plus"></i><span>{{ i18n.ts.selectUser }}</span></div></MkButton>
<button class="_button" :class="$style.remove" :disabled="user == null" @click="removeUser"><i class="ti ti-x"></i></button>
</div>
</div>
<FormSection>
<template #label>{{ i18n.ts._advancedSearch._fileOption.title }}</template>
<div style="text-align: center;" class="_gaps_m">
<MkRadios v-model="isfileOnly" @update:modelValue="search()">
<option value="combined">{{ i18n.ts._advancedSearch._fileOption.combined }}</option>
<option value="file-only">{{ i18n.ts._advancedSearch._fileOption.fileAttachedOnly }}</option>
<option value="no-file">{{ i18n.ts._advancedSearch._fileOption.noFile }}</option>
</MkRadios>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._advancedSearch._fileNsfwOption.title }}</template>

<div style="text-align: center;" class="_gaps_m">
<MkRadios v-model="sensitiveFilter" @update:modelValue="search()">
<option value="combined">{{ i18n.ts._advancedSearch._fileNsfwOption.combined }}</option>
<option value="withOutSensitive">{{ i18n.ts._advancedSearch._fileNsfwOption.withOutSensitive }}</option>
<option value="includeSensitive">{{ i18n.ts._advancedSearch._fileNsfwOption.includeSensitive }}</option>
<option value="sensitiveOnly">{{ i18n.ts._advancedSearch._fileNsfwOption.sensitiveOnly }}</option>
</MkRadios>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts.other }}</template>
<template #caption>{{ i18n.ts._advancedSearch._description.other }}</template>
<template #prefix></template>

<div style="text-align: center;" class="_gaps">
<MkSwitch v-model="excludeReply">{{ i18n.ts._advancedSearch._searchOption.toggleReply }}</MkSwitch>
<MkSwitch v-model="excludeCW">{{ i18n.ts._advancedSearch._searchOption.toggleCW }}</MkSwitch>
<MkSwitch v-model="excludeQuote">{{ i18n.ts._advancedSearch._searchOption.toggleQuote }}</MkSwitch>
</div>
</FormSection>
</MkFolder>
</div>
</MkFoldableSection>
<div>
<MkButton large primary gradate rounded style="margin: 0 auto;" @click="search">{{ i18n.ts.search }}</MkButton>
</div>
<FormSection>
<template #label>{{ i18n.ts._advancedSearch._fileOption.title }}</template>
<div style="text-align: center;" class="_gaps_m">
<MkRadios v-model="isfileOnly" @update:modelValue="search()">
<option value="combined">{{ i18n.ts._advancedSearch._fileOption.combined }}</option>
<option value="file-only">{{ i18n.ts._advancedSearch._fileOption.fileAttachedOnly }}</option>
<option value="no-file">{{ i18n.ts._advancedSearch._fileOption.noFile }}</option>
</MkRadios>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._advancedSearch._fileNsfwOption.title }}</template>

<div style="text-align: center;" class="_gaps_m">
<MkRadios v-model="sensitiveFilter" @update:modelValue="search()">
<option value="combined">{{ i18n.ts._advancedSearch._fileNsfwOption.combined }}</option>
<option value="withOutSensitive">{{ i18n.ts._advancedSearch._fileNsfwOption.withOutSensitive }}</option>
<option value="includeSensitive">{{ i18n.ts._advancedSearch._fileNsfwOption.includeSensitive }}</option>
<option value="sensitiveOnly">{{ i18n.ts._advancedSearch._fileNsfwOption.sensitiveOnly }}</option>
</MkRadios>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts.other }}</template>
<template #caption>{{ i18n.ts._advancedSearch._description.other }}</template>
<template #prefix></template>

<div style="text-align: center;" class="_gaps">
<MkSwitch v-model="excludeReply">{{ i18n.ts._advancedSearch._searchOption.toggleReply }}</MkSwitch>
<MkSwitch v-model="excludeCW">{{ i18n.ts._advancedSearch._searchOption.toggleCW }}</MkSwitch>
<MkSwitch v-model="excludeQuote">{{ i18n.ts._advancedSearch._searchOption.toggleQuote }}</MkSwitch>
</div>
</FormSection>
</MkFolder>
</div>
<MkFoldableSection v-if="notePagination">
<template #label>{{ i18n.ts.searchResult }}</template>
<MkNotes :key="key" :pagination="notePagination"/>
</MkFoldableSection>
<div>
<MkButton large primary gradate rounded style="margin: 0 auto;" @click="search">{{ i18n.ts.search }}</MkButton>
</div>
</div>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import MkNotes from '@/components/MkNotes.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkButton from '@/components/MkButton.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkFolder from '@/components/MkFolder.vue';
import { useRouter } from '@/router/supplier.js';
import MkSearchInput from '@/components/MkSearchInput.vue';
import FormSection from '@/components/form/section.vue';
import { $i } from '@/account.js';
import { instance } from '@/instance.js';
import type { UserDetailed } from 'cherrypick-js/entities.js';

const router = useRouter();

const key = ref(0);
const searchQuery = ref('');
const searchOrigin = ref('combined');
const notePagination = ref();
const user = ref<any>(null);
const isLocalOnly = ref(false);
const isfileOnly = ref('combined');
const excludeCW = ref(false);
const excludeReply = ref(false);
const excludeQuote = ref(false);
const sensitiveFilter = ref('combined');
const hostInput = ref('');

const noteSearchableScope = instance.noteSearchableScope ?? 'local';

function selectUser() {
<MkFoldableSection v-if="notePagination">
<template #label>{{ i18n.ts.searchResult }}</template>
<MkNotes :key="key" :pagination="notePagination"/>
</MkFoldableSection>
</div>
</template>

<script lang="ts" setup>
import { ref } from 'vue';
import type { UserDetailed } from 'cherrypick-js/entities.js';
import MkNotes from '@/components/MkNotes.vue';
import MkRadios from '@/components/MkRadios.vue';
import MkButton from '@/components/MkButton.vue';
import MkSwitch from '@/components/MkSwitch.vue';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkFolder from '@/components/MkFolder.vue';
import MkUserCardMini from '@/components/MkUserCardMini.vue';
import { useRouter } from '@/router/supplier.js';
import MkSearchInput from '@/components/MkSearchInput.vue';
import FormSection from '@/components/form/section.vue';
import { $i } from '@/account.js';
import { instance } from '@/instance.js';

const router = useRouter();

const key = ref(0);
const searchQuery = ref('');
const searchOrigin = ref('combined');
const notePagination = ref();
const user = ref<any>(null);
const isLocalOnly = ref(false);
const isfileOnly = ref('combined');
const excludeCW = ref(false);
const excludeReply = ref(false);
const excludeQuote = ref(false);
const sensitiveFilter = ref('combined');
const hostInput = ref('');

const noteSearchableScope = instance.noteSearchableScope ?? 'local';

function selectUser() {
os.selectUser({ includeSelf: true, localOnly: instance.noteSearchableScope === 'local' }).then(_user => {
user.value = _user;
hostInput.value = _user.host ?? '';
searchOrigin.value = 'specified';
});
}

function selectSelf() {
user.value = $i as UserDetailed | null;
hostInput.value = null;
searchOrigin.value = 'local';
}

function removeUser() {
user.value = null;
hostInput.value = '';
}

async function search() {
const query = searchQuery.value.toString().trim();
async function search() {
const query = searchQuery.value.toString().trim();

if (query == null || query === '') return;

if (query.startsWith('https://')) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts._searchOrApShow.question,
okText: i18n.ts._searchOrApShow.lookup,
cancelText: i18n.ts._searchOrApShow.search,
});
if (query == null || query === '') return;

if (!canceled) {
const promise = misskeyApi('ap/show', {
uri: query,
});
if (query.startsWith('https://')) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts._searchOrApShow.question,
okText: i18n.ts._searchOrApShow.lookup,
cancelText: i18n.ts._searchOrApShow.search,
});

os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);
if (!canceled) {
const promise = misskeyApi('ap/show', {
uri: query,
});

const res = await promise;
os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);

if (res.type === 'User') {
router.push(`/@${res.object.username}@${res.object.host}`);
} else if (res.type === 'Note') {
router.push(`/notes/${res.object.id}`);
}
const res = await promise;

return;
if (res.type === 'User') {
router.push(`/@${res.object.username}@${res.object.host}`);
} else if (res.type === 'Note') {
router.push(`/notes/${res.object.id}`);
}

return;
}
notePagination.value = {
endpoint: 'notes/advanced-search',
limit: 10,
params: {
query: searchQuery.value,
userId: user.value ? user.value.id : null,
...(searchOrigin.value === 'specified' ? { host: hostInput.value } : { origin: searchOrigin.value }),
fileOption: isfileOnly.value,
excludeCW: excludeCW.value,
excludeReply: excludeReply.value,
excludeQuote: excludeQuote.value,
sensitiveFilter: sensitiveFilter.value,
},
};

if (isLocalOnly.value) notePagination.value.params.host = '.';

key.value++;
}
notePagination.value = {
endpoint: 'notes/advanced-search',
limit: 10,
params: {
query: searchQuery.value,
userId: user.value ? user.value.id : null,
...(searchOrigin.value === 'specified' ? { host: hostInput.value } : { origin: searchOrigin.value }),
fileOption: isfileOnly.value,
excludeCW: excludeCW.value,
excludeReply: excludeReply.value,
excludeQuote: excludeQuote.value,
sensitiveFilter: sensitiveFilter.value,
},
};

if (isLocalOnly.value) notePagination.value.params.host = '.';

key.value++;
}
</script>
<style lang="scss" module>
.userItem {
Expand Down
Loading

0 comments on commit fad299c

Please sign in to comment.