<script setup lang="ts">
import { IconChevronRight } from "@tabler/icons-vue";
import type { ItemList } from "src/types";
import { onMounted, ref } from "vue";
import SidebarListItem from "./SidebarListItem.vue";
const props = defineProps<{
title: string;
items: ItemList[];
type: "ip" | "port" | "country" | "city";
selectedItem?: any;
open?: boolean;
}>();
defineEmits<{
(e: "click", value: any): void;
(e: "exclude", value: any): void;
}>();
const detailsRef = ref<HTMLDetailsElement | null>(null);
onMounted(() => {
if (props.open && detailsRef.value) {
detailsRef.value.open = true;
}
});
</script>
<template>
<details ref="detailsRef" class="sidebar-list" name="sidebar-accordion">
<summary
class="sticky top-0 z-10 flex shrink-0 cursor-pointer items-center justify-between bg-stone-900 p-2 text-xs font-bold"
>
<div class="flex items-center gap-1">
<IconChevronRight class="icon transition-transform" size="14" />
<span>{{ title }} ({{ items.length }})</span>
</div>
<slot name="header-actions"></slot>
</summary>
<div class="sidebar-list-content flex flex-col gap-0.5 px-1.5 py-1">
<SidebarListItem
v-for="item in items"
:key="item.value"
:type="type"
:value="item.value"
:label="item.label"
:count="item.count"
:is-selected="selectedItem === item.value"
@click="$emit('click', item.value)"
@exclude="$emit('exclude', item.value)"
/>
</div>
</details>
</template>
<style scoped>
@reference "src/style.css";
summary {
@apply list-none appearance-none;
&::-webkit-details-marker {
@apply hidden;
}
}
.sidebar-list {
@apply transition-none;
}
.sidebar-list[open] {
@apply mb-0 min-h-0 flex-1 overflow-y-auto border-b border-stone-800;
&:last-child {
@apply border-b-0;
}
summary {
@apply border-b border-stone-800;
}
.icon {
@apply rotate-90;
}
}
.sidebar-list-content {
@apply pb-2;
}
</style>