enhance(client): ハイライトをみつけるに統合
This commit is contained in:
		
							parent
							
								
									add6e9b14b
								
							
						
					
					
						commit
						afe0d9a266
					
				
					 7 changed files with 202 additions and 219 deletions
				
			
		|  | @ -11,6 +11,11 @@ You should also include the user name that made the change. | |||
| 
 | ||||
| ## 12.x.x (unreleased) | ||||
| 
 | ||||
| ### Changes | ||||
| - ハイライトがみつけるに統合されました | ||||
| - カスタム絵文字ページはインスタンス情報ページに統合されました | ||||
| - 連合ページはインスタンス情報ページに統合されました | ||||
| 
 | ||||
| ### Improvements | ||||
| - Server: Allow GET method for some endpoints @syuilo | ||||
| - Server: Add rate limit to i/notifications @tamaina | ||||
|  |  | |||
|  | @ -35,11 +35,6 @@ export const menuDef = reactive({ | |||
| 		indicated: computed(() => $i != null && $i.hasPendingReceivedFollowRequest), | ||||
| 		to: '/my/follow-requests', | ||||
| 	}, | ||||
| 	featured: { | ||||
| 		title: 'featured', | ||||
| 		icon: 'fas fa-fire-alt', | ||||
| 		to: '/featured', | ||||
| 	}, | ||||
| 	explore: { | ||||
| 		title: 'explore', | ||||
| 		icon: 'fas fa-hashtag', | ||||
|  |  | |||
							
								
								
									
										16
									
								
								packages/client/src/pages/explore.featured.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								packages/client/src/pages/explore.featured.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| <template> | ||||
| <MkSpacer :content-max="800"> | ||||
| 	<XNotes ref="notes" :pagination="pagination"/> | ||||
| </MkSpacer> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import XNotes from '@/components/notes.vue'; | ||||
| import { i18n } from '@/i18n'; | ||||
| 
 | ||||
| const pagination = { | ||||
| 	endpoint: 'notes/featured' as const, | ||||
| 	limit: 10, | ||||
| 	offsetMode: true, | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										143
									
								
								packages/client/src/pages/explore.users.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								packages/client/src/pages/explore.users.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,143 @@ | |||
| <template> | ||||
| <MkSpacer :content-max="1200"> | ||||
| 	<div v-if="origin === 'local'"> | ||||
| 		<template v-if="tag == null"> | ||||
| 			<MkFolder class="_gap" persist-key="explore-pinned-users"> | ||||
| 				<template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.pinnedUsers }}</template> | ||||
| 				<XUserList :pagination="pinnedUsers"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_gap" persist-key="explore-popular-users"> | ||||
| 				<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template> | ||||
| 				<XUserList :pagination="popularUsers"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_gap" persist-key="explore-recently-updated-users"> | ||||
| 				<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyUpdatedUsers"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_gap" persist-key="explore-recently-registered-users"> | ||||
| 				<template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyRegisteredUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyRegisteredUsers"/> | ||||
| 			</MkFolder> | ||||
| 		</template> | ||||
| 	</div> | ||||
| 	<div v-else> | ||||
| 		<MkFolder ref="tagsEl" :foldable="true" :expanded="false" class="_gap"> | ||||
| 			<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularTags }}</template> | ||||
| 
 | ||||
| 			<div class="vxjfqztj"> | ||||
| 				<MkA v-for="tag in tagsLocal" :key="'local:' + tag.tag" :to="`/explore/tags/${tag.tag}`" class="local">{{ tag.tag }}</MkA> | ||||
| 				<MkA v-for="tag in tagsRemote" :key="'remote:' + tag.tag" :to="`/explore/tags/${tag.tag}`">{{ tag.tag }}</MkA> | ||||
| 			</div> | ||||
| 		</MkFolder> | ||||
| 
 | ||||
| 		<MkFolder v-if="tag != null" :key="`${tag}`" class="_gap"> | ||||
| 			<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template> | ||||
| 			<XUserList :pagination="tagUsers"/> | ||||
| 		</MkFolder> | ||||
| 
 | ||||
| 		<template v-if="tag == null"> | ||||
| 			<MkFolder class="_gap"> | ||||
| 				<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template> | ||||
| 				<XUserList :pagination="popularUsersF"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_gap"> | ||||
| 				<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyUpdatedUsersF"/> | ||||
| 			</MkFolder> | ||||
| 			<MkFolder class="_gap"> | ||||
| 				<template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyDiscoveredUsers }}</template> | ||||
| 				<XUserList :pagination="recentlyRegisteredUsersF"/> | ||||
| 			</MkFolder> | ||||
| 		</template> | ||||
| 	</div> | ||||
| </MkSpacer> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { computed, watch } from 'vue'; | ||||
| import XUserList from '@/components/user-list.vue'; | ||||
| import MkFolder from '@/components/ui/folder.vue'; | ||||
| import number from '@/filters/number'; | ||||
| import * as os from '@/os'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { instance } from '@/instance'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
| 	origin: 'local' | 'remote'; | ||||
| 	tag?: string; | ||||
| }>(); | ||||
| 
 | ||||
| let tagsEl = $ref<InstanceType<typeof MkFolder>>(); | ||||
| let tagsLocal = $ref([]); | ||||
| let tagsRemote = $ref([]); | ||||
| 
 | ||||
| watch(() => props.tag, () => { | ||||
| 	if (tagsEl) tagsEl.toggleContent(props.tag == null); | ||||
| }); | ||||
| 
 | ||||
| const tagUsers = $computed(() => ({ | ||||
| 	endpoint: 'hashtags/users' as const, | ||||
| 	limit: 30, | ||||
| 	params: { | ||||
| 		tag: props.tag, | ||||
| 		origin: 'combined', | ||||
| 		sort: '+follower', | ||||
| 	}, | ||||
| })); | ||||
| 
 | ||||
| const pinnedUsers = { endpoint: 'pinned-users' }; | ||||
| const popularUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	state: 'alive', | ||||
| 	origin: 'local', | ||||
| 	sort: '+follower', | ||||
| } }; | ||||
| const recentlyUpdatedUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'local', | ||||
| 	sort: '+updatedAt', | ||||
| } }; | ||||
| const recentlyRegisteredUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'local', | ||||
| 	state: 'alive', | ||||
| 	sort: '+createdAt', | ||||
| } }; | ||||
| const popularUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	state: 'alive', | ||||
| 	origin: 'remote', | ||||
| 	sort: '+follower', | ||||
| } }; | ||||
| const recentlyUpdatedUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'combined', | ||||
| 	sort: '+updatedAt', | ||||
| } }; | ||||
| const recentlyRegisteredUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'combined', | ||||
| 	sort: '+createdAt', | ||||
| } }; | ||||
| 
 | ||||
| os.api('hashtags/list', { | ||||
| 	sort: '+attachedLocalUsers', | ||||
| 	attachedToLocalUserOnly: true, | ||||
| 	limit: 30, | ||||
| }).then(tags => { | ||||
| 	tagsLocal = tags; | ||||
| }); | ||||
| os.api('hashtags/list', { | ||||
| 	sort: '+attachedRemoteUsers', | ||||
| 	attachedToRemoteUserOnly: true, | ||||
| 	limit: 30, | ||||
| }).then(tags => { | ||||
| 	tagsRemote = tags; | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .vxjfqztj { | ||||
| 	> * { | ||||
| 		margin-right: 16px; | ||||
| 
 | ||||
| 		&.local { | ||||
| 			font-weight: bold; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -1,66 +1,15 @@ | |||
| <template> | ||||
| <MkStickyContainer> | ||||
| 	<template #header><MkPageHeader v-model:tab="tab" :actions="headerActions" :tabs="headerTabs"/></template> | ||||
| 	<MkSpacer :content-max="1200"> | ||||
| 	<div class="lznhrdub"> | ||||
| 			<div v-if="tab === 'local'"> | ||||
| 				<div v-if="instance && stats && tag == null" class="localfedi7 _block _isolated" :style="{ backgroundImage: instance.bannerUrl ? `url(${instance.bannerUrl})` : null }"> | ||||
| 					<header><span>{{ $t('explore', { host: instance.name || 'Misskey' }) }}</span></header> | ||||
| 					<div><span>{{ $t('exploreUsersCount', { count: number(stats.originalUsersCount) }) }}</span></div> | ||||
| 		<div v-if="tab === 'featured'"> | ||||
| 			<XFeatured/> | ||||
| 		</div> | ||||
| 
 | ||||
| 				<template v-if="tag == null"> | ||||
| 					<MkFolder class="_gap" persist-key="explore-pinned-users"> | ||||
| 						<template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.pinnedUsers }}</template> | ||||
| 						<XUserList :pagination="pinnedUsers"/> | ||||
| 					</MkFolder> | ||||
| 					<MkFolder class="_gap" persist-key="explore-popular-users"> | ||||
| 						<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template> | ||||
| 						<XUserList :pagination="popularUsers"/> | ||||
| 					</MkFolder> | ||||
| 					<MkFolder class="_gap" persist-key="explore-recently-updated-users"> | ||||
| 						<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template> | ||||
| 						<XUserList :pagination="recentlyUpdatedUsers"/> | ||||
| 					</MkFolder> | ||||
| 					<MkFolder class="_gap" persist-key="explore-recently-registered-users"> | ||||
| 						<template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyRegisteredUsers }}</template> | ||||
| 						<XUserList :pagination="recentlyRegisteredUsers"/> | ||||
| 					</MkFolder> | ||||
| 				</template> | ||||
| 		<div v-else-if="tab === 'localUsers'"> | ||||
| 			<XUsers origin="local"/> | ||||
| 		</div> | ||||
| 			<div v-else-if="tab === 'remote'"> | ||||
| 				<div v-if="tag == null" class="localfedi7 _block _isolated" :style="{ backgroundImage: `url(/client-assets/fedi.jpg)` }"> | ||||
| 					<header><span>{{ $ts.exploreFediverse }}</span></header> | ||||
| 				</div> | ||||
| 
 | ||||
| 				<MkFolder ref="tagsEl" :foldable="true" :expanded="false" class="_gap"> | ||||
| 					<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularTags }}</template> | ||||
| 
 | ||||
| 					<div class="vxjfqztj"> | ||||
| 						<MkA v-for="tag in tagsLocal" :key="'local:' + tag.tag" :to="`/explore/tags/${tag.tag}`" class="local">{{ tag.tag }}</MkA> | ||||
| 						<MkA v-for="tag in tagsRemote" :key="'remote:' + tag.tag" :to="`/explore/tags/${tag.tag}`">{{ tag.tag }}</MkA> | ||||
| 					</div> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
| 				<MkFolder v-if="tag != null" :key="`${tag}`" class="_gap"> | ||||
| 					<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template> | ||||
| 					<XUserList :pagination="tagUsers"/> | ||||
| 				</MkFolder> | ||||
| 
 | ||||
| 				<template v-if="tag == null"> | ||||
| 					<MkFolder class="_gap"> | ||||
| 						<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template> | ||||
| 						<XUserList :pagination="popularUsersF"/> | ||||
| 					</MkFolder> | ||||
| 					<MkFolder class="_gap"> | ||||
| 						<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template> | ||||
| 						<XUserList :pagination="recentlyUpdatedUsersF"/> | ||||
| 					</MkFolder> | ||||
| 					<MkFolder class="_gap"> | ||||
| 						<template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyDiscoveredUsers }}</template> | ||||
| 						<XUserList :pagination="recentlyRegisteredUsersF"/> | ||||
| 					</MkFolder> | ||||
| 				</template> | ||||
| 		<div v-else-if="tab === 'remoteUsers'"> | ||||
| 			<XUsers origin="remote"/> | ||||
| 		</div> | ||||
| 		<div v-else-if="tab === 'search'"> | ||||
| 			<div class="_isolated"> | ||||
|  | @ -78,13 +27,13 @@ | |||
| 			<XUserList v-if="searchQuery" ref="searchEl" class="_gap" :pagination="searchPagination"/> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	</MkSpacer> | ||||
| </MkStickyContainer> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { computed, defineComponent, watch } from 'vue'; | ||||
| import XUserList from '@/components/user-list.vue'; | ||||
| import { computed, watch } from 'vue'; | ||||
| import XFeatured from './explore.featured.vue'; | ||||
| import XUsers from './explore.users.vue'; | ||||
| import MkFolder from '@/components/ui/folder.vue'; | ||||
| import MkInput from '@/components/form/input.vue'; | ||||
| import MkRadios from '@/components/form/radios.vue'; | ||||
|  | @ -98,11 +47,8 @@ const props = defineProps<{ | |||
| 	tag?: string; | ||||
| }>(); | ||||
| 
 | ||||
| let tab = $ref('local'); | ||||
| let tab = $ref('featured'); | ||||
| let tagsEl = $ref<InstanceType<typeof MkFolder>>(); | ||||
| let tagsLocal = $ref([]); | ||||
| let tagsRemote = $ref([]); | ||||
| let stats = $ref(null); | ||||
| let searchQuery = $ref(null); | ||||
| let searchOrigin = $ref('combined'); | ||||
| 
 | ||||
|  | @ -110,44 +56,6 @@ watch(() => props.tag, () => { | |||
| 	if (tagsEl) tagsEl.toggleContent(props.tag == null); | ||||
| }); | ||||
| 
 | ||||
| const tagUsers = $computed(() => ({ | ||||
| 	endpoint: 'hashtags/users' as const, | ||||
| 	limit: 30, | ||||
| 	params: { | ||||
| 		tag: props.tag, | ||||
| 		origin: 'combined', | ||||
| 		sort: '+follower', | ||||
| 	}, | ||||
| })); | ||||
| 
 | ||||
| const pinnedUsers = { endpoint: 'pinned-users' }; | ||||
| const popularUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	state: 'alive', | ||||
| 	origin: 'local', | ||||
| 	sort: '+follower', | ||||
| } }; | ||||
| const recentlyUpdatedUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'local', | ||||
| 	sort: '+updatedAt', | ||||
| } }; | ||||
| const recentlyRegisteredUsers = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'local', | ||||
| 	state: 'alive', | ||||
| 	sort: '+createdAt', | ||||
| } }; | ||||
| const popularUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	state: 'alive', | ||||
| 	origin: 'remote', | ||||
| 	sort: '+follower', | ||||
| } }; | ||||
| const recentlyUpdatedUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'combined', | ||||
| 	sort: '+updatedAt', | ||||
| } }; | ||||
| const recentlyRegisteredUsersF = { endpoint: 'users', limit: 10, noPaging: true, params: { | ||||
| 	origin: 'combined', | ||||
| 	sort: '+createdAt', | ||||
| } }; | ||||
| const searchPagination = { | ||||
| 	endpoint: 'users/search' as const, | ||||
| 	limit: 10, | ||||
|  | @ -157,31 +65,19 @@ const searchPagination = { | |||
| 	} : null), | ||||
| }; | ||||
| 
 | ||||
| os.api('hashtags/list', { | ||||
| 	sort: '+attachedLocalUsers', | ||||
| 	attachedToLocalUserOnly: true, | ||||
| 	limit: 30, | ||||
| }).then(tags => { | ||||
| 	tagsLocal = tags; | ||||
| }); | ||||
| os.api('hashtags/list', { | ||||
| 	sort: '+attachedRemoteUsers', | ||||
| 	attachedToRemoteUserOnly: true, | ||||
| 	limit: 30, | ||||
| }).then(tags => { | ||||
| 	tagsRemote = tags; | ||||
| }); | ||||
| os.api('stats').then(_stats => { | ||||
| 	stats = _stats; | ||||
| }); | ||||
| 
 | ||||
| const headerActions = $computed(() => []); | ||||
| 
 | ||||
| const headerTabs = $computed(() => [{ | ||||
| 	key: 'local', | ||||
| 	title: i18n.ts.local, | ||||
| 	key: 'featured', | ||||
| 	icon: 'fas fa-bolt', | ||||
| 	title: i18n.ts.featured, | ||||
| }, { | ||||
| 	key: 'remote', | ||||
| 	key: 'localUsers', | ||||
| 	icon: 'fas fa-users', | ||||
| 	title: i18n.ts.users, | ||||
| }, { | ||||
| 	key: 'remoteUsers', | ||||
| 	icon: 'fas fa-users', | ||||
| 	title: i18n.ts.remote, | ||||
| }, { | ||||
| 	key: 'search', | ||||
|  | @ -194,46 +90,3 @@ definePageMetadata(computed(() => ({ | |||
| 	bg: 'var(--bg)', | ||||
| }))); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .localfedi7 { | ||||
| 	color: #fff; | ||||
| 	padding: 16px; | ||||
| 	height: 80px; | ||||
| 	background-position: 50%; | ||||
| 	background-size: cover; | ||||
| 	margin-bottom: var(--margin); | ||||
| 
 | ||||
| 	> * { | ||||
| 		&:not(:last-child) { | ||||
| 			margin-bottom: 8px; | ||||
| 		} | ||||
| 
 | ||||
| 		> span { | ||||
| 			display: inline-block; | ||||
| 			padding: 6px 8px; | ||||
| 			background: rgba(0, 0, 0, 0.7); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	> header { | ||||
| 		font-size: 20px; | ||||
| 		font-weight: bold; | ||||
| 	} | ||||
| 
 | ||||
| 	> div { | ||||
| 		font-size: 14px; | ||||
| 		opacity: 0.8; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .vxjfqztj { | ||||
| 	> * { | ||||
| 		margin-right: 16px; | ||||
| 
 | ||||
| 		&.local { | ||||
| 			font-weight: bold; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -1,26 +0,0 @@ | |||
| <template> | ||||
| <MkStickyContainer> | ||||
| 	<template #header><MkPageHeader/></template> | ||||
| 	<MkSpacer :content-max="800"> | ||||
| 		<XNotes ref="notes" :pagination="pagination"/> | ||||
| 	</MkSpacer> | ||||
| </MkStickyContainer> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import XNotes from '@/components/notes.vue'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | ||||
| 
 | ||||
| const pagination = { | ||||
| 	endpoint: 'notes/featured' as const, | ||||
| 	limit: 10, | ||||
| 	offsetMode: true, | ||||
| }; | ||||
| 
 | ||||
| definePageMetadata({ | ||||
| 	title: i18n.ts.featured, | ||||
| 	icon: 'fas fa-fire-alt', | ||||
| 	bg: 'var(--bg)', | ||||
| }); | ||||
| </script> | ||||
|  | @ -61,9 +61,6 @@ export const routes = [{ | |||
| }, { | ||||
| 	path: '/about-misskey', | ||||
| 	component: page(() => import('./pages/about-misskey.vue')), | ||||
| }, { | ||||
| 	path: '/featured', | ||||
| 	component: page(() => import('./pages/featured.vue')), | ||||
| }, { | ||||
| 	path: '/theme-editor', | ||||
| 	component: page(() => import('./pages/theme-editor.vue')), | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue