✨ Add filtering functionality to the gamemaster panel
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div v-if="hasData" class="filter-panel">
|
||||
<div class="filter-row">
|
||||
<label for="property-select">Filter by Property:</label>
|
||||
<select
|
||||
id="property-select"
|
||||
v-model="filterProperty"
|
||||
@change="applyFilter"
|
||||
>
|
||||
<option value="">All Properties</option>
|
||||
<option v-for="path in availablePaths" :key="path.path" :value="path.path">
|
||||
{{ path.breadcrumb }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-if="filterProperty" class="filter-row">
|
||||
<label for="filter-mode">Mode:</label>
|
||||
<select id="filter-mode" v-model="filterMode" @change="applyFilter">
|
||||
<option value="equals">Equals</option>
|
||||
<option value="contains">Contains</option>
|
||||
<option value="regex">Regex</option>
|
||||
</select>
|
||||
|
||||
<label for="filter-value" class="filter-value-label">Value:</label>
|
||||
<input
|
||||
id="filter-value"
|
||||
v-model="filterValue"
|
||||
@input="applyFilter"
|
||||
:list="valueListId"
|
||||
type="text"
|
||||
placeholder="Enter value..."
|
||||
class="filter-value-input"
|
||||
/>
|
||||
<datalist :id="valueListId">
|
||||
<option v-for="value in valueSuggestions" :key="value" :value="value" />
|
||||
</datalist>
|
||||
|
||||
<button class="btn-clear" @click="clearFilters" title="Clear filter">
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="filter-stats">
|
||||
<span>{{ filterStats.matched }} / {{ filterStats.total }} matched</span>
|
||||
<span v-if="filterStats.total > 0">({{ filterStats.percentage }}%)</span>
|
||||
</div>
|
||||
|
||||
<div v-if="filterError" class="filter-error">
|
||||
{{ filterError }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, watch } from 'vue';
|
||||
import useJsonFilter from '../../composables/useJsonFilter.js';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
filterProperty,
|
||||
filterValue,
|
||||
filterMode,
|
||||
availablePaths,
|
||||
filterError,
|
||||
filterStats,
|
||||
initializeFilter,
|
||||
extractPathsLazy,
|
||||
setFilter,
|
||||
clearFilters,
|
||||
getUniqueValues
|
||||
} = useJsonFilter();
|
||||
|
||||
const hasData = computed(() => Array.isArray(props.data) && props.data.length > 0);
|
||||
|
||||
const valueSuggestions = computed(() => {
|
||||
if (!filterProperty.value) return [];
|
||||
return getUniqueValues(filterProperty.value).slice(0, 50);
|
||||
});
|
||||
|
||||
const valueListId = computed(() => `filter-values-${filterProperty.value || 'all'}`);
|
||||
|
||||
function applyFilter() {
|
||||
setFilter(filterProperty.value, filterValue.value, filterMode.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
data => {
|
||||
if (Array.isArray(data)) {
|
||||
initializeFilter(data);
|
||||
if (data.length > 100) {
|
||||
extractPathsLazy(data, 100);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.filter-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 8px;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.filter-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.filter-row label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.filter-value-label {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.filter-value-input {
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
background: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
padding: 6px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.filter-stats {
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.filter-error {
|
||||
font-size: 13px;
|
||||
color: #d9534f;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user