150 lines
3.5 KiB
Vue
150 lines
3.5 KiB
Vue
<script setup>
|
|
import {onMounted, ref} from 'vue';
|
|
import ToolsBox from "../components/Tools_box.vue";
|
|
|
|
const categories = ref([
|
|
{ name: '计算', active: false },
|
|
]);
|
|
|
|
|
|
const searchQuery = ref('');
|
|
|
|
|
|
const tools = ref([
|
|
{ id: 1, title: 'GPA在线计算器', description: '手动输入在线算', image: null, category: ['计算'] },
|
|
{ id: 2, title: 'PDF页面提取器', description: '提取指定页和封面', image: null, category: ['提取', 'pdf'] },
|
|
{ id: 3, title: '请求测试器', description: '自定义请求测试', image: null, category: ['开发', '网络'] },
|
|
{ id: 4, title: '图片转PDF', description: '导入图片生成pdf', image: null, category: ['pdf', '生成'] },
|
|
]);
|
|
|
|
onMounted(() => {
|
|
const tags = {};
|
|
tools.value.forEach(tool => {
|
|
tool.category.forEach(tag => {
|
|
tags[tag] = tags[tag]+1 || 1;
|
|
})
|
|
})
|
|
function topNKeys(obj, n) {
|
|
let sortedEntries = Object.entries(obj).sort((a, b) => b[1] - a[1]);
|
|
return sortedEntries.slice(0, n).map(entry => entry[0]);
|
|
}
|
|
categories.value = topNKeys(tags, 10).map(tag => { return { name: tag, active: false }})
|
|
})
|
|
|
|
// Toggle function for categories, only one category can be active at a time
|
|
const toggleCategory = (category) => {
|
|
if (category.active) {
|
|
category.active = false; // Deselect if already selected
|
|
} else {
|
|
categories.value.forEach(cat => cat.active = false); // Deselect all other categories
|
|
category.active = true; // Select the clicked category
|
|
}
|
|
};
|
|
|
|
const filterTools = () => {
|
|
return tools.value.filter(tool => {
|
|
const matchesCategory = categories.value.some(cat => cat.active && tool.category.includes(cat.name));
|
|
const matchesSearch = tool.title.toLowerCase().includes(searchQuery.value.toLowerCase());
|
|
return (!categories.value.some(cat => cat.active) || matchesCategory) && matchesSearch;
|
|
});
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="container" v-if="/^\/tools\/?$/.test($route.path)">
|
|
<div class="filters">
|
|
<div class="categories">
|
|
<span
|
|
v-for="category in categories"
|
|
:key="category.name"
|
|
:class="{ active: category.active }"
|
|
@click="toggleCategory(category)"
|
|
>
|
|
{{ category.name }}
|
|
</span>
|
|
</div>
|
|
<input type="text" v-model="searchQuery" placeholder="搜索工具..." class="search-bar" />
|
|
</div>
|
|
|
|
<div class="tools">
|
|
<ToolsBox
|
|
v-for="tool in filterTools()"
|
|
:key="tool.title"
|
|
:tool="tool"
|
|
|
|
/>
|
|
</div>
|
|
</div>
|
|
<router-view v-else />
|
|
</template>
|
|
|
|
<style scoped>
|
|
.container {
|
|
height: calc(100vh - 100px);
|
|
width: 100%;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
display: flex;
|
|
justify-content: flex-start;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 20px 0;
|
|
}
|
|
|
|
.filters {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
width: 100%;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.categories {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
justify-content: center;
|
|
}
|
|
|
|
.categories span {
|
|
cursor: pointer;
|
|
padding: 5px 10px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.categories span.active {
|
|
background-color: #007bff;
|
|
color: white;
|
|
}
|
|
|
|
.search-bar {
|
|
padding: 10px;
|
|
margin: 20px 0;
|
|
width: 50%;
|
|
border-radius: 10px;
|
|
border: 1px solid #ccc;
|
|
}
|
|
|
|
.tools {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
width: 100%;
|
|
}
|
|
|
|
.theme-light .categories span.active {
|
|
background-color: #ffb74d;
|
|
color: black;
|
|
}
|
|
|
|
.theme-light .search-bar {
|
|
border: 1px solid #ffb74d;
|
|
}
|
|
|
|
::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
</style>
|