Skip to content

Commit

Permalink
Add 'Remove' option
Browse files Browse the repository at this point in the history
  • Loading branch information
kommunarr committed Dec 27, 2024
1 parent 3570682 commit 2caa250
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 20 deletions.
11 changes: 11 additions & 0 deletions src/renderer/components/ft-input/ft-input.css
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,17 @@ body[dir='rtl'] .ft-input-component.search.showClearTextButton:focus-within .inp
block-size: 16px;
}

.removeButton {
text-decoration: none;
float: var(--float-right-ltr-rtl-value);
font-size: 13px;
}

.removeButton:hover,
.removeButton.removeButtonSelected {
text-decoration: underline;
}

.hover {
background-color: var(--scrollbar-color-hover);
color: var(--scrollbar-text-color-hover);
Expand Down
62 changes: 53 additions & 9 deletions src/renderer/components/ft-input/ft-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export default defineComponent({
type: Array,
default: null
},
canRemoveResults: {
type: Boolean,
default: false
},
showDataWhenEmpty: {
type: Boolean,
default: false
Expand All @@ -76,7 +80,7 @@ export default defineComponent({
default: ''
}
},
emits: ['clear', 'click', 'input'],
emits: ['clear', 'click', 'input', 'remove'],
data: function () {
let actionIcon = ['fas', 'search']
if (this.forceActionButtonIconName !== null) {
Expand All @@ -96,6 +100,8 @@ export default defineComponent({
// As the text input box should be empty
clearTextButtonExisting: false,
clearTextButtonVisible: false,
removeButtonSelectedIndex: -1,
removalMade: false,
actionButtonIconName: actionIcon
}
},
Expand Down Expand Up @@ -166,6 +172,7 @@ export default defineComponent({
this.searchState.showOptions = false
this.searchState.selectedOption = -1
this.searchState.keyboardSelectedOptionIndex = -1
this.removeButtonSelectedIndex = -1
this.$emit('input', this.inputData)
this.$emit('click', this.inputData, { event: e })
},
Expand Down Expand Up @@ -247,19 +254,34 @@ export default defineComponent({
},

handleOptionClick: function (index) {
if (this.removeButtonSelectedIndex !== -1) {
this.handleRemoveClick(index)
return
}
this.searchState.showOptions = false
this.inputData = this.visibleDataList[index]
this.$emit('input', this.inputData)
this.handleClick()
},

handleRemoveClick: function (index) {
if (!this.canRemoveResults) { return }

// keep focus in input even if removed "Remove" button was clicked
this.$refs.input.focus()
this.removalMade = true
this.$emit('remove', this.visibleDataList[index])
},

/**
* @param {KeyboardEvent} event
*/
handleKeyDown: function (event) {
if (event.key === 'Enter') {
// Update Input box value if enter key was pressed and option selected
if (this.searchState.selectedOption !== -1) {
if (this.removeButtonSelectedIndex !== -1) {
this.handleRemoveClick(this.removeButtonSelectedIndex)
} else if (this.searchState.selectedOption !== -1) {
this.searchState.showOptions = false
event.preventDefault()
this.inputData = this.getTextForArrayAtIndex(this.visibleDataList, this.searchState.selectedOption)
Expand All @@ -274,7 +296,7 @@ export default defineComponent({
if (this.visibleDataList.length === 0) { return }

this.searchState.showOptions = true
const isArrow = event.key === 'ArrowDown' || event.key === 'ArrowUp'
const isArrow = event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'ArrowLeft' || event.key === 'ArrowRight'
if (!isArrow) {
const selectedOptionValue = this.searchStateKeyboardSelectedOptionValue
// Keyboard selected & is char
Expand All @@ -288,17 +310,33 @@ export default defineComponent({
}

event.preventDefault()
if (event.key === 'ArrowDown') {
this.searchState.selectedOption++
} else if (event.key === 'ArrowUp') {
this.searchState.selectedOption--

if (event.key === 'ArrowRight') {
this.removeButtonSelectedIndex = this.searchState.selectedOption
}

if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
const newIndex = this.searchState.selectedOption + (event.key === 'ArrowDown' ? 1 : -1)
this.updateSelectedOptionIndex(newIndex)

// reset removal
this.removeButtonSelectedIndex = -1
}

if (this.searchState.selectedOption !== -1 && event.key === 'ArrowRight') {
this.removeButtonSelectedIndex = this.searchState.selectedOption
}
},

updateSelectedOptionIndex: function (index) {
this.searchState.selectedOption = index
// Allow deselecting suggestion
if (this.searchState.selectedOption < -1) {
this.searchState.selectedOption = this.visibleDataList.length - 1
} else if (this.searchState.selectedOption > this.visibleDataList.length - 1) {
this.searchState.selectedOption = -1
}

// Update displayed value
this.searchState.keyboardSelectedOptionIndex = this.searchState.selectedOption
},
Expand All @@ -313,8 +351,14 @@ export default defineComponent({

updateVisibleDataList: function () {
// Reset selected option before it's updated
this.searchState.selectedOption = -1
this.searchState.keyboardSelectedOptionIndex = -1
if (!this.removalMade || this.searchState.selectedOption >= this.dataList.length) {
this.searchState.selectedOption = -1
this.searchState.keyboardSelectedOptionIndex = -1
this.removeButtonSelectedIndex = -1
}

this.removalMade = false

if (this.inputData.trim() === '') {
this.visibleDataList = this.dataList
return
Expand Down
15 changes: 13 additions & 2 deletions src/renderer/components/ft-input/ft-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,25 @@
:class="{ hover: searchState.selectedOption === index }"
@click="handleOptionClick(index)"
@mouseenter="searchState.selectedOption = index"
@mouseleave="searchState.selectedOption = -1"
@mouseleave="searchState.selectedOption = -1; removeButtonSelectedIndex = -1"
>
<font-awesome-icon
v-if="searchResultIcon"
:icon="searchResultIcon"
class="searchResultIcon"
/>
{{ entry }}
<span>{{ entry }}</span>
<a
v-if="canRemoveResults"
class="removeButton"
:class="{ removeButtonSelected: removeButtonSelectedIndex === index}"
role="button"
:aria-label="$t('Search Bar.Remove')"
href="javascript:void(0)"
@click.prevent.stop="handleRemoveClick(index)"
>
{{ $t('Search Bar.Remove') }}
</a>
</li>
<!-- skipped -->
</ul>
Expand Down
21 changes: 17 additions & 4 deletions src/renderer/components/top-nav/top-nav.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineComponent } from 'vue'
import { mapActions } from 'vuex'
import { mapActions, mapMutations } from 'vuex'
import FtInput from '../ft-input/ft-input.vue'
import FtProfileSelector from '../ft-profile-selector/ft-profile-selector.vue'
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
Expand Down Expand Up @@ -121,17 +121,21 @@ export default defineComponent({
)
},

usingSearchHistoryResults: function () {
return this.lastSuggestionQuery === ''
},

// show latest search history when the search bar is empty
activeDataList: function () {
if (!this.enableSearchSuggestions) {
return
}
return this.lastSuggestionQuery === '' ? this.$store.getters.getLatestUniqueSearchHistoryNames : this.searchSuggestionsDataList
return this.usingSearchHistoryResults ? this.$store.getters.getLatestUniqueSearchHistoryNames : this.searchSuggestionsDataList
},

searchResultIcon: function () {
return this.lastSuggestionQuery === '' ? ['fas', 'clock-rotate-left'] : ['fas', 'magnifying-glass']
}
return this.usingSearchHistoryResults ? ['fas', 'clock-rotate-left'] : ['fas', 'magnifying-glass']
},
},
watch: {
$route: function () {
Expand Down Expand Up @@ -424,10 +428,19 @@ export default defineComponent({
this.navigationHistoryDropdownActiveEntry.label = value
}
},
removeSearchHistoryEntryInDbAndCache(query) {
this.removeSearchHistoryEntry(query)
this.removeFromSessionSearchHistory(query)
},

...mapActions([
'getYoutubeUrlInfo',
'removeSearchHistoryEntry',
'showSearchFilters'
]),

...mapMutations([
'removeFromSessionSearchHistory'
])
}
})
2 changes: 2 additions & 0 deletions src/renderer/components/top-nav/top-nav.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,11 @@
:spellcheck="false"
:show-clear-text-button="true"
:show-data-when-empty="true"
:can-remove-results="usingSearchHistoryResults"
@input="getSearchSuggestionsDebounce"
@click="goToSearch"
@clear="() => lastSuggestionQuery = ''"
@remove="removeSearchHistoryEntryInDbAndCache"
/>
<font-awesome-icon
class="navFilterIcon navIcon"
Expand Down
6 changes: 1 addition & 5 deletions src/renderer/store/modules/search-history.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,7 @@ const mutations = {
},

removeSearchHistoryEntryFromList(state, _id) {
const i = state.searchHistoryEntries.findIndex((searchHistoryEntry) => {
return searchHistoryEntry._id === _id
})

state.searchHistoryEntries.splice(i, 1)
state.searchHistoryEntries = state.searchHistoryEntries.filter((searchHistoryEntry) => searchHistoryEntry._id !== _id)
},

removeSearchHistoryEntriesFromList(state, ids) {
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/store/modules/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,10 @@ const mutations = {
vueSet(state.deArrowCache, payload.videoId, payload)
},

removeFromSessionSearchHistory (state, query) {
state.sessionSearchHistory = state.sessionSearchHistory.filter((search) => search.query !== query)
},

addToSessionSearchHistory (state, payload) {
const sameSearch = state.sessionSearchHistory.findIndex((search) => {
return search.query === payload.query && searchFiltersMatch(payload.searchSettings, search.searchSettings)
Expand Down
1 change: 1 addition & 0 deletions static/locales/en-US.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Global:
Search / Go to URL: Search / Go to URL
Search Bar:
Clear Input: Clear Input
Remove: Remove
Search character limit: Search query is over the {searchCharacterLimit} character limit
Search Listing:
Label:
Expand Down

0 comments on commit 2caa250

Please sign in to comment.