mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-05-05 22:36:05 +02:00
add empty component and poilsh styles
This commit is contained in:
@@ -978,6 +978,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px">
|
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px">
|
||||||
|
<template v-if="userDialog.worlds.length">
|
||||||
<div
|
<div
|
||||||
v-for="world in userDialog.worlds"
|
v-for="world in userDialog.worlds"
|
||||||
:key="world.id"
|
:key="world.id"
|
||||||
@@ -991,6 +992,18 @@
|
|||||||
<span v-if="world.occupants" class="extra">({{ world.occupants }})</span>
|
<span v-if="world.occupants" class="extra">({{ world.occupants }})</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-else-if="!userDialog.isWorldsLoading"
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 120px;
|
||||||
|
width: 100%;
|
||||||
|
">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -1055,7 +1068,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-else-if="!userDialog.isFavoriteWorldsLoading">
|
<template v-else-if="!userDialog.isFavoriteWorldsLoading">
|
||||||
<div style="display: flex; justify-content: center; align-items: center; height: 100%">
|
<div style="display: flex; justify-content: center; align-items: center; height: 100%">
|
||||||
<span style="font-size: 16px">No favorite worlds found.</span>
|
<DataTableEmpty type="nodata" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@@ -1127,6 +1140,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px; max-height: 50vh">
|
<div class="x-friend-list" style="margin-top: 10px; min-height: 60px; max-height: 50vh">
|
||||||
|
<template v-if="userDialogAvatars.length">
|
||||||
<div
|
<div
|
||||||
v-for="avatar in userDialogAvatars"
|
v-for="avatar in userDialogAvatars"
|
||||||
:key="avatar.id"
|
:key="avatar.id"
|
||||||
@@ -1137,7 +1151,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="detail">
|
<div class="detail">
|
||||||
<span class="name" v-text="avatar.name"></span>
|
<span class="name" v-text="avatar.name"></span>
|
||||||
<span v-if="avatar.releaseStatus === 'public'" class="extra" v-text="avatar.releaseStatus">
|
<span
|
||||||
|
v-if="avatar.releaseStatus === 'public'"
|
||||||
|
class="extra"
|
||||||
|
v-text="avatar.releaseStatus">
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-else-if="avatar.releaseStatus === 'private'"
|
v-else-if="avatar.releaseStatus === 'private'"
|
||||||
@@ -1147,6 +1164,18 @@
|
|||||||
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
|
<span v-else class="extra" v-text="avatar.releaseStatus"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
<div
|
||||||
|
v-else-if="!userDialog.isAvatarsLoading"
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 120px;
|
||||||
|
width: 100%;
|
||||||
|
">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -1217,6 +1246,7 @@
|
|||||||
import { DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
import { DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Checkbox } from '@/components/ui/checkbox';
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { TabsUnderline } from '@/components/ui/tabs';
|
import { TabsUnderline } from '@/components/ui/tabs';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<template>
|
||||||
|
<Empty>
|
||||||
|
<EmptyHeader>
|
||||||
|
<EmptyMedia variant="icon">
|
||||||
|
<SearchAlert v-if="props.type === 'nomatch'" class="text-lg" />
|
||||||
|
<Inbox v-else class="text-lg" />
|
||||||
|
</EmptyMedia>
|
||||||
|
<EmptyDescription>
|
||||||
|
{{ emptyText }}
|
||||||
|
</EmptyDescription>
|
||||||
|
</EmptyHeader>
|
||||||
|
</Empty>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Inbox, SearchAlert } from 'lucide-vue-next';
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia } from '../empty';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'nodata'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const emptyText = computed(() => {
|
||||||
|
return props.type === 'nomatch' ? t('common.no_matching_records') : t('common.no_data');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -59,9 +59,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<TableRow v-else>
|
<TableRow v-else>
|
||||||
<TableCell class="h-24 text-center">
|
<TableCell class="h-24 text-center" :colspan="table.getVisibleLeafColumns().length">
|
||||||
<slot name="empty">
|
<slot name="empty">
|
||||||
{{ emptyText }}
|
<DataTableEmpty :type="emptyType" />
|
||||||
</slot>
|
</slot>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -134,6 +134,8 @@
|
|||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../table';
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../table';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select';
|
||||||
|
|
||||||
|
import DataTableEmpty from './DataTableEmpty.vue';
|
||||||
|
|
||||||
const appearanceSettingsStore = useAppearanceSettingsStore();
|
const appearanceSettingsStore = useAppearanceSettingsStore();
|
||||||
const { isDataTableStriped } = storeToRefs(appearanceSettingsStore);
|
const { isDataTableStriped } = storeToRefs(appearanceSettingsStore);
|
||||||
|
|
||||||
@@ -162,10 +164,6 @@
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
emptyText: {
|
|
||||||
type: String,
|
|
||||||
default: 'No results.'
|
|
||||||
},
|
|
||||||
showPagination: {
|
showPagination: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
@@ -187,6 +185,11 @@
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tableScrollRef = ref(null);
|
const tableScrollRef = ref(null);
|
||||||
|
|
||||||
|
const emptyType = computed(() => {
|
||||||
|
const totalRows = props.table?.getCoreRowModel?.().rows?.length ?? 0;
|
||||||
|
return totalRows === 0 ? 'nodata' : 'nomatch';
|
||||||
|
});
|
||||||
|
|
||||||
const expandedRenderer = computed(() => {
|
const expandedRenderer = computed(() => {
|
||||||
const columns = props.table.getAllColumns?.() ?? [];
|
const columns = props.table.getAllColumns?.() ?? [];
|
||||||
for (const column of columns) {
|
for (const column of columns) {
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { default as DataTableLayout } from './DataTableLayout.vue';
|
export { default as DataTableLayout } from './DataTableLayout.vue';
|
||||||
|
export { default as DataTableEmpty } from './DataTableEmpty.vue';
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
data-slot="empty"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-lg border-dashed p-6 text-center md:p-12',
|
||||||
|
props.class
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
data-slot="empty-content"
|
||||||
|
:class="cn('flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-balance text-sm', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<p
|
||||||
|
data-slot="empty-description"
|
||||||
|
:class="
|
||||||
|
cn(
|
||||||
|
'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
|
||||||
|
$attrs.class ?? ''
|
||||||
|
)
|
||||||
|
">
|
||||||
|
<slot />
|
||||||
|
</p>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div data-slot="empty-header" :class="cn('flex max-w-sm flex-col items-center gap-2 text-center', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
import { emptyMediaVariants } from '.';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false },
|
||||||
|
variant: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div data-slot="empty-icon" :data-variant="variant" :class="cn(emptyMediaVariants({ variant }), props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup>
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
class: { type: null, required: false }
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div data-slot="empty-title" :class="cn('text-lg font-medium tracking-tight', props.class)">
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { cva } from 'class-variance-authority';
|
||||||
|
|
||||||
|
export { default as Empty } from './Empty.vue';
|
||||||
|
export { default as EmptyContent } from './EmptyContent.vue';
|
||||||
|
export { default as EmptyDescription } from './EmptyDescription.vue';
|
||||||
|
export { default as EmptyHeader } from './EmptyHeader.vue';
|
||||||
|
export { default as EmptyMedia } from './EmptyMedia.vue';
|
||||||
|
export { default as EmptyTitle } from './EmptyTitle.vue';
|
||||||
|
|
||||||
|
export const emptyMediaVariants = cva(
|
||||||
|
'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: 'bg-transparent',
|
||||||
|
icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: 'default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -2437,6 +2437,10 @@
|
|||||||
"action": "Action"
|
"action": "Action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"common": {
|
||||||
|
"no_data": "No data",
|
||||||
|
"no_matching_records": "No matching records"
|
||||||
|
},
|
||||||
"vr": {
|
"vr": {
|
||||||
"status": {
|
"status": {
|
||||||
"timer": "Timer:",
|
"timer": "Timer:",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<span>{{ t('view.charts.instance_activity.header') }}</span>
|
<span>{{ t('view.charts.instance_activity.header') }}</span>
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCardTrigger as-child>
|
<HoverCardTrigger as-child>
|
||||||
<Info style="margin-left: 5px; font-size: 12px; opacity: 0.7" />
|
<Info style="margin-left: 4px; font-size: 12px; opacity: 0.7" />
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
<HoverCardContent side="bottom" align="start" class="w-75">
|
<HoverCardContent side="bottom" align="start" class="w-75">
|
||||||
<div class="tips-popover">
|
<div class="tips-popover">
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<Button
|
<Button
|
||||||
class="rounded-full"
|
class="rounded-full"
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="outline"
|
variant="ghost"
|
||||||
style="margin-right: 5px"
|
style="margin-right: 5px"
|
||||||
@click="reloadData">
|
@click="reloadData">
|
||||||
<RefreshCcw />
|
<RefreshCcw />
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<div>
|
<div>
|
||||||
<TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top">
|
<TooltipWrapper :content="t('view.charts.instance_activity.settings.header')" side="top">
|
||||||
<Button class="rounded-full" size="icon" variant="outline" style="margin-right: 5px">
|
<Button class="rounded-full" size="icon" variant="ghost" style="margin-right: 5px">
|
||||||
<Settings />
|
<Settings />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipWrapper>
|
</TooltipWrapper>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
<ButtonGroup style="margin-right: 5px">
|
<ButtonGroup class="mr-2">
|
||||||
<TooltipWrapper :content="t('view.charts.instance_activity.previous_day')" side="top">
|
<TooltipWrapper :content="t('view.charts.instance_activity.previous_day')" side="top">
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
|
|
||||||
<div ref="activityChartRef" style="width: 100%"></div>
|
<div ref="activityChartRef" style="width: 100%"></div>
|
||||||
<div v-if="!isLoading && activityData.length === 0" class="nodata">
|
<div v-if="!isLoading && activityData.length === 0" class="nodata">
|
||||||
<span>No data here, try another day</span>
|
<DataTableEmpty type="nodata" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<transition name="el-fade-in-linear">
|
<transition name="el-fade-in-linear">
|
||||||
@@ -165,6 +165,7 @@
|
|||||||
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card';
|
||||||
import { fromDate, getLocalTimeZone, today } from '@internationalized/date';
|
import { fromDate, getLocalTimeZone, today } from '@internationalized/date';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { ButtonGroup } from '@/components/ui/button-group';
|
import { ButtonGroup } from '@/components/ui/button-group';
|
||||||
import { Calendar } from '@/components/ui/calendar';
|
import { Calendar } from '@/components/ui/calendar';
|
||||||
import { Separator } from '@/components/ui/separator';
|
import { Separator } from '@/components/ui/separator';
|
||||||
|
|||||||
@@ -10,12 +10,16 @@
|
|||||||
</transition>
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ref="activityDetailChartRef"></div>
|
<div v-if="hasChartData" ref="activityDetailChartRef"></div>
|
||||||
|
<div v-else style="display: flex; justify-content: center; align-items: center; min-height: 160px; width: 100%">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
|
import { computed, nextTick, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
@@ -47,6 +51,7 @@
|
|||||||
let echartsInstance = null;
|
let echartsInstance = null;
|
||||||
const usersFirstActivity = ref(null);
|
const usersFirstActivity = ref(null);
|
||||||
const resizeObserver = ref(null);
|
const resizeObserver = ref(null);
|
||||||
|
const hasChartData = computed(() => (props.activityDetailData || []).length > 0);
|
||||||
|
|
||||||
const startTimeStamp = computed(() => {
|
const startTimeStamp = computed(() => {
|
||||||
return props.activityDetailData.find((item) => item.user_id === currentUser.value.id)?.joinTime.valueOf();
|
return props.activityDetailData.find((item) => item.user_id === currentUser.value.id)?.joinTime.valueOf();
|
||||||
@@ -189,7 +194,7 @@
|
|||||||
if (!props.activityDetailData || props.activityDetailData.length === 0) {
|
if (!props.activityDetailData || props.activityDetailData.length === 0) {
|
||||||
return {
|
return {
|
||||||
title: {
|
title: {
|
||||||
text: 'No data available',
|
text: 'No data',
|
||||||
left: 'center',
|
left: 'center',
|
||||||
top: 'middle'
|
top: 'middle'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<Button
|
<Button
|
||||||
class="rounded-full"
|
class="rounded-full"
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="outline"
|
variant="ghost"
|
||||||
:disabled="!graphReady"
|
:disabled="!graphReady"
|
||||||
@click="openForceDialog">
|
@click="openForceDialog">
|
||||||
<Settings />
|
<Settings />
|
||||||
|
|||||||
@@ -244,7 +244,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="group-empty">No Data</div>
|
<div v-else class="group-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
<TooltipWrapper
|
<TooltipWrapper
|
||||||
v-if="!isCreatingLocalGroup"
|
v-if="!isCreatingLocalGroup"
|
||||||
:disabled="isLocalUserVrcPlusSupporter"
|
:disabled="isLocalUserVrcPlusSupporter"
|
||||||
@@ -401,7 +403,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nomatch" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="activeRemoteGroup">
|
<template v-else-if="activeRemoteGroup">
|
||||||
@@ -421,7 +425,9 @@
|
|||||||
@click="showAvatarDialog(favorite.id)" />
|
@click="showAvatarDialog(favorite.id)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="!remoteAvatarGroupsResolved">
|
<template v-else-if="!remoteAvatarGroupsResolved">
|
||||||
@@ -452,7 +458,9 @@
|
|||||||
@click="showAvatarDialog(favorite.id)" />
|
@click="showAvatarDialog(favorite.id)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="isHistorySelected">
|
<template v-else-if="isHistorySelected">
|
||||||
@@ -468,7 +476,9 @@
|
|||||||
@click="showAvatarDialog(favorite.id)" />
|
@click="showAvatarDialog(favorite.id)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -484,9 +494,10 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, markRaw, nextTick, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
import { computed, markRaw, nextTick, onBeforeMount, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
|
||||||
import { ArrowUpDown, Check, Ellipsis, Loader, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
|
import { ArrowUpDown, Ellipsis, Loader, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
|
||||||
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
|
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|||||||
@@ -163,7 +163,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="group-empty">No Data</div>
|
<div v-else class="group-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -237,7 +239,9 @@
|
|||||||
@click="showUserDialog(favorite.id)" />
|
@click="showUserDialog(favorite.id)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="!isSearchActive">
|
<template v-else-if="!isSearchActive">
|
||||||
@@ -275,7 +279,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nomatch" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@@ -290,6 +296,7 @@
|
|||||||
import { computed, nextTick, onBeforeMount, onMounted, onUnmounted, ref, watch } from 'vue';
|
import { computed, nextTick, onBeforeMount, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||||
import { ArrowUpDown, Check, Ellipsis, MoreHorizontal, RefreshCw } from 'lucide-vue-next';
|
import { ArrowUpDown, Check, Ellipsis, MoreHorizontal, RefreshCw } from 'lucide-vue-next';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { InputGroupSearch } from '@/components/ui/input-group';
|
import { InputGroupSearch } from '@/components/ui/input-group';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
@input="searchWorldFavorites" />
|
@input="searchWorldFavorites" />
|
||||||
<DropdownMenu v-model:open="worldToolbarMenuOpen">
|
<DropdownMenu v-model:open="worldToolbarMenuOpen">
|
||||||
<DropdownMenuTrigger as-child>
|
<DropdownMenuTrigger as-child>
|
||||||
<Button class="rounded-full" size="icon" variant="outline"><Ellipsis /></Button>
|
<Button class="rounded-full" size="icon" variant="ghost"><Ellipsis /></Button>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent class="favorites-dropdown">
|
<DropdownMenuContent class="favorites-dropdown">
|
||||||
<li class="favorites-dropdown__control" @click.stop>
|
<li class="favorites-dropdown__control" @click.stop>
|
||||||
@@ -244,7 +244,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="group-empty">No Data</div>
|
<div v-else class="group-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="!isCreatingLocalGroup"
|
v-if="!isCreatingLocalGroup"
|
||||||
class="group-item group-item--new"
|
class="group-item group-item--new"
|
||||||
@@ -355,7 +357,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nomatch" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -377,7 +381,9 @@
|
|||||||
@click="showWorldDialog(favorite.id)" />
|
@click="showWorldDialog(favorite.id)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else-if="activeLocalGroupName && isLocalGroupSelected"
|
v-else-if="activeLocalGroupName && isLocalGroupSelected"
|
||||||
@@ -410,9 +416,13 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="favorites-empty">
|
||||||
|
<DataTableEmpty type="nodata" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="favorites-empty">No Data</div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -427,6 +437,7 @@
|
|||||||
import { ArrowUpDown, Ellipsis, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
|
import { ArrowUpDown, Ellipsis, MoreHorizontal, Plus, RefreshCcw, RefreshCw } from 'lucide-vue-next';
|
||||||
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
|
import { InputGroupField, InputGroupSearch } from '@/components/ui/input-group';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { Spinner } from '@/components/ui/spinner';
|
import { Spinner } from '@/components/ui/spinner';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button class="rounded-full mr-2" size="icon" variant="outline">
|
<Button class="rounded-full mr-2" size="icon" variant="ghost">
|
||||||
<Settings />
|
<Settings />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
@@ -112,7 +112,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="friend-view__empty">{{ t('view.friends_locations.no_matching_friends') }}</div>
|
<div v-else class="friend-view__empty">
|
||||||
|
<DataTableEmpty type="nomatch" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="friend-view__initial-loading">
|
<div v-else class="friend-view__initial-loading">
|
||||||
<Loader2 class="friend-view__loading-icon" :size="22" />
|
<Loader2 class="friend-view__loading-icon" :size="22" />
|
||||||
@@ -126,6 +128,7 @@
|
|||||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { Loader2, Settings } from 'lucide-vue-next';
|
import { Loader2, Settings } from 'lucide-vue-next';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { InputGroupSearch } from '@/components/ui/input-group';
|
import { InputGroupSearch } from '@/components/ui/input-group';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<TooltipWrapper side="bottom" :content="t('view.moderation.refresh_tooltip')">
|
<TooltipWrapper side="bottom" :content="t('view.moderation.refresh_tooltip')">
|
||||||
<Button
|
<Button
|
||||||
class="rounded-full"
|
class="rounded-full"
|
||||||
variant="outline"
|
variant="ghost"
|
||||||
size="icon-sm"
|
size="icon-sm"
|
||||||
:disabled="playerModerationTable.loading"
|
:disabled="playerModerationTable.loading"
|
||||||
@click="refreshPlayerModerations()">
|
@click="refreshPlayerModerations()">
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
<TooltipWrapper side="bottom" :content="t('view.notification.refresh_tooltip')">
|
<TooltipWrapper side="bottom" :content="t('view.notification.refresh_tooltip')">
|
||||||
<Button
|
<Button
|
||||||
class="rounded-full"
|
class="rounded-full"
|
||||||
variant="outline"
|
variant="ghost"
|
||||||
size="icon-sm"
|
size="icon-sm"
|
||||||
:disabled="isNotificationsLoading"
|
:disabled="isNotificationsLoading"
|
||||||
style="flex: none"
|
style="flex: none"
|
||||||
|
|||||||
@@ -56,7 +56,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div v-if="quickSearchItems.length === 0" class="px-2 py-2 text-xs opacity-70">
|
<div v-if="quickSearchItems.length === 0" class="px-2 py-2 text-xs opacity-70">
|
||||||
No results
|
<DataTableEmpty type="nomatch" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
<TooltipWrapper side="bottom" :content="t('side_panel.refresh_tooltip')">
|
<TooltipWrapper side="bottom" :content="t('side_panel.refresh_tooltip')">
|
||||||
<Button
|
<Button
|
||||||
class="rounded-full"
|
class="rounded-full"
|
||||||
variant="outline"
|
variant="ghost"
|
||||||
size="icon-sm"
|
size="icon-sm"
|
||||||
:disabled="isRefreshFriendsLoading"
|
:disabled="isRefreshFriendsLoading"
|
||||||
style="margin-right: 10px"
|
style="margin-right: 10px"
|
||||||
@@ -117,6 +117,7 @@
|
|||||||
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
import { computed, nextTick, onMounted, ref, watch } from 'vue';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { DataTableEmpty } from '@/components/ui/data-table';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { RefreshCw } from 'lucide-vue-next';
|
import { RefreshCw } from 'lucide-vue-next';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
|
|||||||
Reference in New Issue
Block a user