diff --git a/src/views/Favorites/dialogs/AvatarImportDialog.vue b/src/views/Favorites/dialogs/AvatarImportDialog.vue
index 7770f00c..8bb1b4b5 100644
--- a/src/views/Favorites/dialogs/AvatarImportDialog.vue
+++ b/src/views/Favorites/dialogs/AvatarImportDialog.vue
@@ -103,57 +103,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ row.name }}
-
-
-
-
-
-
- {{ row.authorName }}
-
-
-
-
-
-
- {{ row.releaseStatus.charAt(0).toUpperCase() + row.releaseStatus.slice(1) }}
-
-
-
-
-
-
-
-
-
+
@@ -161,17 +117,19 @@
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
+ import { DataTableLayout } from '@/components/ui/data-table';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { Loading } from '@element-plus/icons-vue';
- import { Trash2 } from 'lucide-vue-next';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import { useAvatarStore, useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
import { avatarRequest, favoriteRequest } from '../../../api';
+ import { createColumns } from './avatarImportColumns.jsx';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { removeFromArray } from '../../../shared/utils';
+ import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const emit = defineEmits(['update:avatarImportDialogInput']);
const { t } = useI18n();
@@ -207,6 +165,30 @@
layout: 'table'
});
+ const tableStyle = { maxHeight: '400px' };
+
+ const rows = computed(() =>
+ Array.isArray(avatarImportTable.value?.data) ? avatarImportTable.value.data.slice() : []
+ );
+
+ const columns = computed(() =>
+ createColumns({
+ onShowAvatar: showAvatarDialog,
+ onShowUser: showUserDialog,
+ onShowFullscreenImage: showFullscreenImageDialog,
+ onDelete: deleteItemAvatarImport
+ })
+ );
+
+ const { table } = useVrcxVueTable({
+ persistKey: 'avatarImportDialog',
+ data: rows,
+ columns: columns.value,
+ getRowId: (row) => String(row?.id ?? ''),
+ enablePagination: false,
+ enableSorting: false
+ });
+
const avatarImportDialogIndex = ref(2000);
const isVisible = computed({
diff --git a/src/views/Favorites/dialogs/FriendImportDialog.vue b/src/views/Favorites/dialogs/FriendImportDialog.vue
index d0f04629..4202494f 100644
--- a/src/views/Favorites/dialogs/FriendImportDialog.vue
+++ b/src/views/Favorites/dialogs/FriendImportDialog.vue
@@ -84,34 +84,13 @@
{{ t('dialog.friend_import.errors') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ row.displayName }}
-
-
-
-
-
-
-
-
-
+
@@ -119,9 +98,9 @@
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
+ import { DataTableLayout } from '@/components/ui/data-table';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { Loading } from '@element-plus/icons-vue';
- import { Trash2 } from 'lucide-vue-next';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
@@ -129,7 +108,9 @@
import { removeFromArray, userImage, userImageFull } from '../../../shared/utils';
import { useFavoriteStore, useGalleryStore, useUserStore } from '../../../stores';
import { favoriteRequest, userRequest } from '../../../api';
+ import { createColumns } from './friendImportColumns.jsx';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
+ import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { t } = useI18n();
@@ -163,6 +144,31 @@
layout: 'table'
});
+ const tableStyle = { maxHeight: '400px' };
+
+ const rows = computed(() =>
+ Array.isArray(friendImportTable.value?.data) ? friendImportTable.value.data.slice() : []
+ );
+
+ const columns = computed(() =>
+ createColumns({
+ userImage,
+ userImageFull,
+ onShowFullscreenImage: showFullscreenImageDialog,
+ onShowUser: showUserDialog,
+ onDelete: deleteItemFriendImport
+ })
+ );
+
+ const { table } = useVrcxVueTable({
+ persistKey: 'friendImportDialog',
+ data: rows,
+ columns: columns.value,
+ getRowId: (row) => String(row?.id ?? ''),
+ enablePagination: false,
+ enableSorting: false
+ });
+
const friendImportDialogIndex = ref(2000);
const isVisible = computed({
diff --git a/src/views/Favorites/dialogs/WorldImportDialog.vue b/src/views/Favorites/dialogs/WorldImportDialog.vue
index 60b104c4..b18f0805 100644
--- a/src/views/Favorites/dialogs/WorldImportDialog.vue
+++ b/src/views/Favorites/dialogs/WorldImportDialog.vue
@@ -108,54 +108,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -163,17 +122,19 @@
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { computed, ref, watch } from 'vue';
import { Button } from '@/components/ui/button';
+ import { DataTableLayout } from '@/components/ui/data-table';
import { InputGroupTextareaField } from '@/components/ui/input-group';
import { Loading } from '@element-plus/icons-vue';
- import { Trash2 } from 'lucide-vue-next';
import { storeToRefs } from 'pinia';
import { toast } from 'vue-sonner';
import { useI18n } from 'vue-i18n';
import { useFavoriteStore, useGalleryStore, useUserStore, useWorldStore } from '../../../stores';
import { favoriteRequest, worldRequest } from '../../../api';
+ import { createColumns } from './worldImportColumns.jsx';
import { getNextDialogIndex } from '../../../shared/utils/base/ui';
import { removeFromArray } from '../../../shared/utils';
+ import { useVrcxVueTable } from '../../../lib/table/useVrcxVueTable';
const { showUserDialog } = useUserStore();
const { favoriteWorldGroups, worldImportDialogInput, worldImportDialogVisible, localWorldFavoriteGroups } =
@@ -213,6 +174,30 @@
layout: 'table'
});
+ const tableStyle = { maxHeight: '400px' };
+
+ const rows = computed(() =>
+ Array.isArray(worldImportTable.value?.data) ? worldImportTable.value.data.slice() : []
+ );
+
+ const columns = computed(() =>
+ createColumns({
+ onShowWorld: showWorldDialog,
+ onShowUser: showUserDialog,
+ onShowFullscreenImage: showFullscreenImageDialog,
+ onDelete: deleteItemWorldImport
+ })
+ );
+
+ const { table } = useVrcxVueTable({
+ persistKey: 'worldImportDialog',
+ data: rows,
+ columns: columns.value,
+ getRowId: (row) => String(row?.id ?? ''),
+ enablePagination: false,
+ enableSorting: false
+ });
+
const isVisible = computed({
get() {
return worldImportDialogVisible.value;
diff --git a/src/views/Favorites/dialogs/avatarImportColumns.jsx b/src/views/Favorites/dialogs/avatarImportColumns.jsx
new file mode 100644
index 00000000..d4ee12fc
--- /dev/null
+++ b/src/views/Favorites/dialogs/avatarImportColumns.jsx
@@ -0,0 +1,137 @@
+import { Trash2 } from 'lucide-vue-next';
+
+import { Button } from '../../../components/ui/button';
+import { i18n } from '../../../plugin';
+
+const { t } = i18n.global;
+
+export const createColumns = ({ onShowAvatar, onShowUser, onDelete, onShowFullscreenImage }) => [
+ {
+ id: 'image',
+ header: () => t('table.import.image'),
+ enableSorting: false,
+ size: 70,
+ cell: ({ row }) => {
+ const original = row.original;
+ const thumb = original?.thumbnailImageUrl;
+ const full = original?.imageUrl;
+
+ return (
+ (
+
+ )
+ }}
+ >
+
{
+ e.stopPropagation();
+ if (full) {
+ onShowFullscreenImage?.(full);
+ }
+ }}
+ />
+
+ );
+ }
+ },
+ {
+ id: 'name',
+ accessorKey: 'name',
+ header: () => t('table.import.name'),
+ meta: {
+ stretch: true
+ },
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+ {
+ e.stopPropagation();
+ onShowAvatar?.(original?.id);
+ }}
+ >
+ {original?.name}
+
+ );
+ }
+ },
+ {
+ id: 'author',
+ header: () => t('table.import.author'),
+ size: 120,
+ enableSorting: false,
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+ {
+ e.stopPropagation();
+ onShowUser?.(original?.authorId);
+ }}
+ >
+ {original?.authorName}
+
+ );
+ }
+ },
+ {
+ id: 'status',
+ header: () => t('table.import.status'),
+ size: 70,
+ enableSorting: false,
+ cell: ({ row }) => {
+ const status = String(row.original?.releaseStatus ?? '');
+ const label = status
+ ? status.charAt(0).toUpperCase() + status.slice(1)
+ : '';
+ const color =
+ status === 'public'
+ ? '#67c23a'
+ : status === 'private'
+ ? '#f56c6c'
+ : undefined;
+ return {label};
+ }
+ },
+ {
+ id: 'action',
+ header: () => t('table.import.action'),
+ size: 90,
+ enableSorting: false,
+ meta: {
+ tdClass: 'text-right'
+ },
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+
+ );
+ }
+ }
+];
diff --git a/src/views/Favorites/dialogs/friendImportColumns.jsx b/src/views/Favorites/dialogs/friendImportColumns.jsx
new file mode 100644
index 00000000..b10036f7
--- /dev/null
+++ b/src/views/Favorites/dialogs/friendImportColumns.jsx
@@ -0,0 +1,96 @@
+import { Trash2 } from 'lucide-vue-next';
+
+import { Button } from '../../../components/ui/button';
+import { i18n } from '../../../plugin';
+
+const { t } = i18n.global;
+
+export const createColumns = ({ userImage, userImageFull, onShowFullscreenImage, onShowUser, onDelete }) => [
+ {
+ id: 'image',
+ header: () => t('table.import.image'),
+ enableSorting: false,
+ size: 70,
+ cell: ({ row }) => {
+ const original = row.original;
+ const thumb = userImage?.(original);
+ const full = userImageFull?.(original);
+
+ return (
+ (
+
+ )
+ }}
+ >
+
{
+ e.stopPropagation();
+ if (full) {
+ onShowFullscreenImage?.(full);
+ }
+ }}
+ />
+
+ );
+ }
+ },
+ {
+ id: 'name',
+ accessorKey: 'displayName',
+ header: () => t('table.import.name'),
+ meta: {
+ stretch: true
+ },
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+ {
+ e.stopPropagation();
+ onShowUser?.(original?.id);
+ }}
+ >
+ {original?.displayName}
+
+ );
+ }
+ },
+ {
+ id: 'action',
+ header: () => t('table.import.action'),
+ size: 90,
+ enableSorting: false,
+ meta: {
+ tdClass: 'text-right'
+ },
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+
+ );
+ }
+ }
+];
diff --git a/src/views/Favorites/dialogs/worldImportColumns.jsx b/src/views/Favorites/dialogs/worldImportColumns.jsx
new file mode 100644
index 00000000..1e6a39ce
--- /dev/null
+++ b/src/views/Favorites/dialogs/worldImportColumns.jsx
@@ -0,0 +1,138 @@
+import { Trash2 } from 'lucide-vue-next';
+
+import { Button } from '../../../components/ui/button';
+import { i18n } from '../../../plugin';
+
+const { t } = i18n.global;
+
+export const createColumns = ({ onShowWorld, onShowUser, onDelete, onShowFullscreenImage }) => [
+ {
+ id: 'image',
+ header: () => t('table.import.image'),
+ enableSorting: false,
+ size: 70,
+ cell: ({ row }) => {
+ const original = row.original;
+ const thumb = original?.thumbnailImageUrl;
+ const full = original?.imageUrl;
+
+ return (
+ (
+
+ )
+ }}
+ >
+
{
+ e.stopPropagation();
+ if (full) {
+ onShowFullscreenImage?.(full);
+ }
+ }}
+ />
+
+ );
+ }
+ },
+ {
+ id: 'name',
+ accessorKey: 'name',
+ header: () => t('table.import.name'),
+ meta: {
+ stretch: true
+ },
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+ {
+ e.stopPropagation();
+ onShowWorld?.(original?.id);
+ }}
+ >
+ {original?.name}
+
+ );
+ }
+ },
+ {
+ id: 'author',
+ header: () => t('table.import.author'),
+ size: 120,
+ enableSorting: false,
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+ {
+ e.stopPropagation();
+ onShowUser?.(original?.authorId);
+ }}
+ >
+ {original?.authorName}
+
+ );
+ }
+ },
+ {
+ id: 'status',
+ header: () => t('table.import.status'),
+ size: 70,
+ enableSorting: false,
+ cell: ({ row }) => {
+ const status = String(row.original?.releaseStatus ?? '');
+ const label = status
+ ? status.charAt(0).toUpperCase() + status.slice(1)
+ : '';
+ const color =
+ status === 'public'
+ ? '#67c23a'
+ : status === 'private'
+ ? '#f56c6c'
+ : undefined;
+ return {label};
+ }
+ },
+ {
+ id: 'action',
+ header: () => t('table.import.action'),
+ size: 90,
+ enableSorting: false,
+ meta: {
+ tdClass: 'text-right'
+ },
+ cell: ({ row }) => {
+ const original = row.original;
+ return (
+
+ );
+ }
+ }
+];