internal/dashboard/frontend/src/components/EventTable/EventTableFooter.vue

<script setup lang="ts">
import { IconChevronLeft, IconChevronRight } from "@tabler/icons-vue";
import type { FilterActions } from "src/store";
import { formatLocalNumber } from "utils/formatting";

const props = defineProps<{
  totalEvents: number;
  filterActions: FilterActions;
}>();

const state = props.filterActions.state;

function previousPage() {
  state.offset = Math.max(0, state.offset - state.limit);
}

function nextPage() {
  state.offset = Math.min(state.offset + state.limit, props.totalEvents);
}
</script>

<template>
  <div
    class="bg-card sticky bottom-0 flex min-h-12 flex-wrap items-center justify-between gap-2 rounded-b-xl border-t border-stone-800 px-4 py-3 text-sm"
  >
    <div class="flex items-center gap-2">
      <button
        @click="previousPage"
        :disabled="state.offset <= 0"
        class="btn-secondary py-0.5 pl-0.5 font-semibold uppercase select-none"
      >
        <IconChevronLeft class="mt-px" /> Previous
      </button>
      <span>
        {{ Math.floor(state.offset / state.limit) + 1 }} /
        {{ formatLocalNumber(Math.ceil(totalEvents / state.limit)) }}
      </span>
      <button
        @click="nextPage"
        :disabled="state.offset + state.limit >= totalEvents"
        class="btn-secondary py-0.5 pr-0.5 font-semibold uppercase select-none"
      >
        Next <IconChevronRight class="mt-px" />
      </button>
    </div>
    <div class="flex items-center gap-2">
      <span class="filter-label">Events per page:</span>
      <select
        v-model.number="state.limit"
        class="select"
        @change="state.offset = 0"
      >
        <option value="25">25</option>
        <option value="50">50</option>
        <option value="100">100</option>
        <option value="200">200</option>
        <option value="500">500</option>
        <option value="1000">1000</option>
      </select>
    </div>
  </div>
</template>