[READ-ONLY] Mirror of https://github.com/probablykasper/kadium. App for staying ontop of YouTube channels' uploads kadium.kasper.space
linux macos notifications tauri windows youtube
0

Configure Feed

Select the types of activity you want to include in your feed.

Double-click to edit tags

Kasper (Jan 10, 2024, 10:00 AM +0100) eff22faa 6110c52e

+74 -55
+1
CHANGELOG.md
··· 6 6 - Load 100 videos at a time instead of 50 7 7 - Allow selecting bottom row diagonally with the down arrow key 8 8 - Fix channel tags sometimes not saving 9 + - Add ability to edit tags by double-clicking 9 10 10 11 ## 1.5.0 - 2023 Nov 19 11 12 - Add support for all channel URLs. URLs like `/lacunarecs`, `/@lacunarecs`, `/c/lacunarecs`, `/user/lacunarecs` and even `/lacunarecs/playlists` etc work now.
+73 -55
src/lib/Tags.svelte
··· 1 1 <script lang="ts"> 2 + import { tick } from 'svelte' 2 3 import { checkShortcut } from './general' 3 4 4 5 export let value: string[] 5 6 export let onUpdate: () => void 6 7 let inputEl: HTMLInputElement 8 + let text = '' 9 + let editingIndex: number | null = null 7 10 8 - let editing = false 9 - function startEditing() { 10 - editing = true 11 - text = value[value.length - 1] 12 - } 13 - function startAdding() { 14 - editing = false 11 + async function startAdding() { 12 + editingIndex = null 13 + await tick() 14 + inputEl.focus() 15 15 text = '' 16 16 } 17 + async function startEditing(index: number) { 18 + editingIndex = index 19 + await tick() 20 + inputEl.focus() 21 + text = value[index] 22 + } 23 + 24 + function add(text: string) { 25 + value.push(text) 26 + update(value) 27 + } 17 28 function applyEditing() { 18 - if (editing) { 29 + if (editingIndex !== null) { 19 30 if (text === '') { 20 - value.pop() 31 + value.splice(editingIndex, 1) 21 32 update(value) 22 - } else if (text !== value[value.length - 1]) { 23 - value[value.length - 1] = text 33 + } else if (text !== value[editingIndex]) { 34 + value[editingIndex] = text 24 35 update(value) 25 36 } 26 37 text = '' 27 - editing = false 38 + editingIndex = null 28 39 } 29 40 } 30 - 31 - let text = '' 41 + function remove(i: number) { 42 + value.splice(i, 1) 43 + update(value) 44 + } 32 45 33 46 function update(newValue: string[]) { 34 47 value = newValue ··· 39 52 text = '' 40 53 } 41 54 function onBlur() { 42 - if (editing) { 55 + if (editingIndex !== null) { 43 56 applyEditing() 44 57 } else if (text !== '') { 45 - value.push(text) 46 - update(value) 58 + add(text) 47 59 } 48 60 text = '' 49 61 } 50 62 let tagXEls: HTMLButtonElement[] = [] 51 - async function editingKeydown(e: KeyboardEvent) { 52 - if (checkShortcut(e, 'Enter')) { 53 - applyEditing() 54 - } else if (checkShortcut(e, 'Backspace')) { 55 - if (text === '' && value.length >= 2) { 56 - e.preventDefault() 57 - value.pop() 58 - update(value) 59 - startEditing() 60 - } 61 - } else if (checkShortcut(e, 'Escape')) { 62 - startAdding() 63 - e.preventDefault() 64 - } 65 - } 66 63 async function keydown(e: KeyboardEvent) { 67 - if (editing) { 64 + if (editingIndex !== null) { 68 65 editingKeydown(e) 69 66 return 70 67 } 71 68 if (checkShortcut(e, 'Enter')) { 72 69 if (text !== '') { 73 - value.push(text) 74 - update(value) 70 + add(text) 75 71 startAdding() 76 72 } 77 73 } else if (checkShortcut(e, 'Backspace')) { 78 74 if (text === '' && value.length >= 1) { 79 75 e.preventDefault() 80 - startEditing() 76 + startEditing(value.length - 1) 81 77 } 82 - } else if (checkShortcut(e, 'Escape')) { 83 - e.preventDefault() 84 78 } 85 79 } 86 - function remove(i: number) { 87 - value.splice(i, 1) 88 - update(value) 80 + async function editingKeydown(e: KeyboardEvent) { 81 + if (checkShortcut(e, 'Enter')) { 82 + applyEditing() 83 + startAdding() 84 + } else if (checkShortcut(e, 'Backspace') && editingIndex !== null) { 85 + if (text === '' && value.length >= 2) { 86 + e.preventDefault() 87 + remove(editingIndex) 88 + startEditing(editingIndex - 1) 89 + } 90 + } else if (checkShortcut(e, 'Escape')) { 91 + startAdding() 92 + } 89 93 } 90 94 function tagKeydown(e: KeyboardEvent, i: number) { 91 95 if (checkShortcut(e, 'Backspace')) { 92 - value.splice(i, 1) 93 - update(value) 96 + remove(i) 94 97 if (i >= 1) { 95 98 tagXEls[i - 1].focus() 96 99 } else { ··· 103 106 <div class="tags"> 104 107 <div class="label">Tags</div> 105 108 {#each value as tag, i} 106 - {#if i === value.length - 1 && editing} 107 - <!-- hide last element when editing --> 109 + {#if i === editingIndex} 110 + <input 111 + bind:this={inputEl} 112 + type="text" 113 + placeholder="Add tags..." 114 + on:focus={onFocus} 115 + on:blur={onBlur} 116 + on:keydown={keydown} 117 + bind:value={text} 118 + /> 108 119 {:else} 109 120 <div class="tag"> 110 - {tag}<button 121 + <span 122 + role="none" 123 + on:dblclick={() => { 124 + startEditing(i) 125 + }}>{tag}</span 126 + ><button 111 127 bind:this={tagXEls[i]} 112 128 on:keydown={(e) => tagKeydown(e, i)} 113 129 on:click={() => remove(i)} ··· 116 132 </div> 117 133 {/if} 118 134 {/each} 119 - <input 120 - bind:this={inputEl} 121 - type="text" 122 - placeholder="Add tags..." 123 - on:focus={onFocus} 124 - on:blur={onBlur} 125 - on:keydown={keydown} 126 - bind:value={text} 127 - /> 135 + {#if editingIndex === null} 136 + <input 137 + bind:this={inputEl} 138 + type="text" 139 + placeholder="Add tags..." 140 + on:focus={onFocus} 141 + on:blur={onBlur} 142 + on:keydown={keydown} 143 + bind:value={text} 144 + /> 145 + {/if} 128 146 </div> 129 147 130 148 <style lang="sass">