mirror of
https://github.com/sigmasternchen/tagify
synced 2025-03-15 07:08:55 +00:00
feat: added autocompletion for MediaDetails component
This commit is contained in:
parent
55df389ae9
commit
984da2c2bc
3 changed files with 71 additions and 6 deletions
59
src/components/Autocomplete/index.tsx
Normal file
59
src/components/Autocomplete/index.tsx
Normal file
|
@ -0,0 +1,59 @@
|
|||
import React, {FunctionComponent, useState} from "react";
|
||||
|
||||
export type AutocompleteProps = {
|
||||
value: string,
|
||||
options: string[],
|
||||
onChange: (value: string) => void
|
||||
}
|
||||
|
||||
const Autocomplete: FunctionComponent<AutocompleteProps> = ({value, options, onChange}) => {
|
||||
const matchingOptions = options.filter(o => o.toLowerCase().indexOf(value.toLowerCase()) >= 0)
|
||||
const [showSuggestion, setShowSuggestion] = useState<boolean>(false)
|
||||
|
||||
const [selectedIndex, setSelectedIndex] = useState<number|null>(null)
|
||||
|
||||
const onSelect = (value: string) => {
|
||||
setShowSuggestion(false)
|
||||
setSelectedIndex(null)
|
||||
onChange(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
value={value}
|
||||
onKeyDown={event => {
|
||||
if (event.key == "ArrowDown") {
|
||||
setSelectedIndex(Math.min(selectedIndex + 1, matchingOptions.length - 1))
|
||||
} else if (event.key == "ArrowUp") {
|
||||
setSelectedIndex(Math.max(0, selectedIndex - 1))
|
||||
}
|
||||
if (event.key == "Enter" && selectedIndex !== null) {
|
||||
onSelect(matchingOptions[selectedIndex])
|
||||
}
|
||||
}}
|
||||
onChange={event => {
|
||||
setShowSuggestion(true)
|
||||
setSelectedIndex(null)
|
||||
onChange(event.target.value)
|
||||
}}
|
||||
/>
|
||||
{ showSuggestion && matchingOptions.length > 0 && matchingOptions[0] != value &&
|
||||
<ul>
|
||||
{ matchingOptions.map((o, i) => (
|
||||
<li
|
||||
key={o}
|
||||
onClick={() => {
|
||||
onSelect(matchingOptions[i])
|
||||
}}
|
||||
>
|
||||
{i === selectedIndex && "#"} {o}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Autocomplete
|
|
@ -1,14 +1,16 @@
|
|||
import React, {FunctionComponent, useEffect, useState} from "react";
|
||||
import {MediaFile} from "../../database/file";
|
||||
import MediaPreview from "../MediaPreview";
|
||||
import Autocomplete from "../Autocomplete";
|
||||
|
||||
export type MediaDetailsProps = {
|
||||
basePath: string,
|
||||
file: MediaFile,
|
||||
onUpdate: (file: MediaFile) => void
|
||||
onUpdate: (file: MediaFile) => void,
|
||||
allTags: string[]
|
||||
}
|
||||
|
||||
const MediaDetails: FunctionComponent<MediaDetailsProps> = ({basePath, file, onUpdate}) => {
|
||||
const MediaDetails: FunctionComponent<MediaDetailsProps> = ({basePath, file, onUpdate, allTags}) => {
|
||||
const [currentFile, setCurrentFile] = useState<MediaFile>(file)
|
||||
const [hasChanges, setHasChanges] = useState<boolean>(false)
|
||||
|
||||
|
@ -49,9 +51,13 @@ const MediaDetails: FunctionComponent<MediaDetailsProps> = ({basePath, file, onU
|
|||
))
|
||||
}
|
||||
<li>
|
||||
<input type="text" value={newTagInput} onChange={(event) => {
|
||||
setNewTagInput(event.target.value)
|
||||
}} />
|
||||
<Autocomplete
|
||||
value={newTagInput}
|
||||
options={allTags}
|
||||
onChange={(value) => {
|
||||
setNewTagInput(value)
|
||||
}}
|
||||
/>
|
||||
<button onClick={() => {
|
||||
addTag(newTagInput)
|
||||
setNewTagInput("")
|
||||
|
|
|
@ -116,7 +116,7 @@ const Home: FunctionComponent<HomeProps> = () => {
|
|||
{ selected &&
|
||||
<>
|
||||
<button onClick={() => setSelected(null)}>Back</button>
|
||||
<MediaDetails basePath={basePath} file={selected} onUpdate={mediaUpdate} />
|
||||
<MediaDetails basePath={basePath} file={selected} onUpdate={mediaUpdate} allTags={allTags} />
|
||||
</>
|
||||
}
|
||||
{ !selected && showUntagged &&
|
||||
|
|
Loading…
Reference in a new issue