forked from akanyan/STARTLINER
feat: categories and option search
This commit is contained in:
@ -24,8 +24,7 @@ const general = useGeneralStore();
|
||||
pkg.setupListeners();
|
||||
|
||||
const currentTab: Ref<string | number> = ref(3);
|
||||
const searchPkg = ref('');
|
||||
const searchCfg = ref('');
|
||||
const pkgSearchTerm = ref('');
|
||||
|
||||
const isProfileDisabled = computed(() => prf.current === null);
|
||||
|
||||
@ -34,7 +33,7 @@ onMounted(async () => {
|
||||
general.dirs = d as Dirs;
|
||||
});
|
||||
|
||||
const fetch_promise = pkg.fetch();
|
||||
const fetch_promise = pkg.fetch(true);
|
||||
|
||||
await Promise.all([prf.reloadList(), prf.reload()]);
|
||||
|
||||
@ -65,7 +64,10 @@ onMounted(async () => {
|
||||
<Tab :disabled="isProfileDisabled" :value="0"
|
||||
><div class="pi pi-list-check"></div
|
||||
></Tab>
|
||||
<Tab :disabled="isProfileDisabled" :value="1"
|
||||
<Tab
|
||||
v-if="!pkg.offline"
|
||||
:disabled="isProfileDisabled"
|
||||
:value="1"
|
||||
><div class="pi pi-download"></div
|
||||
></Tab>
|
||||
<Tab :disabled="isProfileDisabled" :value="2"
|
||||
@ -75,23 +77,32 @@ onMounted(async () => {
|
||||
><div class="pi pi-question-circle"></div
|
||||
></Tab>
|
||||
<div class="grow"></div>
|
||||
<div class="flex" v-if="currentTab !== 3">
|
||||
<InputIcon class="self-center mr-2">
|
||||
<i class="pi pi-search" />
|
||||
</InputIcon>
|
||||
<InputText
|
||||
v-if="currentTab === 2"
|
||||
class="self-center"
|
||||
<div class="flex gap-4">
|
||||
<div class="flex" v-if="currentTab !== 3">
|
||||
<InputIcon class="self-center mr-2">
|
||||
<i class="pi pi-search" />
|
||||
</InputIcon>
|
||||
<InputText
|
||||
v-if="currentTab === 2"
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
v-model="general.cfgSearchTerm"
|
||||
/>
|
||||
<InputText
|
||||
v-else
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
v-model="pkgSearchTerm"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
v-if="pkg.offline"
|
||||
class="shrink self-center"
|
||||
icon="pi pi-sync"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
v-model="searchCfg"
|
||||
/>
|
||||
<InputText
|
||||
v-else
|
||||
class="self-center"
|
||||
size="small"
|
||||
placeholder="Search"
|
||||
v-model="searchPkg"
|
||||
@click="pkg.fetch(false)"
|
||||
/>
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
@ -100,10 +111,10 @@ onMounted(async () => {
|
||||
</div>
|
||||
<TabPanels class="w-full grow mt-[3rem]">
|
||||
<TabPanel :value="0">
|
||||
<ModList :search="searchPkg" />
|
||||
<ModList :search="pkgSearchTerm" />
|
||||
</TabPanel>
|
||||
<TabPanel :value="1">
|
||||
<ModStore :search="searchPkg" />
|
||||
<ModStore :search="pkgSearchTerm" />
|
||||
</TabPanel>
|
||||
<TabPanel :value="2">
|
||||
<OptionList />
|
||||
|
@ -1,5 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import Divider from 'primevue/divider';
|
||||
import MultiSelect from 'primevue/multiselect';
|
||||
import ToggleSwitch from 'primevue/toggleswitch';
|
||||
import ModStoreEntry from './ModStoreEntry.vue';
|
||||
import { usePkgStore } from '../stores';
|
||||
|
||||
@ -28,6 +31,37 @@ const list = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-2">
|
||||
<div class="text-amber-400 grow">Show deprecated</div>
|
||||
<ToggleSwitch v-model="pkgs.showDeprecated" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<div class="text-red-400 grow">Show NSFW</div>
|
||||
<ToggleSwitch v-model="pkgs.showNSFW" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 grow">
|
||||
<MultiSelect
|
||||
size="small"
|
||||
:showToggleAll="false"
|
||||
placeholder="Include categories"
|
||||
v-model="pkgs.includeCategories"
|
||||
:options="[...pkgs.availableCategories]"
|
||||
class="w-full"
|
||||
/>
|
||||
<MultiSelect
|
||||
size="small"
|
||||
:showToggleAll="false"
|
||||
placeholder="Exclude categories"
|
||||
v-model="pkgs.excludeCategories"
|
||||
:options="[...pkgs.availableCategories]"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div v-for="p in list()" class="flex flex-row">
|
||||
<ModStoreEntry :pkg="p" />
|
||||
</div>
|
||||
|
@ -11,7 +11,7 @@ defineProps({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ModTitlecard :pkg="pkg" showNamespace />
|
||||
<ModTitlecard :pkg="pkg" show-namespace show-categories />
|
||||
<InstallButton :pkg="pkg" />
|
||||
<Button
|
||||
rounded
|
||||
|
@ -1,4 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import Chip from 'primevue/chip';
|
||||
import { convertFileSrc } from '@tauri-apps/api/core';
|
||||
import { Package } from '../types';
|
||||
import { needsUpdate } from '../util';
|
||||
@ -7,6 +8,7 @@ const props = defineProps({
|
||||
pkg: Object as () => Package,
|
||||
showNamespace: Boolean,
|
||||
showVersion: Boolean,
|
||||
showCategories: Boolean,
|
||||
});
|
||||
|
||||
const iconSrc = () => {
|
||||
@ -34,6 +36,18 @@ const iconSrc = () => {
|
||||
<span class="text-lg">
|
||||
{{ pkg?.name ?? 'Untitled' }}
|
||||
</span>
|
||||
<span
|
||||
v-if="pkg?.rmt?.deprecated"
|
||||
v-tooltip="'deprecated'"
|
||||
class="pi pi-exclamation-circle ml-1 text-amber-400"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
v-if="pkg?.rmt?.nsfw"
|
||||
v-tooltip="'NSFW'"
|
||||
class="pi pi-exclamation-triangle ml-1 text-red-400"
|
||||
>
|
||||
</span>
|
||||
<span
|
||||
v-if="showNamespace && pkg?.namespace"
|
||||
class="text-sm opacity-75"
|
||||
@ -58,5 +72,17 @@ const iconSrc = () => {
|
||||
<div class="text-sm opacity-75">
|
||||
{{ pkg?.description ?? 'No description' }}
|
||||
</div>
|
||||
<div v-if="showCategories" class="mt-1 flex gap-1">
|
||||
<span class="text-xs" v-for="c in pkg?.rmt?.categories"
|
||||
><Chip :label="c"
|
||||
/></span>
|
||||
</div>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.p-chip {
|
||||
padding: 0.4rem !important;
|
||||
font-size: 0.66rem !important;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,5 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import Fieldset from 'primevue/fieldset';
|
||||
import { useGeneralStore } from '../stores';
|
||||
|
||||
const general = useGeneralStore();
|
||||
|
||||
defineProps({
|
||||
title: String,
|
||||
@ -7,7 +10,11 @@ defineProps({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Fieldset :legend="title" :toggleable="true">
|
||||
<Fieldset
|
||||
:legend="title"
|
||||
:toggleable="true"
|
||||
v-show="general.cfgCategories.has(title ?? '')"
|
||||
>
|
||||
<div class="flex w-full flex-col gap-1">
|
||||
<slot />
|
||||
</div>
|
||||
|
@ -1,11 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
import { computed, getCurrentInstance } from 'vue';
|
||||
import { useGeneralStore } from '../stores';
|
||||
|
||||
const general = useGeneralStore();
|
||||
const category = getCurrentInstance()?.parent?.parent?.parent?.parent; // yes indeed
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
});
|
||||
|
||||
const searched = computed(() => {
|
||||
const term = general.cfgSearchTerm.toLowerCase();
|
||||
const categoryTitle = category?.props?.title as string | undefined;
|
||||
const res =
|
||||
props.title?.toLowerCase().includes(term) ||
|
||||
categoryTitle?.toLowerCase().includes(term);
|
||||
if (res === true && categoryTitle !== undefined) {
|
||||
general.cfgCategories.add(categoryTitle);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-row w-full p-2 gap-2 items-center">
|
||||
<div v-if="searched" class="flex flex-row w-full p-2 gap-2 items-center">
|
||||
<div class="grow">{{ title }}</div>
|
||||
<slot />
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user