Skip to content

Commit

Permalink
feat: add exclude tags filter for directory entries
Browse files Browse the repository at this point in the history
  • Loading branch information
herteleo committed Nov 2, 2022
1 parent 6e456d7 commit cd38e64
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 16 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Open a local folder and explore your files inside the browser. Your files stay p
IMG001 [2021, Berlin].jpg
IMG002 [2022, New York].jpg
```
Right-click tags in filter to exclude entries with the respective tag from the list.
- Place an image file named like the folder to define a permanent cover/thumbnail. Example:
- Folder name: `Wallpapers`
- Image inside folder: `Wallpapers.jpg`
Expand Down
39 changes: 28 additions & 11 deletions src/features/useDirFilter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, ref, type Ref } from 'vue';
import { computed, reactive, ref, type Ref } from 'vue';
import type { CurrentDirEntry } from '@/features/useDir';

const showFilter = ref(false);
Expand All @@ -9,16 +9,29 @@ const toggleFilter = () => {

const stringFilter = ref('');

const tagFilter = ref<Array<string>>([]);
const tagFilter = reactive<Record<'include' | 'exclude', Array<string>>>({
include: [],
exclude: [],
});

const isTagInFilter = (tag: string) => tagFilter.value.includes(tag);
const isTagFilterActive = computed(() => tagFilter.include.length || tagFilter.exclude.length);

const toggleTag = (tag: string) => {
if (isTagInFilter(tag)) {
tagFilter.value = tagFilter.value.filter((t) => t !== tag);
const isTagInFilter = (tag: string, mode: keyof typeof tagFilter) => tagFilter[mode].includes(tag);

const removeTag = (tag: string, mode: keyof typeof tagFilter) => {
tagFilter[mode] = tagFilter[mode].filter((t) => t !== tag);
};

const toggleTag = (tag: string, mode: keyof typeof tagFilter) => {
if (isTagInFilter(tag, mode)) {
removeTag(tag, mode);
return;
}
tagFilter.value.push(tag);

if (mode === 'exclude' && isTagInFilter(tag, 'include')) removeTag(tag, 'include');
if (mode === 'include' && isTagInFilter(tag, 'exclude')) removeTag(tag, 'exclude');

tagFilter[mode].push(tag);
};

const isUntaggedActive = ref(false);
Expand All @@ -28,7 +41,8 @@ const toggleUntagged = () => {
};

const resetTagFilter = () => {
tagFilter.value = [];
tagFilter.include = [];
tagFilter.exclude = [];
isUntaggedActive.value = false;
};

Expand Down Expand Up @@ -60,7 +74,7 @@ const useDirFilter = (dirEntries: Ref<CurrentDirEntry[]>) => {
.flat()
.sort();

return [...new Set([...tags, ...tagFilter.value].sort())];
return [...new Set([...tags, ...tagFilter.include, ...tagFilter.exclude].sort())];
});

const filteredDirEntries = computed(() => {
Expand All @@ -73,8 +87,10 @@ const useDirFilter = (dirEntries: Ref<CurrentDirEntry[]>) => {
let hasMatchingTags = false;
let show = hasMatchingString;

if (hasMatchingString && tagFilter.value.length) {
hasMatchingTags = tagFilter.value.every((t) => tags.includes(t));
if (hasMatchingString && isTagFilterActive.value) {
hasMatchingTags =
tagFilter.include.every((t) => tags.includes(t)) &&
!tagFilter.exclude.some((t) => tags.includes(t));
show = hasMatchingTags;
}

Expand All @@ -96,6 +112,7 @@ const useDirFilter = (dirEntries: Ref<CurrentDirEntry[]>) => {
stringFilter,

getTagsFromString,
isTagFilterActive,
isTagInFilter,
isUntaggedActive,
removeTagsFromString,
Expand Down
16 changes: 11 additions & 5 deletions src/views/Dir.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ const {
stringFilter,
getTagsFromString,
isTagFilterActive,
isTagInFilter,
removeTagsFromString,
resetTagFilter,
tagFilter,
tagFilterOptions,
toggleTag,
isUntaggedActive,
Expand Down Expand Up @@ -119,8 +119,14 @@ const dirThumbSrc = computed(
v-for="tag in tagFilterOptions"
:key="tag"
class="rounded-full px-2 text-sm"
:class="isTagInFilter(tag) ? 'bg-amber-700 text-amber-100' : 'bg-slate-800 text-slate-400'"
@click="toggleTag(tag)"
:class="{
'bg-amber-700 text-amber-100': isTagInFilter(tag, 'include'),
'bg-slate-900 text-slate-400 line-through': isTagInFilter(tag, 'exclude'),
'bg-slate-800 text-slate-400':
!isTagInFilter(tag, 'include') && !isTagInFilter(tag, 'exclude'),
}"
@click="toggleTag(tag, 'include')"
@contextmenu.prevent="toggleTag(tag, 'exclude')"
v-text="tag"
/>
<button
Expand All @@ -129,10 +135,10 @@ const dirThumbSrc = computed(
isUntaggedActive ? 'border-amber-700 text-amber-300' : 'border-slate-800 text-slate-600'
"
@click="toggleUntagged()"
v-text="tagFilter.length ? '+ Untagged' : 'Untagged'"
v-text="isTagFilterActive ? '+ Untagged' : 'Untagged'"
/>
<button
v-if="tagFilter.length || isUntaggedActive"
v-if="isTagFilterActive || isUntaggedActive"
class="text-sm text-slate-500"
@click="resetTagFilter"
>
Expand Down

0 comments on commit cd38e64

Please sign in to comment.