110 lines
3.6 KiB
Vue
110 lines
3.6 KiB
Vue
<template>
|
|
<v-pagination :density="density"
|
|
:disabled="disabled"
|
|
:total-visible="totalVisible ?? 7"
|
|
:length="totalPageCount"
|
|
v-model="currentPage">
|
|
<template #item="{ key, page, isActive }">
|
|
<v-btn variant="text"
|
|
:density="density"
|
|
:disabled="disabled"
|
|
:icon="true"
|
|
:color="isActive ? 'primary' : 'default'"
|
|
@click="currentPage = key;"
|
|
v-if="isNumber(key)"
|
|
>
|
|
<span>{{ formatNumberToLocalizedNumerals(key) }}</span>
|
|
</v-btn>
|
|
<v-btn variant="text"
|
|
color="default"
|
|
:density="density"
|
|
:disabled="disabled"
|
|
:icon="true"
|
|
v-if="!isNumber(key)"
|
|
>
|
|
<span>{{ page }}</span>
|
|
<v-menu activator="parent"
|
|
:disabled="disabled"
|
|
:close-on-content-click="false"
|
|
v-model="showMenus[key]">
|
|
<v-list>
|
|
<v-list-item class="text-sm" :density="density">
|
|
<v-list-item-title class="cursor-pointer">
|
|
<v-autocomplete width="110"
|
|
item-title="name"
|
|
item-value="value"
|
|
auto-select-first
|
|
:density="density"
|
|
:items="allPages"
|
|
:custom-filter="customFilter"
|
|
:no-data-text="tt('No results')"
|
|
v-model="currentPage"/>
|
|
</v-list-item-title>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
</v-btn>
|
|
</template>
|
|
</v-pagination>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed } from 'vue';
|
|
import type { InternalItem, FilterMatch } from 'vuetify/lib/composables/filter.d.ts';
|
|
|
|
import { useI18n } from '@/locales/helpers.ts';
|
|
|
|
import { type NameNumeralValue, keys } from '@/core/base.ts';
|
|
|
|
import { isNumber } from '@/lib/common.ts';
|
|
import type { ComponentDensity } from '@/lib/ui/desktop.ts';
|
|
|
|
const props = defineProps<{
|
|
density?: ComponentDensity;
|
|
disabled?: boolean;
|
|
totalPageCount: number;
|
|
totalVisible?: number;
|
|
modelValue: number;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
(e: 'update:modelValue', value: number): void;
|
|
}>();
|
|
|
|
const { tt, formatNumberToLocalizedNumerals } = useI18n();
|
|
|
|
const showMenus = ref<Record<string, boolean>>({});
|
|
|
|
const allPages = computed<NameNumeralValue[]>(() => {
|
|
const pages: NameNumeralValue[] = [];
|
|
|
|
for (let i = 1; i <= props.totalPageCount; i++) {
|
|
pages.push({ value: i, name: formatNumberToLocalizedNumerals(i) });
|
|
}
|
|
|
|
return pages;
|
|
});
|
|
|
|
const currentPage = computed<number>({
|
|
get: () => props.modelValue,
|
|
set: (value) => {
|
|
if (value && value >= 1 && value <= props.totalPageCount) {
|
|
emit('update:modelValue', value);
|
|
|
|
for (const key of keys(showMenus.value)) {
|
|
showMenus.value[key] = false;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
function customFilter(value: string, query: string, item?: InternalItem): FilterMatch {
|
|
if (!item) {
|
|
return false;
|
|
}
|
|
|
|
const page = item.value as number;
|
|
return page.toString(10).includes(query);
|
|
}
|
|
</script>
|