Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 2つの検索画面の統合 (#9949) #10038

Merged
merged 8 commits into from
Feb 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
## 13.x.x (unreleased)

### Improvements
-
- feat: 検索画面の統合 (Khsmty)

### Bugfixes
-
Expand Down
6 changes: 4 additions & 2 deletions packages/frontend/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import { $i, refreshAccount, login, updateAccount, signout } from '@/account';
import { defaultStore, ColdDeviceStorage } from '@/store';
import { fetchInstance, instance } from '@/instance';
import { makeHotkey } from '@/scripts/hotkey';
import { search } from '@/scripts/search';
import { deviceKind } from '@/scripts/device-kind';
import { initializeSw } from '@/scripts/initialize-sw';
import { reloadChannel } from '@/scripts/unison-reload';
Expand All @@ -47,6 +46,7 @@ import { deckStore } from './ui/deck/deck-store';
import { miLocalStorage } from './local-storage';
import { claimAchievement, claimedAchievements } from './scripts/achievements';
import { fetchCustomEmojis } from './custom-emojis';
import { mainRouter } from './router';

console.info(`Misskey v${version}`);

Expand Down Expand Up @@ -352,7 +352,9 @@ const hotkeys = {
'd': (): void => {
defaultStore.set('darkMode', !defaultStore.state.darkMode);
},
's': search,
's': (): void => {
mainRouter.push('/search');
}
};

if ($i) {
Expand Down
3 changes: 1 addition & 2 deletions packages/frontend/src/navbar.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { computed, reactive } from 'vue';
import { $i } from './account';
import { miLocalStorage } from './local-storage';
import { search } from '@/scripts/search';
import * as os from '@/os';
import { i18n } from '@/i18n';
import { ui } from '@/config';
Expand Down Expand Up @@ -42,7 +41,7 @@ export const navbarItemDef = reactive({
search: {
title: i18n.ts.search,
icon: 'ti ti-search',
action: () => search(),
to: '/search',
},
lists: {
title: i18n.ts.lists,
Expand Down
35 changes: 0 additions & 35 deletions packages/frontend/src/pages/explore.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,6 @@
<div v-else-if="tab === 'roles'">
<XRoles/>
</div>
<div v-else-if="tab === 'search'">
<MkSpacer :content-max="1200">
<div>
<MkInput v-model="searchQuery" :debounce="true" type="search">
<template #prefix><i class="ti ti-search"></i></template>
<template #label>{{ i18n.ts.searchUser }}</template>
</MkInput>
<MkRadios v-model="searchOrigin">
<option value="combined">{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option value="remote">{{ i18n.ts.remote }}</option>
</MkRadios>
</div>

<MkUserList v-if="searchQuery" ref="searchEl" class="_margin" :pagination="searchPagination"/>
</MkSpacer>
</div>
</div>
</MkStickyContainer>
</template>
Expand All @@ -38,11 +21,8 @@ import XFeatured from './explore.featured.vue';
import XUsers from './explore.users.vue';
import XRoles from './explore.roles.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkInput from '@/components/MkInput.vue';
import MkRadios from '@/components/MkRadios.vue';
import { definePageMetadata } from '@/scripts/page-metadata';
import { i18n } from '@/i18n';
import MkUserList from '@/components/MkUserList.vue';

const props = withDefaults(defineProps<{
tag?: string;
Expand All @@ -53,22 +33,11 @@ const props = withDefaults(defineProps<{

let tab = $ref(props.initialTab);
let tagsEl = $shallowRef<InstanceType<typeof MkFoldableSection>>();
let searchQuery = $ref(null);
let searchOrigin = $ref('combined');

watch(() => props.tag, () => {
if (tagsEl) tagsEl.toggleContent(props.tag == null);
});

const searchPagination = {
endpoint: 'users/search' as const,
limit: 10,
params: computed(() => (searchQuery && searchQuery !== '') ? {
query: searchQuery,
origin: searchOrigin,
} : null),
};

const headerActions = $computed(() => []);

const headerTabs = $computed(() => [{
Expand All @@ -83,10 +52,6 @@ const headerTabs = $computed(() => [{
key: 'roles',
icon: 'ti ti-badges',
title: i18n.ts.roles,
}, {
key: 'search',
icon: 'ti ti-search',
title: i18n.ts.search,
}]);

definePageMetadata(computed(() => ({
Expand Down
128 changes: 115 additions & 13 deletions packages/frontend/src/pages/search.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,164 @@
<MkStickyContainer>
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :content-max="800">
<MkNotes ref="notes" :pagination="pagination"/>
<MkInput v-model="searchQuery" :large="true" :autofocus="true" :debounce="true" type="search" style="margin-bottom: var(--margin);" @update:model-value="search()">
<template #prefix><i class="ti ti-search"></i></template>
</MkInput>
<MkTab v-model="searchType" style="margin-bottom: var(--margin);" @update:model-value="search()">
<option value="note">{{ i18n.ts.note }}</option>
<option value="user">{{ i18n.ts.user }}</option>
</MkTab>

<div v-if="searchType === 'note'">
<MkNotes v-if="searchQuery" ref="notes" :pagination="notePagination"/>
</div>
<div v-else>
<MkRadios v-model="searchOrigin" style="margin-bottom: var(--margin);" @update:model-value="search()">
<option value="combined">{{ i18n.ts.all }}</option>
<option value="local">{{ i18n.ts.local }}</option>
<option value="remote">{{ i18n.ts.remote }}</option>
</MkRadios>

<MkUserList v-if="searchQuery" ref="users" :pagination="userPagination"/>
</div>
</MkSpacer>
</MkStickyContainer>
</template>

<script lang="ts" setup>
import { computed } from 'vue';
import { computed, onMounted } from 'vue';
import MkNotes from '@/components/MkNotes.vue';
import MkUserList from '@/components/MkUserList.vue';
import MkInput from '@/components/MkInput.vue';
import MkTab from '@/components/MkTab.vue';
import MkRadios from '@/components/MkRadios.vue';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import * as os from '@/os';
import { useRouter } from '@/router';
import { useRouter, mainRouter } from '@/router';
import { $i } from '@/account';

const router = useRouter();

const props = defineProps<{
query: string;
channel?: string;
type?: string;
origin?: string;
}>();

const query = props.query;
let searchQuery = $ref('');
let searchType = $ref('note');
let searchOrigin = $ref('combined');

onMounted(() => {
searchQuery = props.query ?? '';
searchType = props.type ?? 'note';
searchOrigin = props.origin ?? 'combined';

if (searchQuery) {
search();
}
});

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

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

if (query.startsWith('@') && !query.includes(' ')) {
mainRouter.push(`/${query}`);
return;
}

if (query.startsWith('#')) {
mainRouter.push(`/tags/${encodeURIComponent(query.substr(1))}`);
return;
}

// like 2018/03/12
if (/^[0-9]{4}\/[0-9]{2}\/[0-9]{2}/.test(query.replace(/-/g, '/'))) {
const date = new Date(query.replace(/-/g, '/'));

// 日付しか指定されてない場合、例えば 2018/03/12 ならユーザーは
// 2018/03/12 のコンテンツを「含む」結果になることを期待するはずなので
// 23時間59分進める(そのままだと 2018/03/12 00:00:00 「まで」の
// 結果になってしまい、2018/03/12 のコンテンツは含まれない)
if (query.replace(/-/g, '/').match(/^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$/)) {
date.setHours(23, 59, 59, 999);
}

// TODO
//v.$root.$emit('warp', date);
os.alert({
icon: 'ti ti-history',
iconOnly: true, autoClose: true,
});
return;
}

if ($i != null) {
if (query.startsWith('https://') || (query.startsWith('@') && !query.includes(' '))) {
if (query.startsWith('https://')) {
const promise = os.api('ap/show', {
uri: props.query,
uri: query,
});

os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);

const res = await promise;

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

return;
}
}

const pagination = {
if ($i != null) {
if (query.startsWith('https://') || (query.startsWith('@') && !query.includes(' '))) {
const promise = os.api('ap/show', {
uri: query,
});

os.promiseDialog(promise, null, null, i18n.ts.fetchingAsApObject);

const res = await promise;

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

window.history.replaceState('', '', `/search?q=${encodeURIComponent(query)}&type=${searchType}${searchType === 'user' ? `&origin=${searchOrigin}` : ''}`);
};

const notePagination = {
endpoint: 'notes/search' as const,
limit: 10,
params: computed(() => ({
query: props.query,
query: searchQuery,
channelId: props.channel,
})),
};
const userPagination = {
endpoint: 'users/search' as const,
limit: 10,
params: computed(() => ({
query: searchQuery,
origin: searchOrigin,
})),
};

const headerActions = $computed(() => []);

const headerTabs = $computed(() => []);

definePageMetadata(computed(() => ({
title: i18n.t('searchWith', { q: props.query }),
title: searchQuery ? i18n.t('searchWith', { q: searchQuery }) : i18n.ts.search,
icon: 'ti ti-search',
})));
</script>
2 changes: 2 additions & 0 deletions packages/frontend/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ export const routes = [{
query: {
q: 'query',
channel: 'channel',
type: 'type',
origin: 'origin',
},
}, {
path: '/authorize-follow',
Expand Down
63 changes: 0 additions & 63 deletions packages/frontend/src/scripts/search.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/frontend/src/ui/classic.header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,11 @@
import { defineAsyncComponent, defineComponent } from 'vue';
import { openInstanceMenu } from './_common_/common';
import { host } from '@/config';
import { search } from '@/scripts/search';
import * as os from '@/os';
import { navbarItemDef } from '@/navbar';
import { openAccountMenu } from '@/account';
import MkButton from '@/components/MkButton.vue';
import { mainRouter } from '@/router';

export default defineComponent({
components: {
Expand Down Expand Up @@ -103,7 +103,7 @@ export default defineComponent({
},

search() {
search();
mainRouter.push('/search');
},

more(ev) {
Expand Down
Loading