fix some ui issue

This commit is contained in:
pa
2026-03-05 22:35:30 +09:00
parent fb6358b3be
commit 75282fa5d2
6 changed files with 280 additions and 6 deletions

View File

@@ -8,7 +8,7 @@
<SidebarMenuItem v-if="!item.children?.length">
<SidebarMenuButton
:is-active="activeMenuIndex === item.index"
:tooltip="item.titleIsCustom ? item.title : t(item.title || '')"
:tooltip="getItemTooltip(item)"
@click="handleMenuItemClick(item)">
<i
:class="item.icon"
@@ -22,6 +22,10 @@
<span v-show="!isCollapsed">{{
item.titleIsCustom ? item.title : t(item.title || '')
}}</span>
<template v-if="item.action === 'direct-access' && !isCollapsed">
<Kbd class="ml-auto">{{ isMac ? '⌘' : 'Ctrl' }}</Kbd>
<Kbd>D</Kbd>
</template>
</SidebarMenuButton>
</SidebarMenuItem>
@@ -333,9 +337,10 @@
DropdownMenuSubTrigger,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
import { computed, defineAsyncComponent, onMounted, ref, watch } from 'vue';
import { computed, defineAsyncComponent, h, onMounted, ref, watch } from 'vue';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';
import { ChevronRight, Heart } from 'lucide-vue-next';
import { Kbd } from '@/components/ui/kbd';
import { TooltipWrapper } from '@/components/ui/tooltip';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
@@ -361,6 +366,21 @@
const { t, locale } = useI18n();
const router = useRouter();
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const getItemTooltip = (item) => {
const label = item.titleIsCustom ? item.title : t(item.title || '');
if (item.action !== 'direct-access') {
return label;
}
return () =>
h('span', { class: 'inline-flex items-center gap-1' }, [
label,
h(Kbd, () => (isMac ? '⌘' : 'Ctrl')),
h(Kbd, () => 'D')
]);
};
const createDefaultNavLayout = () => [
{ type: 'item', key: 'feed' },
{ type: 'item', key: 'friends-locations' },
@@ -804,6 +824,10 @@
router.push({ name: routeName });
};
/**
*
* @param layout
*/
function getFirstNavRoute(layout) {
for (const entry of layout) {
if (entry.type === 'item') {

View File

@@ -1501,6 +1501,10 @@
}
);
/**
*
* @param visibility
*/
function userFavoriteWorldsStatus(visibility) {
const style = {};
if (visibility === 'public') {
@@ -1513,6 +1517,10 @@
return style;
}
/**
*
* @param user
*/
function getUserStateText(user) {
let state = '';
if (user.state === 'active') {
@@ -1528,6 +1536,10 @@
return state;
}
/**
*
* @param status
*/
function getUserStatusText(status) {
if (status === 'active') {
return t('dialog.user.status.active');
@@ -1544,6 +1556,9 @@
return t('dialog.user.status.offline');
}
/**
*
*/
function refreshUserDialogTreeData() {
const D = userDialog.value;
if (D.id === currentUser.value.id) {
@@ -1556,6 +1571,10 @@
treeData.value = formatJsonVars(D.ref);
}
/**
*
* @param tabName
*/
function handleUserDialogTab(tabName) {
userDialog.value.lastActiveTab = tabName;
const userId = userDialog.value.id;
@@ -1604,10 +1623,17 @@
}
}
/**
*
*/
function loadLastActiveTab() {
handleUserDialogTab(userDialog.value.lastActiveTab);
}
/**
*
* @param tabName
*/
function userDialogTabClick(tabName) {
if (tabName === userDialog.value.lastActiveTab) {
if (tabName === 'JSON') {
@@ -1618,17 +1644,26 @@
handleUserDialogTab(tabName);
}
/**
*
*/
function showPronounsDialog() {
const D = pronounsDialog.value;
D.pronouns = currentUser.value.pronouns;
D.visible = true;
}
/**
*
*/
function showLanguageDialog() {
const D = languageDialog.value;
D.visible = true;
}
/**
*
*/
function showSocialStatusDialog() {
const D = socialStatusDialog.value;
const { statusHistory } = currentUser.value;
@@ -1646,6 +1681,10 @@
D.visible = true;
}
/**
*
* @param userId
*/
async function setUserDialogAvatarsRemote(userId) {
if (avatarRemoteDatabase.value && userId !== currentUser.value.id) {
userDialog.value.isAvatarsLoading = true;
@@ -1672,6 +1711,10 @@
sortUserDialogAvatars(userDialog.value.avatars);
}
/**
*
* @param badge
*/
async function toggleBadgeVisibility(badge) {
if (badge.hidden) {
badge.showcased = false;
@@ -1684,6 +1727,10 @@
handleBadgeUpdate(args);
}
/**
*
* @param badge
*/
async function toggleBadgeShowcased(badge) {
if (badge.showcased) {
badge.hidden = false;
@@ -1696,12 +1743,21 @@
handleBadgeUpdate(args);
}
/**
*
* @param args
*/
function handleBadgeUpdate(args) {
if (args.json) {
toast.success(t('message.badge.updated'));
}
}
/**
*
* @param userId
* @param type
*/
function setPlayerModeration(userId, type) {
const D = userDialog.value;
AppApi.SetVRChatUserModeration(currentUser.value.id, userId, type).then((result) => {
@@ -1722,6 +1778,11 @@
});
}
/**
*
* @param params
* @param userId
*/
function showSendInviteDialog(params, userId) {
sendInviteDialog.value = {
params,
@@ -1733,6 +1794,11 @@
sendInviteDialogVisible.value = true;
}
/**
*
* @param params
* @param userId
*/
function showSendInviteRequestDialog(params, userId) {
sendInviteDialog.value = {
params,
@@ -1744,12 +1810,21 @@
sendInviteRequestDialogVisible.value = true;
}
/**
*
* @param groupId
* @param userId
*/
function showInviteGroupDialog(groupId, userId) {
inviteGroupDialog.value.groupId = groupId;
inviteGroupDialog.value.userId = userId;
inviteGroupDialog.value.visible = true;
}
/**
*
* @param command
*/
function userDialogCommand(command) {
let L;
const D = userDialog.value;
@@ -1892,6 +1967,10 @@
}
}
/**
*
* @param args
*/
function handleSendFriendRequest(args) {
const ref = cachedUsers.get(args.params.userId);
if (typeof ref === 'undefined') {
@@ -1917,6 +1996,10 @@
}
}
/**
*
* @param args
*/
function handleCancelFriendRequest(args) {
const ref = cachedUsers.get(args.params.userId);
if (typeof ref === 'undefined') {
@@ -1937,6 +2020,10 @@
D.outgoingRequest = false;
}
/**
*
* @param args
*/
function handleSendPlayerModeration(args) {
const ref = applyPlayerModeration(args.json);
const D = userDialog.value;
@@ -1955,6 +2042,11 @@
toast.success(t('message.user.moderated'));
}
/**
*
* @param command
* @param userId
*/
async function performUserDialogCommand(command, userId) {
let args;
let key;
@@ -2092,6 +2184,10 @@
}
}
/**
*
* @param userId
*/
function reportUserForHacking(userId) {
miscRequest.reportUser({
userId,
@@ -2101,6 +2197,10 @@
});
}
/**
*
* @param userId
*/
async function getUserGroups(userId) {
exitEditModeCurrentUserGroups();
userDialog.value.isGroupsLoading = true;
@@ -2161,6 +2261,10 @@
userDialog.value.isGroupsLoading = false;
}
/**
*
* @param userId
*/
async function getUserMutualFriends(userId) {
userDialog.value.mutualFriends = [];
if (currentUser.value.hasSharedConnectionsOptOut) {
@@ -2200,6 +2304,11 @@
});
}
/**
*
* @param a
* @param b
*/
function sortGroupsByInGame(a, b) {
const aIndex = inGameGroupOrder.value.indexOf(a?.id);
const bIndex = inGameGroupOrder.value.indexOf(b?.id);
@@ -2215,6 +2324,9 @@
return aIndex - bIndex;
}
/**
*
*/
async function sortCurrentUserGroups() {
const D = userDialog.value;
let sortMethod = () => 0;
@@ -2237,6 +2349,10 @@
userDialog.value.userGroups.remainingGroups.sort(sortMethod);
}
/**
*
* @param userId
*/
function setUserDialogAvatars(userId) {
const avatars = new Set();
userDialogAvatars.value.forEach((avatar) => {
@@ -2250,6 +2366,10 @@
sortUserDialogAvatars(userDialog.value.avatars);
}
/**
*
* @param userId
*/
function setUserDialogWorlds(userId) {
const worlds = [];
for (const ref of cachedWorlds.values()) {
@@ -2260,6 +2380,9 @@
userDialog.value.worlds = worlds;
}
/**
*
*/
function refreshUserDialogWorlds() {
const D = userDialog.value;
if (D.isWorldsLoading) {
@@ -2306,6 +2429,10 @@
});
}
/**
*
* @param userId
*/
async function getUserFavoriteWorlds(userId) {
userDialog.value.isFavoriteWorldsLoading = true;
favoriteWorldsTab.value = '0';
@@ -2344,6 +2471,9 @@
userDialog.value.isFavoriteWorldsLoading = false;
}
/**
*
*/
function showBioDialog() {
const D = bioDialog.value;
D.bio = currentUser.value.bio;
@@ -2351,6 +2481,9 @@
D.visible = true;
}
/**
*
*/
async function translateBio() {
if (translateLoading.value) {
return;
@@ -2388,22 +2521,35 @@
}
}
/**
*
* @param userRef
*/
function showPreviousInstancesListDialog(userRef) {
instanceStore.showPreviousInstancesListDialog('user', userRef);
}
/**
*
*/
function toggleAvatarCopying() {
userRequest.saveCurrentUser({
allowAvatarCopying: !currentUser.value.allowAvatarCopying
});
}
/**
*
*/
function toggleAllowBooping() {
userRequest.saveCurrentUser({
isBoopingEnabled: !currentUser.value.isBoopingEnabled
});
}
/**
*
*/
function resetHome() {
modalStore
.confirm({
@@ -2426,14 +2572,26 @@
.catch(() => {});
}
/**
*
* @param userId
*/
function copyUserId(userId) {
copyToClipboard(userId, 'User ID copied to clipboard');
}
/**
*
* @param userId
*/
function copyUserURL(userId) {
copyToClipboard(`https://vrchat.com/home/user/${userId}`, 'User URL copied to clipboard');
}
/**
*
* @param displayName
*/
function copyUserDisplayName(displayName) {
copyToClipboard(displayName, 'User DisplayName copied to clipboard');
}
@@ -2449,6 +2607,10 @@
return found ? String(found[0]) : '';
});
/**
*
* @param key
*/
function setUserDialogGroupSortingByKey(key) {
const option = userDialogGroupSortingOptions[key];
if (!option) {
@@ -2457,6 +2619,10 @@
setUserDialogGroupSorting(option);
}
/**
*
* @param sortOrder
*/
async function setUserDialogGroupSorting(sortOrder) {
const D = userDialog.value;
if (D.groupSorting.value === sortOrder.value) {
@@ -2477,6 +2643,10 @@
return found ? String(found[0]) : '';
});
/**
*
* @param key
*/
function setUserDialogMutualFriendSortingByKey(key) {
const option = userDialogMutualFriendSortingOptions[key];
if (!option) {
@@ -2485,6 +2655,10 @@
setUserDialogMutualFriendSorting(option);
}
/**
*
* @param sortOrder
*/
async function setUserDialogMutualFriendSorting(sortOrder) {
const D = userDialog.value;
D.mutualFriendSorting = sortOrder;
@@ -2501,6 +2675,9 @@
}
}
/**
*
*/
async function exitEditModeCurrentUserGroups() {
userDialogGroupEditMode.value = false;
userDialogGroupEditGroups.value = [];
@@ -2509,6 +2686,9 @@
await sortCurrentUserGroups();
}
/**
*
*/
async function editModeCurrentUserGroups() {
await updateInGameGroupOrder();
userDialogGroupEditGroups.value = Array.from(currentUserGroups.value.values());
@@ -2516,6 +2696,9 @@
userDialogGroupEditMode.value = true;
}
/**
*
*/
async function saveInGameGroupOrder() {
userDialogGroupEditGroups.value.sort(sortGroupsByInGame);
try {
@@ -2531,6 +2714,9 @@
}
// Select all groups currently in the editable list by collecting their IDs
/**
*
*/
function selectAllGroups() {
const allSelected = userDialogGroupEditSelectedGroupIds.value.length === userDialogGroupEditGroups.value.length;
@@ -2547,6 +2733,10 @@
const bulkGroupActionValue = ref('');
/**
*
* @param value
*/
function handleBulkGroupAction(value) {
bulkGroupActionValue.value = value;
@@ -2563,6 +2753,10 @@
}
// Apply the given visibility to all selected groups
/**
*
* @param newVisibility
*/
async function bulkSetVisibility(newVisibility) {
for (const groupId of userDialogGroupEditSelectedGroupIds.value) {
setGroupVisibility(groupId, newVisibility);
@@ -2570,6 +2764,9 @@
}
// Leave (remove user from) all selected groups
/**
*
*/
function bulkLeaveGroups() {
for (const groupId of userDialogGroupEditSelectedGroupIds.value) {
leaveGroup(groupId);
@@ -2577,6 +2774,10 @@
}
// Toggle individual group selection for bulk actions
/**
*
* @param groupId
*/
function toggleGroupSelection(groupId) {
const index = userDialogGroupEditSelectedGroupIds.value.indexOf(groupId);
if (index === -1) {
@@ -2586,6 +2787,10 @@
}
}
/**
*
* @param groupId
*/
function moveGroupUp(groupId) {
const index = inGameGroupOrder.value.indexOf(groupId);
if (index > 0) {
@@ -2595,6 +2800,10 @@
}
}
/**
*
* @param groupId
*/
function moveGroupDown(groupId) {
const index = inGameGroupOrder.value.indexOf(groupId);
if (index < inGameGroupOrder.value.length - 1) {
@@ -2604,6 +2813,10 @@
}
}
/**
*
* @param groupId
*/
function moveGroupTop(groupId) {
const index = inGameGroupOrder.value.indexOf(groupId);
if (index > 0) {
@@ -2613,6 +2826,10 @@
}
}
/**
*
* @param groupId
*/
function moveGroupBottom(groupId) {
const index = inGameGroupOrder.value.indexOf(groupId);
if (index < inGameGroupOrder.value.length - 1) {
@@ -2622,6 +2839,10 @@
}
}
/**
*
* @param sortOrder
*/
async function setUserDialogWorldSorting(sortOrder) {
const D = userDialog.value;
if (D.worldSorting.value === sortOrder.value) {
@@ -2642,6 +2863,10 @@
return found ? String(found[0]) : '';
});
/**
*
* @param key
*/
function setUserDialogWorldSortingByKey(key) {
const option = userDialogWorldSortingOptions[key];
if (!option) {
@@ -2650,6 +2875,10 @@
setUserDialogWorldSorting(option);
}
/**
*
* @param order
*/
async function setUserDialogWorldOrder(order) {
const D = userDialog.value;
if (D.worldOrder.value === order.value) {
@@ -2670,6 +2899,10 @@
return found ? String(found[0]) : '';
});
/**
*
* @param key
*/
function setUserDialogWorldOrderByKey(key) {
const option = userDialogWorldOrderOptions[key];
if (!option) {
@@ -2678,16 +2911,26 @@
setUserDialogWorldOrder(option);
}
/**
*
* @param sortOption
*/
function changeUserDialogAvatarSorting(sortOption) {
const D = userDialog.value;
D.avatarSorting = sortOption;
sortUserDialogAvatars(D.avatars);
}
/**
*
*/
function closeInviteDialog() {
clearInviteImageUpload();
}
/**
*
*/
function getVRChatCredits() {
miscRequest.getVRChatCredits().then((args) => (vrchatCredit.value = args.json?.balance));
}

View File

@@ -12,7 +12,7 @@
data-slot="input-group-control"
:class="
cn(
'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent',
'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent break-all',
props.class
)
" />

View File

@@ -76,7 +76,7 @@
}
},
"side_panel": {
"search_placeholder": "Search...",
"search_placeholder": "Quick Search...",
"search_no_results": "No results found",
"search_min_chars": "Type at least 2 characters",
"search_categories": "Search for...",
@@ -1935,7 +1935,7 @@
"export_bans": "Export Bans",
"import_bans": "Import Bans",
"import_bans_description": "Paste CSV or user IDs below. The userId column will be auto-detected from CSV headers, or all usr_ IDs will be extracted.",
"import_bans_warning": "Do not import too many users at once. The API is rate-limited and may fail. You are responsible for any consequences.",
"import_bans_warning": "Do not import too many at once. This is a sensitive operation actively monitored and enforced by the official, use at your own risk!",
"import_bans_placeholder": "Paste CSV or user IDs here (one per line)\nusr_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"import_bans_start": "Import & Ban",
"import_bans_clear_errors": "Clear Errors"

View File

@@ -30,6 +30,7 @@ export const useUiStore = defineStore('Ui', () => {
const ctrlR = keys['Ctrl+R'];
const ctrlD = keys['Ctrl+D'];
const metaD = keys['Meta+D'];
const shift = keys['Shift'];
const ctrlShiftI = keys['Ctrl+Shift+I'];
const altShiftR = keys['Alt+Shift+R'];
@@ -51,6 +52,12 @@ export const useUiStore = defineStore('Ui', () => {
}
});
watch(metaD, (isPressed) => {
if (isPressed) {
directAccessPaste();
}
});
watch(shift, (isHeld) => {
shiftHeld.value = isHeld;
});

View File

@@ -4,7 +4,7 @@
<div style="flex: 1; padding: 10px; padding-left: 0">
<button
type="button"
class="border-input dark:bg-input/30 flex h-9 w-full items-center gap-1 rounded-md border bg-transparent px-3 shadow-xs transition-[color,box-shadow] hover:border-ring cursor-pointer"
class="border-input dark:bg-input/30 flex h-9 w-full items-center gap-2 rounded-md border bg-transparent px-3 shadow-xs transition-[color,box-shadow] hover:border-ring cursor-pointer"
@click="openGlobalSearch">
<Search class="size-4 shrink-0 opacity-50" />
<span class="flex-1 text-left text-sm text-muted-foreground truncate">{{